From b000857bb4aad2ed0e2639c35136ebc9f3d92cbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juhani=20Krekel=C3=A4?= Date: Thu, 24 Feb 2022 21:14:37 +0200 Subject: [PATCH] Implement the RNG for word selection --- dosdl.asm | 281 +++++++++++++++++++++++++++++++++++++++++++++- word_selection.py | 28 +++++ 2 files changed, 305 insertions(+), 4 deletions(-) create mode 100644 word_selection.py diff --git a/dosdl.asm b/dosdl.asm index af58eb4..41a9b6d 100644 --- a/dosdl.asm +++ b/dosdl.asm @@ -5,11 +5,36 @@ org 0x100 section .code -select_target: - ; TODO: Implement target word selection - ; https://github.com/lynn/hello-wordl/blob/7da40c1f067eb1ec157d4c5b7a9bd8257ed39342/src/util.ts#L14 - mov si, 1397 +seed equ 20220224 +; Seed the rng +mov ax, seed & 0xffff +mov dx, seed >> 16 +mov bp, rng_seed +call store32 + +select_target: + ; Call rng to get a number + call rng + mov bp, rng_output + call store32 + + ; Multiply rng output by number of targer words + xor si, si + xor dx, dx + xor ax, ax + mov cx, targets_len + .multiply_loop: + add ax, [rng_output + 0] + adc dx, [rng_output + 2] + adc si, 0 + loop .multiply_loop + + mov ax, si + call hexprint16 + call newline + +load_target: shl si, 1 shl si, 1 add si, targets @@ -18,6 +43,11 @@ select_target: call unpack_target + ; Figure out whether this is a removed word + ; If so, reroll target word + cmp byte [target], '{' + je select_target + read_guess: ; Number of thus far guessed letters stored in bx xor bx, bx @@ -428,6 +458,237 @@ unpack_target: ret +; out: +; dx:ax = result +rng: + ; https://github.com/lynn/hello-wordl/blob/7da40c1f067eb1ec157d4c5b7a9bd8257ed39342/src/util.ts#L14 + + ; rng_t = rng_seed += rng_seed + 0x6d2b79f5 + mov bp, rng_seed + call load32 + add ax, 0x79f5 + adc dx, 0x6d2b + call store32 + mov bp, rng_t + call store32 + + ; xorl32 = rng_t + mov bp, xorl32 + call store32 + + ; xorr32 = rng_t >> 15 + mov cx, 15 + call rshift32 + mov bp, xorr32 + call store32 + + ; mull32 = xorl32 ^ xorr32 = rng_t ^ (rng_t >> 15) + call xor32 + mov bp, mull32 + call store32 + + ; mulr32 = rng_t | 1 + mov bp, rng_t + call load32 + or ax, 1 + mov bp, mulr32 + call store32 + + ; rng_t = mull32 * mulr32 = (rng_t ^ (rng_t >> 15)) * (rng_t | 1) + call mul32 + mov bp, rng_t + call store32 + + ; xorl32 = rng_t + mov bp, xorl32 + call store32 + + ; xorr32 = rng_t >> 7 + mov cx, 7 + call rshift32 + mov bp, xorr32 + call store32 + + ; mull32 = xorl32 ^ xorr32 = rng_t ^ (rng_t >> 7) + call xor32 + mov bp, mull32 + call store32 + + ; mulr32 = rng_t | 61 + mov bp, rng_t + call load32 + or ax, 61 + mov bp, mulr32 + call store32 + + ; addl32 = rng_t + mov bp, rng_t + call load32 + mov bp, addl32 + call store32 + + ; addr32 = mull32 * mulr32 = (rng_t ^ (rng_t >> 7)) * (rng_t | 61) + call mul32 + mov bp, addr32 + call store32 + + ; xorl32 = rng_t + mov bp, rng_t + call load32 + mov bp, xorl32 + call store32 + + ; xorr32 = addl32 + addr32 = rng_t + (rng_t ^ (rng_t >> 7)) * (rng_t | 61) + call add32 + mov bp, xorr32 + call store32 + + ; rng_t = xorl32 ^ xorr32 = rng_t ^ (rng_t + (rng_t ^ (rng_t >> 7)) * (rng_t | 61)) + call xor32 + mov bp, rng_t + call store32 + + ; xorl32 = rng_t + mov bp, xorl32 + call store32 + + ; xorr32 = rng_t >> 14 + mov cx, 14 + call rshift32 + mov bp, xorr32 + call store32 + + ; result = xorl32 ^ xorr32 = rng_t ^ (rng_t >> 14) + call xor32 + + ret + +; in: +; bp = address of uint32 +; out: +; dx = high 16 bits +; ax = low 16 bits +load32: + mov ax, [bp + 0] + mov dx, [bp + 2] + ret + +; in: +; bp = address of uint32 +; dx = high 16 bits +; ax = low 16 bits +store32: + mov [bp + 0], ax + mov [bp + 2], dx + ret + +; in: +; dx:ax = uint32 to be shifted +; cx = shift amount (must not be 0) +; out: +; dx:ax = result +rshift32: + push cx + .loop: + shr dx, 1 + rcr ax, 1 + loop .loop + pop cx + ret + +; in: +; [xorl32], [xorr32] = operands +; out: +; dx:ax = result +xor32: + mov ax, [xorl32 + 0] + xor ax, [xorr32 + 0] + mov dx, [xorl32 + 2] + xor dx, [xorr32 + 2] + ret + +; in: +; [mull32], [mulr32] = operands +; out: +; dx:ax = result +mul32: + push bx + push cx + ; c = 1<<16 + ; l = l₁<<16 + l₀ + ; r = r₁<<16 + r₀ + ; l·r = (l₁<<16 + l₀)·(r₁<<16 + r₀) + ; = l₁<<16·r₁<<16 + l₁<<16·r₀ + l₀·r₁<<16 + l₀·r₀ + ; = l₁·r₁<<32 + l₁·r₀<<16 + l₀·r₁<<16 + l₀·r₀ ||1<<32 = 0 (mod 1<<32) + ; = l₁·r₀<<16 + l₀·r₁<<16 + l₀·r₀ + + ; l₀·r₀ + mov ax, [mull32 + 0] + mul word [mulr32 + 0] + mov bx, ax + mov cx, dx + + ; l₀·r₁<<16 + mov ax, [mull32 + 0] + mul word [mulr32 + 2] + add cx, ax + + ; l₁·r₀<<16 + mov ax, [mull32 + 2] + mul word [mulr32 + 0] + add cx, ax + + mov dx, cx + mov ax, bx + + pop cx + pop bx + + ret + +; in: +; [addl32], [addr32] = operands +; out: +; dx:ax = result +add32: + mov ax, [addl32 + 0] + mov dx, [addl32 + 2] + add ax, [addr32 + 0] + adc dx, [addr32 + 2] + ret + +hexprint32: + xchg ax, dx + call hexprint16 + xchg ax, dx +hexprint16: + xchg ah, al + call hexprint8 + xchg ah, al +hexprint8: +%rep 4 + rol al, 1 +%endrep + call hexprint4 +%rep 4 + rol al, 1 +%endrep +hexprint4: + push ax + and al, 0xf + cmp al, 10 + jb .digit09 + + add al, 'a' - 10 - '0' + + .digit09: + add al, '0' + mov ah, 0xe + int 0x10 + + pop ax + ret + section .data target times 5 db 0 guess times 5 db 0 @@ -439,6 +700,18 @@ guesses db 0 dictionary_entry times 5 db 0 +rng_seed dd 0 +rng_t dd 0 + +rng_output dd 0 + +xorl32 dd 0 +xorr32 dd 0 +mull32 dd 0 +mulr32 dd 0 +addl32 dd 0 +addr32 dd 0 + section .rodata not_found_str db ' - word not found$' diff --git a/word_selection.py b/word_selection.py new file mode 100644 index 0000000..9f0affe --- /dev/null +++ b/word_selection.py @@ -0,0 +1,28 @@ +import json +import sys + +# https://github.com/lynn/hello-wordl/blob/7da40c1f067eb1ec157d4c5b7a9bd8257ed39342/src/util.ts#L14 +def rshift(n, a): return (n & 0xffff_ffff) >> a + +def mulberry32(rng_state): + def worker(): + nonlocal rng_state + rng_state += 0x6d2b79f5; + t = rng_state + t = (t ^ rshift(t, 15)) * (t | 1) & 0xffff_ffff + t ^= t + (t ^ rshift(t, 7)) * (t | 61) & 0xffff_ffff + return (t ^ (t >> 14)) + return worker + +with open('targets.json', 'r') as f: + targets = json.load(f) + +targets = targets[:targets.index('murky') + 1] +targets = [i for i in targets if len(i) == 5] + +rng = mulberry32(int(sys.argv[1])) +while True: + num = rng() + index = num * len(targets) >> 32 + print(f'{num:08x}', index, targets[index]) + if targets[index] != '*****': break