day 20 part 1

This commit is contained in:
Lucia Ceionia 2023-12-23 02:56:15 -06:00
parent 2598b444f8
commit 9f5df0a65c
6 changed files with 703 additions and 0 deletions

3
20/Makefile Normal file
View File

@ -0,0 +1,3 @@
all:
nasm -g -felf32 main.s && ld -melf_i386 -g main.o

58
20/input Normal file
View File

@ -0,0 +1,58 @@
%cd -> jx, gh
%bk -> jp, cn
%px -> xc, hg
%tv -> gh, xl
&xc -> bm, zq, jf, hg, bd, hn
%bd -> px
&bh -> mf
%dx -> cn, rb
%vv -> pp, gh
broadcaster -> cx, zq, tv, rh
%rb -> cn, qr
&jf -> mf
%jd -> mm
%cx -> xd, cn
%zs -> cz
%hn -> bm
%xr -> bd, xc
&mf -> rx
%zq -> kg, xc
&cn -> sh, jd, cx, tc, xd
%cs -> xj
%fb -> tc, cn
%mm -> cn, bk
%sq -> th, hz
%sz -> vx
%xl -> gh, sz
%vm -> gh, vv
%jp -> cn
%qr -> cn, jd
%bq -> xc, zv
&sh -> mf
%gz -> gs, hz
%qc -> qg, xc
%hg -> bq
%dt -> sq, hz
%xj -> fz
%qs -> gh
%fz -> hz, zs
%qg -> xc
%pp -> qs, gh
%zv -> xc, qc
%rh -> hz, mr
&gh -> tv, lk, sz, bh, vx
%th -> hz
&mz -> mf
%bm -> xr
%lk -> pg
%jx -> lk, gh
&hz -> xj, cs, zs, rh, mz
%tc -> dx
%mr -> hz, gz
%xd -> jk
%pg -> vm, gh
%kg -> hn, xc
%gs -> cs, hz
%vx -> cd
%cz -> hz, dt
%jk -> cn, fb

5
20/input_test Normal file
View File

@ -0,0 +1,5 @@
broadcaster -> aa, bb, cc
%aa -> bb
%bb -> cc
%cc -> iv
&iv -> aa

5
20/input_test2 Normal file
View File

@ -0,0 +1,5 @@
broadcaster -> aa
%aa -> iv, cn
&iv -> bb
%bb -> cn
&cn -> ou

296
20/main_part1.s Normal file
View File

@ -0,0 +1,296 @@
%include "utils.s"
global _start
[bits 32]
[section .text]
%define FILENAME "input"
;%define FILENAME "input_test"
;%define FILENAME "input_test2"
;%define DBG
;%define DBG_ITERS 1000
_start:
; read in modules
; module data (16 bytes):
; 0
; bit 1: type (0: flipflop, 1: conj) bit 0: state (0: low, 1: high)
; 1 2 3 4 5 6
; destination IDX list
; 7 8 9 A B C D E F
; input states (for conj modules)
; bit 0 is remembered state, higher is index
mov esi, file
read_modules:
lodsb
cmp al, '%'
je .flipflop
cmp al, '&'
je .conjunc
; broadcaster
%ifdef DBG
mov al, 'B'
call print_char
mov al, 'R'
call print_char
call space
%endif
mov ch, 1<<1
mov al, 1
%ifdef DBG
call print_hex_byte
call space
%endif
mov cl, -1 ; broadcaster is special
add esi, 14
mov edi, modules+16 ; module 1 is broadcast
jmp .get_dests
.flipflop:
mov cl, 0b00 ; low, flipflop
jmp .get_idx
.conjunc:
mov cl, 0b10 ; low, conj
jmp .get_idx
.get_idx:
; get ID
lodsb
%ifdef DBG
call print_char
%endif
mov bh, al
lodsb
%ifdef DBG
call print_char
call space
%endif
mov bl, al
call id_to_idx ; idx in edx
mov ch, dl
%ifdef DBG
mov al, dl
call print_hex_byte
call space
%endif
shl ch, 1
shl edx, 4 ; * 16
lea edi, [modules+edx]
add esi, 4
.get_dests:
; type/state in CL
mov [edi], cl
inc edi
.next_dest:
; get dest ID
lodsb
%ifdef DBG
call print_char
%endif
mov bh, al
lodsb
%ifdef DBG
call print_char
call space
%endif
mov bl, al
call id_to_idx
mov al, dl
%ifdef DBG
call print_hex_byte
call space
%endif
stosb
; store our idx<<1 in dest inputs
shl edx, 4 ; * 16
lea edx, [modules+edx+7]
.store_input:
cmp byte [edx], 0
jnz .check_next_input
mov byte [edx], ch
jmp .input_stored
.check_next_input:
inc edx
jmp .store_input
.input_stored:
; check if more
lodsb
cmp al, ','
jne .cont ; no more
inc esi ; space
jmp .next_dest
.cont:
%ifdef DBG
call newline
%endif
cmp esi, file.over
jb read_modules
main:
mov ecx, 1000
%ifdef DBG
mov ecx, DBG_ITERS
%endif
.loop:
push ecx
; start an iteration, broadcaster (1) sends low to everything
mov dword [queue_head], 0
mov dword [queue_tail], 2
mov word [queue], 0b10 ; low to index 1
call do_iters
pop ecx
loop .loop
jmp game_over
do_iters:
; get head of queue
mov eax, [queue_head]
mov ax, [eax+queue]
%ifdef DBG
call print_hex_word
call newline
%endif
mov cl, ah ; sender
movzx eax, al
shr eax, 1 ; get pulse
setc bl
jc .got_high
inc dword [low_count]
jmp .add_done
.got_high:
inc dword [high_count]
.add_done:
; get module
mov bh, al ; idx
shl eax, 4 ; * 16
lea edi, [modules+eax]
mov al, [edi]
cmp al, -1
je .broadcast
bt ax, 1
jc .conj
.flipflop:
; if high, do nothing
test bl, bl
jnz .cont
; if low, flip and send result
xor al, 1
bt ax, 0
setc bl
mov [edi], al
jmp add_cmds
.conj:
mov dl, 1
mov esi, 7
.check_mem:
mov al, [edi+esi]
test al, al
jz .mem_done
shr al, 1
setc dh
cmp al, cl
jne .mem_cont
shr bl, 1
setc dh
rcl al, 1
mov [edi+esi], al
.mem_cont:
and dl, dh
inc esi
cmp esi, 0xF
jbe .check_mem
.mem_done:
; send high if not all were high
xor dl, 1
mov bl, dl
jmp add_cmds
.broadcast:
jmp add_cmds ; just add commands with same pulse
.cont:
mov eax, [queue_head]
add eax, 2
and eax, 511
mov [queue_head], eax
cmp eax, [queue_tail]
jne do_iters
ret
; BH: module IDX, BL: pulse, EDI: *module
add_cmds:
mov dx, bx ; save
mov ecx, 1
.loop:
mov al, [edi+ecx]
test al, al
jz .done
mov bx, dx
shl al, 1
or bl, al
%ifdef DBG
call space
mov ax, bx
call print_hex_word
call newline
%endif
; add to queue
mov eax, [queue_tail]
mov [eax+queue], bx
add eax, 2
and eax, 511
mov [queue_tail], eax
inc ecx
cmp ecx, 6
jbe .loop
.done:
jmp do_iters.cont
game_over:
mov eax, [low_count]
call print_dec
call space
mov eax, [high_count]
call print_dec
call newline
p_string info
mul dword [low_count]
call print_dec
mov al, ':'
call print_char
mov eax, edx
call print_dec
call newline
jmp exit
; ID in BX, IDX return in EDX
id_to_idx:
xor edx, edx
.test:
cmp [module_idx_to_id+edx*2], bx
je .found
inc dx
cmp dx, [next_module_idx]
jb .test
; new ID
mov [module_idx_to_id+edx*2], bx
inc word [next_module_idx]
.found:
ret
[section .data]
low_count: dd 0
high_count: dd 0
next_module_idx: dw 2 ; 1 reserved for broadcaster
in_idx: dw 0
queue_head: dd queue
queue_tail: dd queue
file: incbin FILENAME
.over: db 0 ; EOF
[section .bss]
modules: resb 64*16
module_idx_to_id: resw 64
queue: resw 64*8
[section .rodata]
info: db `LOW:HIGH\n`
.over:

336
20/utils.s Normal file
View File

@ -0,0 +1,336 @@
[bits 32]
[section .text]
; call # val val2
; int $0x80 eax eax edx -
;
; arg1 arg2 arg3 arg4 arg5 arg6 arg7
; ebx ecx edx esi edi ebp -
exit:
mov eax, 1 ; exit
int 0x80
; filename in EBX
; return handle in EBX
; read only
open_file:
push eax
push ecx
mov eax, 5 ; open
xor ecx, ecx ; read only
int 0x80
mov ebx, eax
pop ecx
pop eax
ret
; file handle in EBX
; buffer in ECX
; count of bytes to read in EDX
; return bytes actually read in EAX
; exits on error
read_file:
mov eax, 3 ; read
int 0x80
test eax, eax
js .err
ret
.err:
mov eax, 4 ; write
mov ebx, 1 ; stdout
mov ecx, .err_str
mov edx, 21
int 0x80
jmp exit
.err_str: db `Could not read file.\n`
; string input in ESI
; value in EAX
; CF set if none, clear if some
; ESI set past checked area
dec_parse:
push ebx
push edx
push edi
xor eax, eax
xor edi, edi
mov ebx, 10 ; base
lodsb
sub al, '0'
js .no_input
cmp al, 9
jle .got_char
.no_input:
stc ; set CF
jmp .done
.loop:
xor eax,eax
lodsb
sub al, '0'
js .dec_done
cmp al, 9
jg .dec_done
.got_char:
xchg edi,eax
mul ebx
add edi,eax
jmp .loop
.dec_done:
clc ; clear CF
.done:
mov eax,edi
pop edi
pop edx
pop ebx
ret
; string input in ESI
; value in EAX
; CF set if none, clear if some
; ESI set past checked area
sign_dec_parse:
push ebx
push ecx
push edx
push edi
xor eax, eax
xor edi, edi
xor ecx, ecx ; neg flag
mov ebx, 10 ; base
cmp byte [esi], '-'
jne .no_minus
inc esi
mov cl, 1
.no_minus:
lodsb
sub al, '0'
js .no_input
cmp al, 9
jle .got_char
.no_input:
stc ; set CF
jmp .done
.loop:
xor eax,eax
lodsb
sub al, '0'
js .dec_done
cmp al, 9
jg .dec_done
.got_char:
xchg edi,eax
mul ebx
add edi,eax
jmp .loop
.dec_done:
test ecx, ecx
jz .not_neg
neg edi
.not_neg:
clc ; clear CF
.done:
mov eax,edi
pop edi
pop edx
pop ecx
pop ebx
ret
; modifies no regs
newline:
pushad
push 10
mov eax, 4 ; write
mov ebx, 1 ; stdout
mov ecx, esp ; string
mov edx, 1 ; length
int 0x80
add esp, 4
popad
ret
; modifies no regs
space:
pushad
push 9
mov eax, 4 ; write
mov ebx, 1 ; stdout
mov ecx, esp ; string
mov edx, 1 ; length
int 0x80
add esp, 4
popad
ret
; input in EAX, all regs unmodified
print_dec:
pushad ; save regs
; max 4294967296 is 10 chars
; round to nearest 32-bit boundary
sub esp, 12
; string in ECX, length in EDX
lea ecx, [esp+11] ; last possible byte
; check for 0
test eax, eax
jz .zero
mov ebx, 10 ; base 10
xor esi, esi ; counter
.div_shit:
xor edx, edx
; divide
div ebx
dec ecx ; next char
inc esi
; store
add dl, '0'
mov byte [ecx], dl
; check if done
test eax, eax
jnz .div_shit ; continue
mov edx, esi ; counter in edx
jmp .write
.zero:
mov byte [ecx], '0'
mov edx, 1 ; length
.write:
mov eax, 4 ; write
mov ebx, 1 ; stdout
int 0x80
add esp, 12 ; restore stack
popad ; restore regs
ret
; input in EAX, all regs unmodified
print_sign_dec:
pushad ; save regs
; range -2147483648 to 2147483647 is 11 chars
; round to nearest 32-bit boundary
sub esp, 12
; string in ECX, length in EDX
lea ecx, [esp+11] ; last possible byte
; check for 0, negative
xor ebp, ebp
test eax, eax
jz .zero
jns .positive
neg eax
mov ebp, 1
.positive:
mov ebx, 10 ; base 10
xor esi, esi ; counter
.div_shit:
xor edx, edx
; divide
div ebx
dec ecx ; next char
inc esi
; store
add dl, '0'
mov byte [ecx], dl
; check if done
test eax, eax
jnz .div_shit ; continue
mov edx, esi ; counter in edx
jmp .write
.zero:
mov byte [ecx], '0'
mov edx, 1 ; length
.write:
test ebp, ebp
jz .no_minus
dec ecx
inc edx
mov byte [ecx], '-'
.no_minus:
mov eax, 4 ; write
mov ebx, 1 ; stdout
int 0x80
add esp, 12 ; restore stack
popad ; restore regs
ret
; input in EAX, all regs unmodified
print_hex:
pushad
mov ebx, eax
shr eax, 16
call print_hex_word
mov eax, ebx
call print_hex_word
popad
ret
; input in AX, all regs unmodified
print_hex_word:
pushad
mov bx, ax
mov al, ah
call print_hex_byte
mov ax, bx
call print_hex_byte
popad
ret
; input in AL, all regs unmodified
print_hex_byte:
pushad
push '0000'
mov bl, al
shr bl, 4
mov dx, '0'
mov cx, 'A' - 10
cmp bl, 9
cmovg dx, cx
add bl, dl
mov [esp], bl
mov bl, al
and bl, 0xF
mov dx, '0'
mov cx, 'A' - 10
cmp bl, 9
cmovg dx, cx
add bl, dl
mov [esp+1], bl
mov eax, 4 ; write
mov ebx, 1 ; stdout
mov edx, 2 ; length
mov ecx, esp ; string
int 0x80
add esp, 4
popad
ret
; input in ESI, len in ECX, all regs unmodified
print_string:
pushad ; save regs
mov eax, 4 ; write
mov ebx, 1 ; stdout
mov edx, ecx ; length
mov ecx, esi ; string
int 0x80
popad ; restore regs
ret
; input in AL, all regs unmodified
print_char:
pushad ; save regs
push eax
mov eax, 4 ; write
mov ebx, 1 ; stdout
mov edx, 1 ; length
mov ecx, esp ; string
int 0x80
add esp, 4
popad ; restore regs
ret
; --- MACROS ---
%define len(x) x %+ .over - x
%macro p_string 1
push esi
push ecx
mov esi, %1
mov ecx, len(%1)
call print_string
pop ecx
pop esi
%endmacro