Michael
2008-12-19 07:54:17 UTC
Let me know if you find corrections, or optimizations :)
The only known bug (or lack of feature) is EOF isn't handled. I
didn't feel like "bloating" the code with a few more bytes :-)
Enjoy!
; Title: BrainFuck Interpreter
; File: BF6502A2.Ver2.s
; CPU: 6502
; Platform: Apple ][ //e
; By: Michael Pohoreski
; Date: Dec, 2008
; Description: 135 Byte Interpreter of BrainFuck (Version 2)
; License: BSD "Sharing is Caring!"
;
; Reference: http://en.wikipedia.org/wiki/Brainfuck
; > ++pData;
; < --pData;
; + ++(*pData);
; - --(*pData);
; . putchar(*pData);
; , *pData=getchar();
; [ while (*pData) {
; ] }
;
; Note: Select, Copy, then Shift-INS to paste into AppleWin, or
manually enter...
CALL-151
300:20 E2 F3 A9 06 85 3C A9 08 85 3D
30B:A0 00 84 40 A9 20 85 41
313:20 1D 03 20 C2 FC A0 00 F0 F6 // interpret
31D:B1 3C D0 02 68 68 // fetch
323:A2 07 DD 77 03 F0 04 CA 10 F8 60 // find op
32E:A9 03 48 BD 7F 03 48 18 B1 40 60 // exec
339:4C 11 FE // bf_next
33C:A5 40 D0 02 C6 41 C6 40 60 // bf_prev
345:69 02 18 // bf_inc
348:E9 00 A0 00 91 40 60 // bf_dec
34F:20 0C FD 29 7F 10 F4 // bf_in
356:09 80 4C ED FD // bf_out
35B:D0 19 20 C2 FC B1 3C C9 5D D0 F7 // bf_if
366:F0 0E A5 3C D0 02 C6 3D C6 3C B1 3C C9 5B D0 F2 60 // bf_end
377:2C 2E 5B 3C 5D 3E 2D 2B
37F:4E 55 5A 3B 65 38 47 44
FA62G
0 "++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<
+++++++++++++++.>.+++.------.--------.>+.>."
REM Hello World!
CALL 768
REM http://esolangs.org/wiki/Talk:Brainfuck
0 "++++++++[->-[->-[->-[-]<]<]<]"
REM -n/a-
CALL 768
0 ">++++++++[<++++++++++>-]<[>+>+<<-]>-.>-----.>"
REM OK
CALL 768
0 "+++++++++++++[>+++++++++>++++++++>++++++++>+++++<<<<-]>-.>.---.>++++
+.<----.<.>>+++++.<++++++++.>++++++.<----.----.<.-.>>+.----------.<<+
+.>>>-.<<<++++.>.+++++++.>..>------------------.<<-----.>.>.<-.<<+."
REM ***@yahoo.co.nz
CALL 768
0 "++++++++[->-[->-[->-[-]<]<]<]>++++++++[<++++++++++>-]<[>+>+<<-]
>-.>-----.>"
; Source
;pCode EQU $3C ; can't use $00C0, used by AppleSoft!
;pData EQU $FE ; shouldn't use $00DA, used by AppleSoft: LINENUMONERR
BFPC EQU $3C ; BFPC/pCode same as A1L/H
DATA EQU $40 ; DATA/pData same as A3L/H
HGR EQU $F3E2
HGR EQU $F3D8
COUT EQU $FDED
RDKEY EQU $FD0C
NXTA1_8 EQU $FCC2 ; standard entry point is NXTA1 = $FCBA
STOR_6 EQU $FE11 ; standard entry point is STOR = $FE0B
.ORG $300
; JSR HGR2 ; 20 D8 F3 ; If want 16K of data space... uncomment
JSR HGR ; 20 E2 F3 ; Clear 8K of data space
LDA #$06 ; A9 06 ; $0806 first Applesoft token
STA BFPC ; 85 3C
LDA #$08 ; A9 08 ; $0806 first Applesoft token
STA BFPC+1 ; 85 3D
LDY #$00 ; A0 00 ; use HGR page 1 for data ...
STY DATA ; 84 40
; UNDO optimization: HGR sets current HiRes page pointer, E6 = $20
LDA #$20 ; A9 20
STA DATA+1 ; 85 41
INTERPRET
JSR FETCH ; 20 1D 03
JSR NXTA1+8 ; 20 C2 FC
LDY #$00 ; A0 00 ; because COUT trashes Y
BEQ INTERPRET ; F0 F6 ; branch always
FETCH
LDA (BFPC),Y ; B1 3C
BNE FIND_OP ; D0 02
EXIT
PLA ; 68
PLA ; 68
; optimization: intentional-fall through : RTS after not finding
opcode
FIND_OP
LDX #$07 ; A2 07 ; 8 Instructions
.1
CMP OPCHAR,X ; DD 77 03 ; table of opcodes (char)
BEQ EXEC ; F0 04
DEX ; CA
BPL .1 ; 10 F8
; Note: (alternative) optimization: intentional fall-through: bad-
opcode so skip next instruction
; and fall into into INC_PC, but this is no longer stands compliant
-- as it
; skips two opcodes instead of one on a invalid opcode
RTS ; 60
EXEC
LDA #$03 ; A9 03 ; high byte of this code address
PHA ; 48
LDA OPFUNCPTR,X ; BD 7F 03 ; function pointer table (address)
PHA ; 48
CLC ; 18 ; optimization: common code
LDA (DATA),Y ; B1 40 ; optimization: common code
RTS ; 60 ; relative jsr
BF_NEXT
; optimization: use monitor rom STOR: BF_NEXT -> STOR+6 = $FE11
; INC DATA ; E6 E5
; BNE .1 ; D0 02
; INC DATA+1 ; E6 E6
;.1
; RTS ; 60
;FE11
; INC A3L ; E6 40
; BNE RTS5 ; D0
; INC A3H ; E6 41
;RTS5 RTS ; 60
JMP STOR+6 ; 4C 11 FE
BF_PREV
LDA DATA ; A5 40
BNE .1 ; D0 02
DEC DATA+1 ; C6 41
.1
DEC DATA ; C6 40
RTS ; 60
BF_INC
ADC #$02 ; 69 02 ; optimization: n+2-1 = n+1
CLC ; 18 ; optimization: fall-through into BF_INCDEC
BF_DEC
SBC #$00 ; E9 00
BF_INCDEC
LDY #$00 ; A0 00
STA (DATA),Y ; 91 40
RTS ; 60
BF_IN
JSR RDKEY ; 20 0C FD ; trashes Y
AND #$7F ; 29 7F ; convert 8-bit Apple Text to 7-bit ASCII
BPL BF_INCDEC ; 10 F4 ; optmization: BPL BF_INCDEC (10 F4)
BF_OUT
ORA #$80 ; 09 80 ; output Hi-Bit Apple Text !
JMP COUT ; 4C ED FD ; trashes A, Y
BF_IF ; if( !*pData ) pc = ']'
BNE .3 ; D0 19 ; optimization: BEQ .1, therefore BNE RTS
; RTS
; optimization: JSR INC_PC -> JSR NXTA1+8 = $FCC2
;INC_PC -> NXTA1+8 = $FCC2
; INC BFPC ; E6 3C
; BNE .1 ; D0 02
; INC BFPC+1 ; E6 3D
;.1
; RTS ; 60
.1
JSR NXTA1+8 ; 20 C2 FC
LDA (BFPC), Y ; B1 3C
CMP ']' ; C9 5D
BNE .1 ; D0 F7
.2
; optimization: intentional-fall through: remove RTS -- we got here
if BEQ, so exit...
BF_END ; if( !*pData ) pc = '['
BEQ .3 ; F0 0E ; optimization: BNE .1, therefore BEQ RTS
.1
LDA BFPC ; A5 3C
BNE .2 ; D0 02
DEC BFPC+1 ; C6 3D
.2
DEC BFPC ; C6 3C
LDA (BFPC),Y ; B1 3C
CMP '[' ; C9 5B
BNE .1 ; D0 F2
.3
RTS ; 60
OPCHAR DA ",.[<]>-+" ; sorted: 2B 2C 2D 2E 3C 3E 5B 5D
OPFUNCPTR ; sorted by usage: least commonly called to most frequently
called
DFB BF_IN -1 ; , 2C
DFB BF_OUT -1 ; . 2E
DFB BF_IF -1 ; [ 5B
DFB BF_PREV-1 ; < 3C
DFB BF_END -1 ; ] 5D
DFB BF_NEXT-1 ; > 3E
DFB BF_DEC -1 ; - 2D
DFB BF_INC -1 ; + 2B
// AppleWin symbols...
SYM BRAINFUCK = 300
SYM LASTVARS = 303
SYM INTERPRET = 313
SYM FETCH = 31D
SYM EXIT = 320
SYM FIND_OP = 323
SYM EXEC = 32E
SYM BF_NEXT = 339 // > 3E
SYM BF_NEXT_1 = 33B
SYM BF_PREV = 33C // < 3C
SYM BF_PREV_1 = 342
SYM BF_INC = 345 // + 2B
SYM BF_DEC = 348 // - 2D
SYM BF_INCDEC = 34A
SYM BF_IN = 34F // , 2C
SYM BF_OUT = 356 // . 2E
SYM BF_IF = 35B // [ 5B
SYM BF_IF_1 = 35D
SYM BF_IF_2 = 35E
SYM BF_END = 366 // ] 5D
SYM BF_END_1 = 368
SYM BF_END_2 = 36E
SYM BF_END_3 = 376
SYM NXTA1_8 = FCC2
SYM STOR_6 = FE11
SYM OPCHAR = 377
SYM OPFUNCPTR = 37F
Notes:
Apple Specific Optimizations:
- use F800 rom code :-)
1) INC_PC -> NXTA1+8 = $FCC2
INC BFPC ; E6 3C
BNE .1 ; D0 02
INC BFPC+1 ; E6 3D
.1
RTS ; 60
FE11
INC A3L ; E6 40
BNE RTS5 ; D0
INC A3H ; E6 41
RTS5 RTS ; 60
2) BF_NEXT -> STOR+6 = $FE11
INC PDATA ; E6 40
BNE .1 ; D0 02
INC PDATA+1 ; E6 41
.1
RTS ; 60
FE11
INC A3L ; E6 40
BNE RTS5 ; D0
INC A3H ; E6 41
RTS5 RTS ; 60
The only known bug (or lack of feature) is EOF isn't handled. I
didn't feel like "bloating" the code with a few more bytes :-)
Enjoy!
; Title: BrainFuck Interpreter
; File: BF6502A2.Ver2.s
; CPU: 6502
; Platform: Apple ][ //e
; By: Michael Pohoreski
; Date: Dec, 2008
; Description: 135 Byte Interpreter of BrainFuck (Version 2)
; License: BSD "Sharing is Caring!"
;
; Reference: http://en.wikipedia.org/wiki/Brainfuck
; > ++pData;
; < --pData;
; + ++(*pData);
; - --(*pData);
; . putchar(*pData);
; , *pData=getchar();
; [ while (*pData) {
; ] }
;
; Note: Select, Copy, then Shift-INS to paste into AppleWin, or
manually enter...
CALL-151
300:20 E2 F3 A9 06 85 3C A9 08 85 3D
30B:A0 00 84 40 A9 20 85 41
313:20 1D 03 20 C2 FC A0 00 F0 F6 // interpret
31D:B1 3C D0 02 68 68 // fetch
323:A2 07 DD 77 03 F0 04 CA 10 F8 60 // find op
32E:A9 03 48 BD 7F 03 48 18 B1 40 60 // exec
339:4C 11 FE // bf_next
33C:A5 40 D0 02 C6 41 C6 40 60 // bf_prev
345:69 02 18 // bf_inc
348:E9 00 A0 00 91 40 60 // bf_dec
34F:20 0C FD 29 7F 10 F4 // bf_in
356:09 80 4C ED FD // bf_out
35B:D0 19 20 C2 FC B1 3C C9 5D D0 F7 // bf_if
366:F0 0E A5 3C D0 02 C6 3D C6 3C B1 3C C9 5B D0 F2 60 // bf_end
377:2C 2E 5B 3C 5D 3E 2D 2B
37F:4E 55 5A 3B 65 38 47 44
FA62G
0 "++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<
+++++++++++++++.>.+++.------.--------.>+.>."
REM Hello World!
CALL 768
REM http://esolangs.org/wiki/Talk:Brainfuck
0 "++++++++[->-[->-[->-[-]<]<]<]"
REM -n/a-
CALL 768
0 ">++++++++[<++++++++++>-]<[>+>+<<-]>-.>-----.>"
REM OK
CALL 768
0 "+++++++++++++[>+++++++++>++++++++>++++++++>+++++<<<<-]>-.>.---.>++++
+.<----.<.>>+++++.<++++++++.>++++++.<----.----.<.-.>>+.----------.<<+
+.>>>-.<<<++++.>.+++++++.>..>------------------.<<-----.>.>.<-.<<+."
REM ***@yahoo.co.nz
CALL 768
0 "++++++++[->-[->-[->-[-]<]<]<]>++++++++[<++++++++++>-]<[>+>+<<-]
>-.>-----.>"
; Source
;pCode EQU $3C ; can't use $00C0, used by AppleSoft!
;pData EQU $FE ; shouldn't use $00DA, used by AppleSoft: LINENUMONERR
BFPC EQU $3C ; BFPC/pCode same as A1L/H
DATA EQU $40 ; DATA/pData same as A3L/H
HGR EQU $F3E2
HGR EQU $F3D8
COUT EQU $FDED
RDKEY EQU $FD0C
NXTA1_8 EQU $FCC2 ; standard entry point is NXTA1 = $FCBA
STOR_6 EQU $FE11 ; standard entry point is STOR = $FE0B
.ORG $300
; JSR HGR2 ; 20 D8 F3 ; If want 16K of data space... uncomment
JSR HGR ; 20 E2 F3 ; Clear 8K of data space
LDA #$06 ; A9 06 ; $0806 first Applesoft token
STA BFPC ; 85 3C
LDA #$08 ; A9 08 ; $0806 first Applesoft token
STA BFPC+1 ; 85 3D
LDY #$00 ; A0 00 ; use HGR page 1 for data ...
STY DATA ; 84 40
; UNDO optimization: HGR sets current HiRes page pointer, E6 = $20
LDA #$20 ; A9 20
STA DATA+1 ; 85 41
INTERPRET
JSR FETCH ; 20 1D 03
JSR NXTA1+8 ; 20 C2 FC
LDY #$00 ; A0 00 ; because COUT trashes Y
BEQ INTERPRET ; F0 F6 ; branch always
FETCH
LDA (BFPC),Y ; B1 3C
BNE FIND_OP ; D0 02
EXIT
PLA ; 68
PLA ; 68
; optimization: intentional-fall through : RTS after not finding
opcode
FIND_OP
LDX #$07 ; A2 07 ; 8 Instructions
.1
CMP OPCHAR,X ; DD 77 03 ; table of opcodes (char)
BEQ EXEC ; F0 04
DEX ; CA
BPL .1 ; 10 F8
; Note: (alternative) optimization: intentional fall-through: bad-
opcode so skip next instruction
; and fall into into INC_PC, but this is no longer stands compliant
-- as it
; skips two opcodes instead of one on a invalid opcode
RTS ; 60
EXEC
LDA #$03 ; A9 03 ; high byte of this code address
PHA ; 48
LDA OPFUNCPTR,X ; BD 7F 03 ; function pointer table (address)
PHA ; 48
CLC ; 18 ; optimization: common code
LDA (DATA),Y ; B1 40 ; optimization: common code
RTS ; 60 ; relative jsr
BF_NEXT
; optimization: use monitor rom STOR: BF_NEXT -> STOR+6 = $FE11
; INC DATA ; E6 E5
; BNE .1 ; D0 02
; INC DATA+1 ; E6 E6
;.1
; RTS ; 60
;FE11
; INC A3L ; E6 40
; BNE RTS5 ; D0
; INC A3H ; E6 41
;RTS5 RTS ; 60
JMP STOR+6 ; 4C 11 FE
BF_PREV
LDA DATA ; A5 40
BNE .1 ; D0 02
DEC DATA+1 ; C6 41
.1
DEC DATA ; C6 40
RTS ; 60
BF_INC
ADC #$02 ; 69 02 ; optimization: n+2-1 = n+1
CLC ; 18 ; optimization: fall-through into BF_INCDEC
BF_DEC
SBC #$00 ; E9 00
BF_INCDEC
LDY #$00 ; A0 00
STA (DATA),Y ; 91 40
RTS ; 60
BF_IN
JSR RDKEY ; 20 0C FD ; trashes Y
AND #$7F ; 29 7F ; convert 8-bit Apple Text to 7-bit ASCII
BPL BF_INCDEC ; 10 F4 ; optmization: BPL BF_INCDEC (10 F4)
BF_OUT
ORA #$80 ; 09 80 ; output Hi-Bit Apple Text !
JMP COUT ; 4C ED FD ; trashes A, Y
BF_IF ; if( !*pData ) pc = ']'
BNE .3 ; D0 19 ; optimization: BEQ .1, therefore BNE RTS
; RTS
; optimization: JSR INC_PC -> JSR NXTA1+8 = $FCC2
;INC_PC -> NXTA1+8 = $FCC2
; INC BFPC ; E6 3C
; BNE .1 ; D0 02
; INC BFPC+1 ; E6 3D
;.1
; RTS ; 60
.1
JSR NXTA1+8 ; 20 C2 FC
LDA (BFPC), Y ; B1 3C
CMP ']' ; C9 5D
BNE .1 ; D0 F7
.2
; optimization: intentional-fall through: remove RTS -- we got here
if BEQ, so exit...
BF_END ; if( !*pData ) pc = '['
BEQ .3 ; F0 0E ; optimization: BNE .1, therefore BEQ RTS
.1
LDA BFPC ; A5 3C
BNE .2 ; D0 02
DEC BFPC+1 ; C6 3D
.2
DEC BFPC ; C6 3C
LDA (BFPC),Y ; B1 3C
CMP '[' ; C9 5B
BNE .1 ; D0 F2
.3
RTS ; 60
OPCHAR DA ",.[<]>-+" ; sorted: 2B 2C 2D 2E 3C 3E 5B 5D
OPFUNCPTR ; sorted by usage: least commonly called to most frequently
called
DFB BF_IN -1 ; , 2C
DFB BF_OUT -1 ; . 2E
DFB BF_IF -1 ; [ 5B
DFB BF_PREV-1 ; < 3C
DFB BF_END -1 ; ] 5D
DFB BF_NEXT-1 ; > 3E
DFB BF_DEC -1 ; - 2D
DFB BF_INC -1 ; + 2B
// AppleWin symbols...
SYM BRAINFUCK = 300
SYM LASTVARS = 303
SYM INTERPRET = 313
SYM FETCH = 31D
SYM EXIT = 320
SYM FIND_OP = 323
SYM EXEC = 32E
SYM BF_NEXT = 339 // > 3E
SYM BF_NEXT_1 = 33B
SYM BF_PREV = 33C // < 3C
SYM BF_PREV_1 = 342
SYM BF_INC = 345 // + 2B
SYM BF_DEC = 348 // - 2D
SYM BF_INCDEC = 34A
SYM BF_IN = 34F // , 2C
SYM BF_OUT = 356 // . 2E
SYM BF_IF = 35B // [ 5B
SYM BF_IF_1 = 35D
SYM BF_IF_2 = 35E
SYM BF_END = 366 // ] 5D
SYM BF_END_1 = 368
SYM BF_END_2 = 36E
SYM BF_END_3 = 376
SYM NXTA1_8 = FCC2
SYM STOR_6 = FE11
SYM OPCHAR = 377
SYM OPFUNCPTR = 37F
Notes:
Apple Specific Optimizations:
- use F800 rom code :-)
1) INC_PC -> NXTA1+8 = $FCC2
INC BFPC ; E6 3C
BNE .1 ; D0 02
INC BFPC+1 ; E6 3D
.1
RTS ; 60
FE11
INC A3L ; E6 40
BNE RTS5 ; D0
INC A3H ; E6 41
RTS5 RTS ; 60
2) BF_NEXT -> STOR+6 = $FE11
INC PDATA ; E6 40
BNE .1 ; D0 02
INC PDATA+1 ; E6 41
.1
RTS ; 60
FE11
INC A3L ; E6 40
BNE RTS5 ; D0
INC A3H ; E6 41
RTS5 RTS ; 60