Skip to main content
Typo fix, syntax highlighting that allows hex numbers
Source Link
EasyasPi
  • 5.4k
  • 20
  • 23
; 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 
; 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 
Update comments
Source Link
EasyasPi
  • 5.4k
  • 20
  • 23
; 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 Found, addAdd 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 (EOF) jr nz, parse ; 14 IfNot notEOF, continue parsing exec: ; Time== Finalize and jump to execthe code == ex de, hl ; 16 Swap DE and(code pointer) to HL, setting HL to the start of the tape ret ; 17 ReturnJump 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: ; From== below,Push whenreturn thefor loop']' conditionto isstack trueand 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 [ (trapScan to RSTskip 0x38loop or push return address for ']') read: rst rst_read ; 32 , (trap to RSTWrap 0x20GETC) print: rst rst_print ; 33 . (trap to RSTWrap 0x18PUTC) 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: ; Otherwise,== scanScan 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: 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 add hl, bc ; 0F Found, 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 inc c ; 13 Increment C to test if BC == -1 (EOF) jr nz, parse ; 14 If not, continue parsing exec: ; Time to exec ex de, hl ; 16 Swap DE and HL, setting HL to the start of the tape ret ; 17 Return to 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: ; From below, when the loop condition is true. 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 [ (trap to RST 0x38) read: rst rst_read ; 32 , (trap to RST 0x20) print: rst rst_print ; 33 . (trap to RST 0x18) 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: ; Otherwise, scan 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 
Explain overview better
Source Link
EasyasPi
  • 5.4k
  • 20
  • 23
; 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. ; ; Specs: ; - Wrapping 8-bit cells ; - Maximum stripped program size of 32674 bytes ; - Maximum tape size of (64925 - stripped program size) bytes, non wrapping ; - Maximum loop depth of 255 ; - Program is '!' or EOF terminated ; - Technically supports self modifying, but the instructions are translated to bytecode ; - Read instruction sets cell to 0 on EOF ; ; The code is carefully ordered to align to RST addresses. ; 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: 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 add hl, bc ; 0F Found, 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 inc c ; 13 Increment C to test if BC == -1 (EOF) jr nz, parse ; 14 If not, continue parsing exec: ; Time to exec ex de, hl ; 16 Swap DE and HL, setting HL to the start of the tape ret ; 17 Return to 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: ; From below, when the loop condition is true. 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 [ (trap to RST 0x38) read: rst rst_read ; 32 , (trap to RST 0x20) print: rst rst_print ; 33 . (trap to RST 0x18) 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: ; Otherwise, scan 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 

This takes advantage of the fact that RST, INC, DEC, RET, and HALT are all 1 byte instructionswith only 3 rst routines, so we can usedo a 1:1 lookup tablemapping of Brainfuck to 1-byte opcodes, and eitherjust execute the bytecode directly removing the need for an interpreter loop or RSTmanual PC tracking (we just pop the return address of rst)

  • +: inc (hl)
  • -: dec (hl)
  • >: inc hl
  • <: dec hl
  • .: rst 0x18
    • wraps PUTC (0x8000)
  • ,: rst 0x20
    • wraps GETC (0x8003)
  • [: rst 0x38
    • If zero, scan forward to skip, else push address of [ to the call stack and continue.
  • ]: ret
    • Return unconditionally to the pushed address of [ to test again
  • ! (EOF): halt

Specs:

  • Wrapping 8-bit cells
  • Maximum stripped program size of (if my calculations are correct) 32673 bytes
  • Maximum tape size of (64924 - stripped program size) bytes, non wrapping
  • Maximum loop depth of 255
  • Program is read from stdin as prog!input or EOF terminated
  • Cells are set to 0 on EOF

The code is carefully written to emulateline up with the RST addresses perfectly without NOPs, opcode overlaps, excess jumps or other weirdness, another thing I find elegant.

; 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. ; ; Specs: ; - Wrapping 8-bit cells ; - Maximum stripped program size of 32674 bytes ; - Maximum tape size of (64925 - stripped program size) bytes, non wrapping ; - Maximum loop depth of 255 ; - Program is '!' or EOF terminated ; - Technically supports self modifying, but the instructions are translated to bytecode ; - Read instruction sets cell to 0 on EOF ; ; The code is carefully ordered to align to RST addresses. ; 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: 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 add hl, bc ; 0F Found, 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 inc c ; 13 Increment C to test if BC == -1 (EOF) jr nz, parse ; 14 If not, continue parsing exec: ; Time to exec ex de, hl ; 16 Swap DE and HL, setting HL to the start of the tape ret ; 17 Return to 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: ; From below, when the loop condition is true. 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 [ (trap to RST 0x38) read: rst rst_read ; 32 , (trap to RST 0x20) print: rst rst_print ; 33 . (trap to RST 0x18) 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: ; Otherwise, scan 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 

This takes advantage of the fact that RST, INC, DEC, RET, and HALT are all 1 byte instructions, so we can use a 1:1 lookup table and either execute the bytecode directly or RST to emulate.

; 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: 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 add hl, bc ; 0F Found, 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 inc c ; 13 Increment C to test if BC == -1 (EOF) jr nz, parse ; 14 If not, continue parsing exec: ; Time to exec ex de, hl ; 16 Swap DE and HL, setting HL to the start of the tape ret ; 17 Return to 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: ; From below, when the loop condition is true. 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 [ (trap to RST 0x38) read: rst rst_read ; 32 , (trap to RST 0x20) print: rst rst_print ; 33 . (trap to RST 0x18) 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: ; Otherwise, scan 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 

This takes advantage of the fact that with only 3 rst routines, we can do a 1:1 mapping of Brainfuck to 1-byte opcodes, and just execute directly removing the need for an interpreter loop or manual PC tracking (we just pop the return address of rst)

  • +: inc (hl)
  • -: dec (hl)
  • >: inc hl
  • <: dec hl
  • .: rst 0x18
    • wraps PUTC (0x8000)
  • ,: rst 0x20
    • wraps GETC (0x8003)
  • [: rst 0x38
    • If zero, scan forward to skip, else push address of [ to the call stack and continue.
  • ]: ret
    • Return unconditionally to the pushed address of [ to test again
  • ! (EOF): halt

Specs:

  • Wrapping 8-bit cells
  • Maximum stripped program size of (if my calculations are correct) 32673 bytes
  • Maximum tape size of (64924 - stripped program size) bytes, non wrapping
  • Maximum loop depth of 255
  • Program is read from stdin as prog!input or EOF terminated
  • Cells are set to 0 on EOF

The code is carefully written to line up with the RST addresses perfectly without NOPs, opcode overlaps, excess jumps or other weirdness, another thing I find elegant.

No byte count change but have 162 more bytes of tape/prog space for free
Source Link
EasyasPi
  • 5.4k
  • 20
  • 23
Loading
Minor typo in comment
Source Link
EasyasPi
  • 5.4k
  • 20
  • 23
Loading
Source Link
EasyasPi
  • 5.4k
  • 20
  • 23
Loading