142 lines
4.1 KiB
Fennel
142 lines
4.1 KiB
Fennel
(local command (require :core.command))
|
|
(local {: spawn : kill } (require :lib.spawn))
|
|
(local socket (require :socket))
|
|
(local json (require :lib.dkjson))
|
|
(local asm (require :asm.asm))
|
|
(local lume (require :lib.lume))
|
|
|
|
(local gsplus-path "/home/jeremy/src/gsplus/result/bin/GSplus")
|
|
|
|
(local debug-port 8769)
|
|
(local reg-write-format {
|
|
:PC " k%06X"
|
|
:A " a%04X"
|
|
:X " x%04X"
|
|
:Y " y%04X"
|
|
:S " s%04X"
|
|
:D " d%04X"
|
|
:B " b%02X"
|
|
:PSR " p%06X"
|
|
})
|
|
(fn get-cpu-reg [response]
|
|
(-> response
|
|
(lume.filter #(= $1.type :cpu))
|
|
(. 1 :data)))
|
|
|
|
(local machine
|
|
{:boot
|
|
(fn [self]
|
|
(when (not self.pid)
|
|
(set self.pid (spawn [:nixGL gsplus-path :-debugport (tostring debug-port)]))))
|
|
:die
|
|
(fn [self]
|
|
(self:disconnect)
|
|
(when self.pid
|
|
(kill (- self.pid) 1)
|
|
(set self.pid nil)))
|
|
:connect
|
|
(fn [self]
|
|
(when (not self.socket)
|
|
(set self.socket (socket.connect :localhost debug-port))
|
|
(if self.socket
|
|
(self.socket:settimeout 1)
|
|
(love.timer.sleep 0.25))))
|
|
:disconnect
|
|
(fn [self]
|
|
(when self.socket
|
|
(self.socket:close)
|
|
(set self.socket nil)))
|
|
:connected? (fn [self] self.socket)
|
|
:cmd (fn [self cmd] (self.socket:send (.. cmd "\n")))
|
|
:response
|
|
(fn [self]
|
|
(var bytes "")
|
|
(var done false)
|
|
(while (not done)
|
|
(local (line err) (self.socket:receive))
|
|
(set done (or (= line "") (= line nil)))
|
|
(when line (set bytes (.. bytes line))))
|
|
(json.decode bytes))
|
|
:cmd-response (fn [self cmd] (self:cmd cmd) (self:response))
|
|
:hello (fn [self] (self:cmd-response "1"))
|
|
:continue (fn [self] (self:cmd "3"))
|
|
:step (fn [self] (self:cmd-response "2"))
|
|
:getreg (fn [self] (get-cpu-reg (self:cmd-response "4")))
|
|
:set-bp (fn [self addr] (self:cmd-response (.. "8" (string.format "%06X" addr))))
|
|
:delete-bp (fn [self addr] (self:cmd-response (.. "9" (string.format "%06X" addr))))
|
|
:get-bp (fn [self] (self:cmd-response "A"))
|
|
:write
|
|
(fn [self addr bytes]
|
|
(var bytes-to-write bytes)
|
|
(var addrout addr)
|
|
(while (> (length bytes-to-write) 0)
|
|
(local bytesout (bytes-to-write:sub 1 50))
|
|
(self:cmd-response (.. "7" (string.format "%06X" addrout) (bytesout:tohex)))
|
|
(set bytes-to-write (bytes-to-write:sub 51))
|
|
(set addrout (+ addrout 50))))
|
|
:setreg
|
|
(fn [self regvals]
|
|
(var bytes "5")
|
|
(each [reg val (pairs regvals)]
|
|
(set bytes (.. bytes (string.format (. reg-write-format reg) val))))
|
|
(self:cmd-response bytes))
|
|
:stop-at
|
|
(fn [self addr k]
|
|
(local fulladdr (bit.bor addr (bit.lshift (or k 0) 16)))
|
|
(self:set-bp fulladdr)
|
|
; wait for breakpoint to be hit
|
|
(var bp-response (self:response))
|
|
(self:delete-bp fulladdr)
|
|
(when (not bp-response)
|
|
; attempt to consume extra response in case the breakpoint was actually hit while sending the message to delete the breakpoint
|
|
(set bp-response (self:response)))
|
|
(when bp-response
|
|
(local reg (get-cpu-reg bp-response))
|
|
(local pc (tonumber reg.PC 16))
|
|
(local curr-k (tonumber reg.K 16))
|
|
(and (= pc addr) (= curr-k (or k 0)))))
|
|
|
|
:jump (fn [self addr] (self:setreg {:PC addr}))
|
|
:do
|
|
(fn [self prg f]
|
|
(when (self:stop-at (prg:lookup-addr :debug-stub))
|
|
(f self)
|
|
(self:continue)
|
|
true))
|
|
:hotswap
|
|
(fn [self prg-old prg-new]
|
|
(self:do prg-old
|
|
(fn []
|
|
(prg-new:upload self)
|
|
; on-hotswap may move around in memory; we can handle this
|
|
(self:jump (prg-new:lookup-addr :on-hotswap)))))
|
|
:stub
|
|
(fn [self org post-check-jump ...]
|
|
(org:append :debug-stub [:jmp post-check-jump] :on-hotswap ...))
|
|
})
|
|
|
|
(command.add #(not machine.pid) {
|
|
"gsplus:launch-gsplus" #(machine:boot)
|
|
"gsplus:boot" (fn []
|
|
(machine:boot)
|
|
(while (not machine.socket) (machine:connect))
|
|
(machine:hello)
|
|
)
|
|
})
|
|
(command.add (fn [] machine.pid) {
|
|
"gsplus:kill-gsplus" #(machine:die)
|
|
})
|
|
(command.add (fn [] machine.socket) {
|
|
"gsplus:disconnect" #(machine:disconnect)
|
|
"gsplus:hello" #(machine:hello)
|
|
"gsplus:dump-cpu-state" #(pp (machine:getreg))
|
|
"gsplus:step" #(pp (machine:step))
|
|
"gsplus:continue" #(pp (machine:continue))
|
|
})
|
|
(command.add #(not machine.socket) {
|
|
"gsplus:connect" #(machine:connect)
|
|
})
|
|
|
|
machine
|
|
|