honeylisp/test.fnl

202 lines
4.2 KiB
Fennel

(local {: program : dat-parser : new-block : parse-dats : lo : hi} (require "asm"))
(local {: stream : kvstream : one} (require "stream"))
(local prg (program))
(local code1 (prg:org 0xc00))
(fn dat-parser.vm [bytecodes]
(local block (new-block))
(each [_ bytecode (ipairs (lume.slice bytecodes 2))]
(if
(= (type bytecode) :number)
(parse-dats block [[:ref :lit] [:dw bytecode]])
(= (type bytecode) :string)
(parse-dats block [[:ref bytecode]])
(= (type bytecode) :table)
(parse-dats block bytecode)
(error (.. "VM can't parse " (fv bytecode)))))
block)
(local mon {
:hexout :0xfdda
:putchar :0xfded
:bell :0xff3a
})
(local vm {
:IP :0x60
:IPH :0x61
:W :0x62
:WH :0x63
:ROFF :0x64
:TOP :0x80
:TOPH :0x81
:ST1 :0x7e
:ST1H :0x7f
:ST2 :0x7c
:ST2H :0x7d
:RSTACK :0x6000
:ret (fn [self] [:jmp :next])
:push
(fn [self v]
(local l (bit.band v 0xff))
(local h (bit.band (bit.rshift v 8) 0xff))
[:block
[:inx]
[:inx]
[:lda l]
[:sta [self.TOP :x]]
[:lda h]
[:sta [self.TOPH :x]]
])
:drop (fn [self] [:block [:dex] [:dex]])
:def
(fn [self name ...]
(code1:append name (table.unpack (lume.concat [...] [(self:ret)]))))
:word
(fn [self name ...]
(code1:append name [:jsr :subroutine] [:vm ...] [:vm :ret]))
})
(fn inc16 [l h]
[:block
[:inc l]
[:bne :done]
[:inc h]
:done
])
(fn add16 [l h]
[:block
[:clc]
[:adc l]
[:sta l]
[:bcc :go]
[:inc h]
:go
])
(code1:append :next
[:ldy 0]
[:lda [vm.IP] :y] [:sta vm.W]
(inc16 vm.IP vm.IPH)
[:lda [vm.IP] :y] [:sta vm.WH]
(inc16 vm.IP vm.IPH)
[:jmp [vm.W]])
(code1:append :reset
[:lda #(lo ($1:lookup-addr :quit))]
[:sta vm.IP]
[:lda #(hi ($1:lookup-addr :quit))]
[:sta vm.IPH]
[:lda 0]
[:sta vm.ROFF]
[:ldx 0xfe]
[:rts])
(vm:def
:subroutine ; usage: [jsr :subroutine] followed by bytecode
[:ldy vm.ROFF]
[:lda vm.IP] [:sta vm.RSTACK :y] [:iny]
[:lda vm.IPH] [:sta vm.RSTACK :y] [:iny]
[:sty vm.ROFF]
:interpret ; usage: [jsr :interpret] followed by bytecode
[:pla] [:sta vm.IP] [:pla] [:sta vm.IPH]
(inc16 vm.IP vm.IPH))
(vm:def :ret
[:ldy vm.ROFF]
[:dey] [:lda vm.RSTACK :y] [:sta vm.IPH]
[:dey] [:lda vm.RSTACK :y] [:sta vm.IP]
[:sty vm.ROFF])
(code1:append :native [:jmp [vm.IP]])
(code1:append :quit [:rts])
(vm:def :mixed-hires
[:sta :0xc050]
[:sta :0xc057]
[:sta :0xc053])
(vm:def :drop (vm:drop))
(vm:def :dup
[:inx] [:inx]
[:lda vm.ST1H :x]
[:sta vm.TOPH :x]
[:lda vm.ST1 :x]
[:sta vm.TOP :x])
(vm:def :swap
[:lda vm.TOP :x]
[:ldy vm.ST1 :x]
[:sty vm.TOP :x]
[:sta vm.ST1 :x]
[:lda vm.TOPH :x]
[:ldy vm.ST1H :x]
[:sty vm.TOPH :x]
[:sta vm.ST1H :x])
(vm:def :>rot ; (a b c -- c a b)
[:lda vm.TOP :x] ; a: c (a b c)
[:ldy vm.ST2 :x] ; y: a (a b c)
[:sta vm.ST2 :x] ; a: c (c b c)
[:lda vm.ST1 :x] ; a: b (c b c)
[:sta vm.TOP :x] ; a: b (c b b)
[:sty vm.ST1 :x] ; y: a (c a b)
[:lda vm.TOPH :x] ; a: c (a b c)
[:ldy vm.ST2H :x] ; y: a (a b c)
[:sta vm.ST2H :x] ; a: c (c b c)
[:lda vm.ST1H :x] ; a: b (c b c)
[:sta vm.TOPH :x] ; a: b (c b b)
[:sty vm.ST1H :x] ; y: a (c a b)
)
(vm:def :<rot ; (a b c -- b c a)
[:lda vm.TOP :x] ; a: c (a b c)
[:ldy vm.ST1 :x] ; y: b (a b c)
[:sta vm.ST1 :x] ; a: c (a c c)
[:lda vm.ST2 :x] ; a: a (a c c)
[:sta vm.TOP :x] ; a: a (a c a)
[:sty vm.ST1 :x] ; y: b (b c a)
[:lda vm.TOPH :x] ; a: c (a b c)
[:ldy vm.ST1H :x] ; y: b (a b c)
[:sta vm.ST1H :x] ; a: c (a c c)
[:lda vm.ST2H :x] ; a: a (a c c)
[:sta vm.TOPH :x] ; a: a (a c a)
[:sty vm.ST1H :x] ; y: b (b c a)
)
(vm:def "@"
[:lda [vm.TOP :x]]
[:tay]
(inc16 vm.TOP vm.TOPH)
[:lda [vm.TOP :x]]
[:sta vm.TOPH :x]
[:sty vm.TOP :x])
(vm:def :lit
[:inx] [:inx] [:ldy 0]
[:lda [vm.IP] :y] [:sta vm.TOP :x]
(inc16 vm.IP vm.IPH)
[:lda [vm.IP] :y] [:sta vm.TOPH :x]
(inc16 vm.IP vm.IPH))
(vm:def :.
[:lda vm.TOPH :x]
[:jsr mon.hexout]
[:lda vm.TOP :x]
[:jsr mon.hexout]
[:lda (string.byte " ") ]
[:jsr mon.putchar]
(vm:drop))
(code1:append :main
[:jsr :reset]
[:jsr :interpret]
[:vm 0xbabe 0xcafe :. :. :quit])
(prg:assemble)
prg