fuzzy/fuzzy.asm

215 lines
5.7 KiB
NASM

; ʕ·ᴥ·ʔ- fuzzy v0 rev 0: parse program text and spit out binary representation @ $4000
.include "./macro.inc"
n = $05 ; temporary storage for data stack operations
base = $00
result_binary_base = base ; pointer to where the next byte of binary data should be stored0
binary_base_index = result_binary_base + 2 ; offset for that pointer
binary_subroutine_address = binary_base_index + 1 ; pointer to a subroutine to be written to the binary
.org $8000
.include "./subroutines.inc"
program_text:
.include "./program.inc"
reset:
sei
lda #0
ldx #0
ldy #0
main:
stz binary_base_index
lda #$40
sta result_binary_base + 1 ; set where to store resulting binary
stz binary_subroutine_address
lda #$80
sta binary_subroutine_address + 1 ; available subroutines start at $8000
jsr compile_values
stp
; parser loop, eventually this will be able to handle longer program strings, but indexing by y is fine for now
compile_values:
ldy #0
parser_loop:
lda program_text, y ; get character at index
cmp #0 ; is eof?
beq .end ; yes, exit loop
cmp #20 ; is space?
beq parser_loop ; yes, skip this char
cmp #12 ; is newline?
beq .newline ; yes, handle newline
jsr compile_values_op
jsr compile_values_nat
.newline: ; we reached a newline, y is program string index
iny ; WARN: don't accidentally iny in this loop w/out handling a character
lda program_text, y ; load next char
cmp #12 ; is newline?
bne parser_loop ; no, keep parsing tokens
rts ; yes, no more tokens in body (see syntax.md for info)
.end:
rts
; a holds character value, y program text index, only iny if you find a matching character & consume it
compile_values_op:
cmp #"+" ; i personally think this syntax is really silly but whatever, one of these days i'm gonna write my own assembler and document everything cause vasm documentation is kinda terrible
bne .next
.is_plus:
lda #1
jsr store_subroutine
rts
.next:
rts
; cmp #"!" ; commenting these out for now to handle a single simple case
; cmp #"&"
; cmp #"|"
; cmp #"-"
; cmp #"*"
; cmp #"/"
; cmp #"="
; cmp #">"
; cmp #"<"
; cmp #"#"
; a holds character value, y program text index, only iny if you find a matching character & consume it
; TODO:
; 1-3 digit decimal values
; 1-2 digit hex values
compile_values_nat:
; TODO:
; cmp #"$" ; is hex?
; bne .decimal ; no, try decimal
; cmp
; rts
cmp #47 ; less than (before) start of 0-9 georgescii range?
bcc .not_nat
cmp #57 ; greater than end of 0-9 georgescii range?
bcs .not_nat
pha
lda #$a9 ; $a9: lda imm
jsr store_binary
pla
jsr georgescii_decimal_to_value
jsr store_binary
lda #2 ; push
jsr store_subroutine
iny
rts
.not_nat:
rts
; georgescii decimal value in a register, return equivalent plain value in a register
georgescii_decimal_to_value:
clc
sbc #$30 ; decimal digits start at georgescii $30
rts
; we have binary in the a register we want to store
store_binary:
phy
ldy binary_base_index
sta (result_binary_base), y
inc binary_base_index
bne .not_overflow ; did we roll over?
inc result_binary_base + 1 ; yes, roll over base address
.not_overflow: ; no, carry on as normal
ply
rts
; binary_subroutine_address is a pointer to a subroutine that we want to store
; the first byte at the subroutine's address is its length
store_contiguous_binary:
pha ; just to be safe
lda (binary_subroutine_address) ; get the subroutine length
tax ; loop counter
ldy #1 ; index into subroutine, offset by one to skip subroutine length
.loop:
lda (binary_subroutine_address), y
jsr store_binary
iny
dex
bne .loop
.end:
pla
rts
; this wouldn't be necessary if we could get the
; address of a label in vasm, but that's for another time
; (when i feel like writing an assembler lol)
; for now, pass the index of the subroutine (in subroutines.asm)
; to a and it will get written to binary_subroutine_address
get_subroutine_address:
pha
tax ; set up counter
bne .loop ; first subrotine?
stz binary_subroutine_address ; yes, store its address
lda #$80
sta binary_subroutine_address + 1
rts
.loop: ; loop through
lda (binary_subroutine_address) ; no, load length of subroutine
inc ; distance from next subroutine
clc
adc binary_subroutine_address ; add it to the current address
sta binary_subroutine_address
bcs .no_carry
lda binary_subroutine_address + 1 ; add the carry to the high byte of address
adc #0
sta binary_subroutine_address + 1
.no_carry:
dex ; is this our address?
bne .loop ; yes, we're done
pla
rts
; pass subroutine index to a and it will get written into the binary
; TODO: stabilize subroutine location & just write a `jsr $subroutine` to the binary
store_subroutine:
pha
phy
phx
jsr get_subroutine_address
jsr store_contiguous_binary
; reset subroutine address
stz binary_subroutine_address
lda #$80
sta binary_subroutine_address + 1
plx
ply
pla
rts
; write error message and stop execution
error:
ldy #0
.loop:
lda .message, y
sta $4000, y
beq .end
iny
bra .loop
.end:
stp
.message:
.asciiz "ruh roh! fuzzy couldn't compile"
isr: ; interrupt service routine
pha
phx
phy
ply
plx
pla
rti
.org $fffc
.word reset
.word isr