183 lines
5.1 KiB
NASM
183 lines
5.1 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:
|
||
|
.asciiz '2 3 +'
|
||
|
|
||
|
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
|
||
|
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
|
||
|
jsr georgescii_decimal_to_value
|
||
|
jsr store_binary
|
||
|
iny
|
||
|
rts
|
||
|
.not_nat:
|
||
|
rts
|
||
|
|
||
|
; georgescii decmal 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
|
||
|
phy
|
||
|
phx
|
||
|
lda (binary_subroutine_address) ; get the subroutine length
|
||
|
tax ; loop counter
|
||
|
ldy #0 ; index into subroutine
|
||
|
.loop:
|
||
|
lda (binary_subroutine_address), y
|
||
|
jsr store_binary
|
||
|
iny
|
||
|
dex
|
||
|
bne .loop
|
||
|
.end:
|
||
|
phx
|
||
|
ply
|
||
|
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:
|
||
|
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
|
||
|
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:
|
||
|
jsr get_subroutine_address
|
||
|
jsr store_contiguous_binary
|
||
|
rts
|
||
|
|
||
|
|
||
|
isr: ; interrupt service routine
|
||
|
pha
|
||
|
phx
|
||
|
phy
|
||
|
ply
|
||
|
plx
|
||
|
pla
|
||
|
rti
|
||
|
|
||
|
|
||
|
|
||
|
.org $fffc
|
||
|
.word reset
|
||
|
.word isr
|