diff --git a/20/Makefile b/20/Makefile new file mode 100644 index 0000000..573eb71 --- /dev/null +++ b/20/Makefile @@ -0,0 +1,3 @@ +all: + nasm -g -felf32 main.s && ld -melf_i386 -g main.o + diff --git a/20/input b/20/input new file mode 100644 index 0000000..cdb0c1e --- /dev/null +++ b/20/input @@ -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 diff --git a/20/input_test b/20/input_test new file mode 100644 index 0000000..ceebe1b --- /dev/null +++ b/20/input_test @@ -0,0 +1,5 @@ +broadcaster -> aa, bb, cc +%aa -> bb +%bb -> cc +%cc -> iv +&iv -> aa diff --git a/20/input_test2 b/20/input_test2 new file mode 100644 index 0000000..1faea23 --- /dev/null +++ b/20/input_test2 @@ -0,0 +1,5 @@ +broadcaster -> aa +%aa -> iv, cn +&iv -> bb +%bb -> cn +&cn -> ou diff --git a/20/main_part1.s b/20/main_part1.s new file mode 100644 index 0000000..402bee8 --- /dev/null +++ b/20/main_part1.s @@ -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: diff --git a/20/utils.s b/20/utils.s new file mode 100644 index 0000000..e96c63d --- /dev/null +++ b/20/utils.s @@ -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