; A tiny (76 bytes), non-optimizing Brainfuck bytecode based interpreter for Z80Golf ; The bytecode is a sequence of 1 byte instructions which either execute directly or trap+emulate. ; z80asm brainfuck-z80g.asm -o brainfuck-z80g.z8g AT: MACRO ADDR IF $ != ADDR not ADDR ENDIF ENDM PUTC: EQU 0x8000 ; Z80Golf putc syscall GETC: EQU 0x8003 ; Z80Golf getc syscall RETOPC: EQU 0xC9 ; Opcode for RET, used in the scan loop EOF: EQU '!' ; Standard EOF extension for Brainfuck ORG 0x0000 _start: ld e, (hl) ; 00 Start assembling at DE = 0x005E (read the opcode itself lol) push de ; 01 Push return address to start of code parse: ; == Parse loop == ld a, EOF ; 02 Default to EOF ('!') call GETC ; 04 Read byte from stdin ld c, 9 ; 07 Length of table ld l, table ; 09 Address of table cpir ; 0B Scan the lookup table (WHILE BC && *HL != A; HL++; BC--) jr nz, parse ; 0D Not found, next byte translate: ; == Found a match, translate from BF to bytecode == add hl, bc ; 0F Add BC (remainder from CPIR) to HL. HL == bytecode add hl, bc ; 10 Add again, this time pointing to the table entry ldi ; 11 Copy compiled code to (DE), decrement BC. On EOF, BC == -1 inc c ; 13 Increment C to test if BC == -1 jr nz, parse ; 14 Not EOF, continue parsing exec: ; == Finalize and jump to the code == ex de, hl ; 16 Swap DE (code pointer) to HL, setting HL to the tape ret ; 17 Jump to start of code (0x005E) we pushed earlier AT 0x18 rst_print: ; == RST 0x18: Syscall for print (.) == ld a, (hl) ; 18 Load byte from tape jp PUTC ; 19 Tail call PUTC loop_cont: ; == Push return for ']' to stack and continue. DE = ptr to '[' == push de ; 1C Push return address for ']' to RET to inc de ; 1D Increment to get past the '[' push de ; 1E Push DE ret ; 1F and jump to it AT 0x20 rst_read: ; == RST 0x20: Syscall for read (,) == xor a ; 20 Default to 0 call GETC ; 21 Read byte from stdin ld (hl), a ; 24 Store to tape ret ; 25 Return table: ; == Lookup table for Brainfuck opcodes == DB "+-<>.,[]", EOF ; 26-2E BF opcodes bytecode: ; == Reversed compiled bytecode == term: halt ; 2F EOF end: ret ; 30 ] (RET to the start of the loop pushed by ']') begin: rst rst_begin ; 31 [ (Scan to skip loop or push return address for ']') read: rst rst_read ; 32 , (Wrap GETC) print: rst rst_print ; 33 . (Wrap PUTC) right: inc hl ; 34 > left: dec hl ; 35 < minus: dec (hl) ; 36 - plus: inc (hl) ; 37 + AT 0x38 rst_begin: ; == RST 0x38: Syscall for begin ([) == pop de ; 38 Pop return address (points past the '['' dec de ; 39 Decrement to point to the '[' ld b, (hl) ; 3A Load tape value into B inc b ; 3B INC B/DJNZ: test for B == 0 djnz loop_cont ; 3C If nonzero, loop is true, continue execution. scan_loop: ; == Scan bytecode to match []. B is conveniently 0. == ld a, (de) ; 3E Load compiled opcode inc de ; 3F Advance DE cp RETOPC ; 40 Test for ']' which is encoded as RET jr z, scan_djnz ; 42 If ']', jump to the DJNZ for a net of -1 incr_again: ; inc b ; 44 Increment B inc a ; 45 Increment A to test for '[' (RST 0x38 == 0xFF). jr z, incr_again ; 46 If '[', repeat the increment for a net of +1, scan_djnz: ; otherwise cancel out the inc b with djnz djnz scan_loop ; 48 Decrement loop depth and loop if nonzero push de ; 4A Push DE ret ; 4B and jump to it
; A tiny (76 bytes), non-optimizing Brainfuck bytecode based interpreter for Z80Golf ; The bytecode is a sequence of 1 byte instructions which either execute directly or trap+emulate. ; z80asm brainfuck-z80g.asm -o brainfuck-z80g.z8g AT: MACRO ADDR IF $ != ADDR not ADDR ENDIF ENDM PUTC: EQU 0x8000 ; Z80Golf putc syscall GETC: EQU 0x8003 ; Z80Golf getc syscall RETOPC: EQU 0xC9 ; Opcode for RET, used in the scan loop EOF: EQU '!' ; Standard EOF extension for Brainfuck ORG 0x0000 _start: ld e, (hl) ; 00 Start assembling at DE = 0x005E (read the opcode itself lol) push de ; 01 Push return address to start of code parse: ; == Parse loop == ld a, EOF ; 02 Default to EOF ('!') call GETC ; 04 Read byte from stdin ld c, 9 ; 07 Length of table ld l, table ; 09 Address of table cpir ; 0B Scan the lookup table (WHILE BC && *HL != A; HL++; BC--) jr nz, parse ; 0D Not found, next byte translate: ; == Found a match, translate from BF to bytecode == add hl, bc ; 0F Add BC (remainder from CPIR) to HL. HL == bytecode add hl, bc ; 10 Add again, this time pointing to the table entry ldi ; 11 Copy compiled code to (DE), decrement BC. On EOF, BC == -1 inc c ; 13 Increment C to test if BC == -1 jr nz, parse ; 14 Not EOF, continue parsing exec: ; == Finalize and jump to the code == ex de, hl ; 16 Swap DE (code pointer) to HL, setting HL to the tape ret ; 17 Jump to start of code (0x005E) we pushed earlier AT 0x18 rst_print: ; == RST 0x18: Syscall for print (.) == ld a, (hl) ; 18 Load byte from tape jp PUTC ; 19 Tail call PUTC loop_cont: ; == Push return for ']' to stack and continue. DE = ptr to '[' == push de ; 1C Push return address for ']' to RET to inc de ; 1D Increment to get past the '[' push de ; 1E Push DE ret ; 1F and jump to it AT 0x20 rst_read: ; == RST 0x20: Syscall for read (,) == xor a ; 20 Default to 0 call GETC ; 21 Read byte from stdin ld (hl), a ; 24 Store to tape ret ; 25 Return table: ; == Lookup table for Brainfuck opcodes == DB "+-<>.,[]", EOF ; 26-2E BF opcodes bytecode: ; == Reversed compiled bytecode == term: halt ; 2F EOF end: ret ; 30 ] (RET to the start of the loop pushed by ']') begin: rst rst_begin ; 31 [ (Scan to skip loop or push return address for ']') read: rst rst_read ; 32 , (Wrap GETC) print: rst rst_print ; 33 . (Wrap PUTC) right: inc hl ; 34 > left: dec hl ; 35 < minus: dec (hl) ; 36 - plus: inc (hl) ; 37 + AT 0x38 rst_begin: ; == RST 0x38: Syscall for begin ([) == pop de ; 38 Pop return address (points past the '[') dec de ; 39 Decrement to point to the '[' ld b, (hl) ; 3A Load tape value into B inc b ; 3B INC B/DJNZ: test for B == 0 djnz loop_cont ; 3C If nonzero, loop is true, continue execution. scan_loop: ; == Scan bytecode to match []. B is conveniently 0. == ld a, (de) ; 3E Load compiled opcode inc de ; 3F Advance DE cp RETOPC ; 40 Test for ']' which is encoded as RET jr z, scan_djnz ; 42 If ']', jump to the DJNZ for a net of -1 incr_again: ; inc b ; 44 Increment B inc a ; 45 Increment A to test for '[' (RST 0x38 == 0xFF). jr z, incr_again ; 46 If '[', repeat the increment for a net of +1, scan_djnz: ; otherwise cancel out the inc b with djnz djnz scan_loop ; 48 Decrement loop depth and loop if nonzero push de ; 4A Push DE ret ; 4B and jump to it