;Brainfuck Interpreter

;antiquekid3 - 3/28/2012

;

;Enter your BF program and press enter to execute. RAM will first be cleared,

;then program will start. Program finishes with "

\rdone!" printed to screen.

;If you make a mistake during the entry of your program, DEL ($7F), which is

;mapped to the backspace key for many people, will allow you to correct the

;program. Invalid characters are not entered, saving valuable RAM space. A true

;backspace character ($08, or ^H) will also operate as a DEL.

;A handy subroutine can be found at the bottom for printing null-terminated

;strings.

;Typically, another stack is used for storing the return addresses when jumping

;to subroutines, since the main stack is used to enter the program, and then is

;used for the "tape" memory. Since the 6800 lacks a Y index register, one must

;make due with what one has.

;One thing I've noticed is that if I switch around the direction of the tape,

;such that the starting end is higher in RAM (and I change the > and < commands

;accordingly), the program runs much slower. Any clue as to why that would be?

;I have a feeling it could be a result from direct vs. extended addressing,

;but I'm not entirely sure.

OUTCH EQU $E1D1

INCH EQU $E1AC

CONTRL EQU $E0E3

RAMSTART EQU $0000 ;start of RAM (tape for BF program)

ARRAY EQU $5000 ;start of BF code array

ARREND EQU $5BFF ;end of BF code array

VARS EQU $5C00 ;variables

SCRATCH EQU $5D00 ;start of code

RAMEND EQU $5FFF ;end of RAM

START EQU $A048 ;for SWTBUG's 'G' command

;Memory Map:

;RAMSTART to ARRAY = data

;ARRAY to ARREND = BF code

;VARS to SCRATCH = variables

;SCRATCH to $BFFF = ASM code

;SP = data index

;X = code index

ORG START

FDB SCRATCH ;set $A048 = #SCRATCH (start of program)

ORG VARS

Greet FCB $0A , $0D

FCC "Enter code and press return:"

LF FCB $0A , $0D , $00

Clear FCC "Clearing RAM..."

FCB $00

Done FCC "done!"

FCB $00

bs FCB $20 , $08 , $08 , $20 , $08 , $00 ;DEL key sequence

bs1 FCB $20 , $08 , $00 ;^H key sequence

invalid FCB $08 , $3F , $08 , $00

Address RMB 2 ;used to store current SP

Brace RMB 1 ;used to count up to 255 (brace depth)

RMB 8 ;used as return address stack for JSR

RtnAdd RMB 1

ORG SCRATCH

LDX #Greet

LDS #RtnAdd

JSR PRINT ;print greeting message

LDS #ARREND

input: JSR INCH

CMPA #$0D ;return

BEQ run

TAB

ANDB #%11111101

CMPB # ','

BEQ valid

CMPA # '+'

BEQ valid

CMPA # '-'

BEQ valid

CMPB # '<'

BEQ valid

CMPA # '['

BEQ valid

CMPA # ']'

BEQ valid

CMPA #$7F ;"delete" (backspace key)

BNE next

del: TSX

DEX

CPX #ARREND

BEQ input

LDX #bs

JSR PRINT

PULA

BRA input

fwd: LDAA #$20

JSR OUTCH

toInput: BRA input

next: CMPA # 8 ;"backspace" (^H)

BNE inv

TSX

DEX

CPX #ARREND

BEQ fwd

PULA

LDX #bs1

JSR PRINT

BRA input

inv: LDX #invalid

JSR PRINT

BRA toInput

valid: PSHA

BRA toInput

run: PSHA ;mark EOF as $0D (return)

LDX #LF

JSR PRINT

;zero out data array

LDX #Clear

JSR PRINT

LDX #ARRAY

zero: CLR 0 , X

DEX

CPX #$FFFF

BNE zero

run1: LDX #Done

JSR PRINT

LDX #LF

JSR PRINT

LDX #ARREND

LDS #RAMSTART

DES ;since PUL first increments SP, decrease SP beforehand

INX

CLR Brace

loop: DEX

LDAA 0 , X

CMPA # '>'

BNE next2

INS

BRA loop

next2: CMPA # '<'

BNE next3

DES

BRA loop

next3: CMPA # '+'

BNE next4

PULA

INCA

PSHA

BRA loop

next4: CMPA # '-'

BNE next5

PULA

DECA

PSHA

BRA loop

next5: CMPA # ','

BNE next6

PULA

STS Address

LDS #RtnAdd

JSR INCH

LDS Address

PSHA

BRA loop

next6: CMPA # '.'

BNE leftb

PULA

PSHA

STS Address

LDS #RtnAdd

JSR OUTCH

LDS Address

BRA loop

leftb: CMPA # '['

BNE rightb

CLR Brace

INC Brace

PULA

PSHA

TSTA

BNE loop

find1: DEX

LDAA 0 , X

CMPA # ']'

BNE notrb1

DEC Brace

BEQ loop

BRA find1

notrb1: CMPA # '['

BNE find1

INC Brace

BRA find1

rightb: CMPA # ']'

BNE stop

CLR Brace

INC Brace

PULA

PSHA

TSTA

BEQ loop

find2: INX

LDAA 0 , X

CMPA # '['

BNE notlb2

DEC Brace

BEQ toLoop

BRA find2

notlb2: CMPA # ']'

BNE find2

INC Brace

BRA find2

stop : LDS #RtnAdd

LDX #LF

JSR PRINT

LDX #Done

JSR PRINT

LDX #SCRATCH

STX START

JMP CONTRL

toLoop: JMP loop

;Subroutine to print a null-terminated string

;A = (changed)

;B = (not changed)

;X = starting address of string (changed)

;S = (not changed)

PRINT: LDAA 0 , X

BEQ END

JSR OUTCH

INX

BRA PRINT