diff --git a/README.md b/README.md index a6b08fa..4e7fb13 100644 --- a/README.md +++ b/README.md @@ -16,16 +16,26 @@ fuzzy is part of george, and shouldn't run anywhere else. #### low-level -(most of) fuzzy could be made with assembler macros, but that's no fun +(most of) fuzzy could be written as assembler macros, but that's no fun #### reliable if fuzzy says it can run, george can run it -## feature progress +## how to work on fuzzy -- [x] parser - - roughly complete, but want to finish the whole pipeline before adding things to the parser -- [x] typechecker - - generates a "type stack" from parsed input and checks that word definition types match their body -- [ ] code generation +edit `program.asm` and run `./run.sh`. the program gets included in the fuzzy compiler `fuzzy.asm` and is assembled with `vasm6502_oldstyle`, then george runs the program, reading out her system image when she reaches `stp` or `brk` + +then the program she compiled gets formatted as a standard 32k rom, and she reads it again, and then shows her system image again when the program finishes (hits `stp` or `brk`). + +since fuzzy works on a zero-page data stack, it's pretty easy to read the results of a program from the hexdump. + +for now this loop only works on apple silicon, but eventually i'll compile a `george` binary for x86 linux and switch based on the host platform. + +## reference help + +i wrote [syntax](./syntax.md) and [semantics](./semantics.md) docs to keep track of how fuzzy works before starting work on the compiler implementation in assembly. they're the _official_ source of truth for how fuzzy works. assume that the compiler implementation is always in flux :) + +## a note on implementation + +i was writing fuzzy's compiler in rust for a sec, but then i realized that it would be a fun challenge to write it in assembly. it's been wayyy easier! and fun! and so rewarding :) this feels like a flex but i'm genuinely just so happy to see george & fuzzy playing together in this little computer world i've made <3 diff --git a/fuzzy.asm b/fuzzy.asm index 0ff7e59..31f3364 100644 --- a/fuzzy.asm +++ b/fuzzy.asm @@ -12,7 +12,7 @@ binary_subroutine_address = binary_base_index + 1 ; pointer to a subroutine to b .include "./subroutines.inc" program_text: - .asciiz '2 3 +' + .include "./program.inc" reset: sei @@ -74,6 +74,9 @@ compile_values_op: ; 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? @@ -84,14 +87,20 @@ compile_values_nat: 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 decmal value in a register, return equivalent plain value in a register +; 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 @@ -113,11 +122,9 @@ store_binary: ; 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 + ldy #1 ; index into subroutine, offset by one to skip subroutine length .loop: lda (binary_subroutine_address), y jsr store_binary @@ -125,8 +132,6 @@ store_contiguous_binary: dex bne .loop .end: - phx - ply pla rts @@ -136,6 +141,7 @@ store_contiguous_binary: ; 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 @@ -155,16 +161,42 @@ get_subroutine_address: .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 diff --git a/george b/george index 27b4099..0693d36 100755 Binary files a/george and b/george differ diff --git a/program.inc b/program.inc new file mode 100644 index 0000000..bfb9f44 --- /dev/null +++ b/program.inc @@ -0,0 +1 @@ + .asciiz '2 3 +' diff --git a/run.sh b/run.sh index 301275d..51090f6 100755 --- a/run.sh +++ b/run.sh @@ -2,6 +2,15 @@ set -e -vasm6502_oldstyle fuzzy.asm -dotdir -wdc02 -ldots -Fbin -o fuzzy.rom; -cat fuzzy.rom | ./george > result.bin; +rm *.bin *.rom +vasm6502_oldstyle fuzzy.asm -dotdir -wdc02 -ldots -Fbin -o fuzzy.rom &> /dev/null; +echo -e "\nʕ·ᴥ·ʔ- source text:\n"; +cat program.inc; +cat fuzzy.rom | ./george > compiled.bin; +dd skip=16384 count=500 if=compiled.bin of=compiled.rom bs=1 &> /dev/null; +truncate -s 32k compiled.rom &> /dev/null; +printf '\x80\x00\x00' | dd of=compiled.rom bs=1 seek=32765 count=3 conv=notrunc &> /dev/null; +cat compiled.rom | ./george > result.bin; +echo -e "\n\nʕ·ᴥ·ʔ- compiled program result:\n"; hexdump -C ./result.bin; +echo -e ""; diff --git a/subroutines.inc b/subroutines.inc index 1094678..aaecae5 100644 --- a/subroutines.inc +++ b/subroutines.inc @@ -4,4 +4,12 @@ test_contiguous_binary: ; 1 - assembled from "plus.asm" subroutine_plus: - .byte 17,$b5,$18,$75,$00,$95,$02,$b5,$02,$75,$01,$95,$03,$e8,$03,$60,$e8,$60 + .byte 15, $18,$b5,$00,$75,$02,$95, $02, $b5, $01, $75, $03, $95, $03, $ca, $ca + +; 2 +subroutine_push: + .byte 6,$ca,$ca,$95,$0,$74,$1 + ; dex + ; dex + ; sta 0, x + ; stz 1, x