Preserve state across hot code reload!!

This commit is contained in:
Jeremy Penner 2021-05-15 11:50:53 -04:00
parent a5dbc5fcfc
commit 1db882c150
8 changed files with 58 additions and 16 deletions

Binary file not shown.

View file

@ -115,7 +115,7 @@
; takes the form [:op args] ; takes the form [:op args]
; pdat - a parsed dat; takes the form {:type type :addr addr ...} ; pdat - a parsed dat; takes the form {:type type :addr addr ...}
(local dat-parser {}) (local dat-parser {})
(fn new-block [last-symbol] {:type :block :pdats [] :symbols {} :globals {} : last-symbol}) (fn new-block [last-symbol] {:type :block :pdats [] :preserved {} :symbols {} :globals {} : last-symbol})
(fn parse-dats [block dats] (fn parse-dats [block dats]
(each [_ dat (ipairs dats)] (each [_ dat (ipairs dats)]
@ -139,7 +139,10 @@
(table.insert block.pdats pdat) (table.insert block.pdats pdat)
(when pdat.globals (when pdat.globals
(each [name _ (pairs pdat.globals)] (each [name _ (pairs pdat.globals)]
(tset block.globals name (length block.pdats)))))))) (tset block.globals name (length block.pdats))))
(when pdat.preserved
(each [name pdat-preserved (pairs pdat.preserved)]
(tset block.preserved name pdat-preserved)))))))
block) block)
(fn dat-parser.op [op] (fn dat-parser.op [op]
@ -166,6 +169,13 @@
nil) nil)
(fn dat-parser.align [pad] {:type :pad :align (. pad 2)}) (fn dat-parser.align [pad] {:type :pad :align (. pad 2)})
(fn dat-parser.hot-preserve [[_ label & dats] block]
(let [preserve-block (new-block)]
(tset block.preserved label preserve-block)
(tset preserve-block.globals label true)
(parse-dats preserve-block [label])
(parse-dats preserve-block dats)
preserve-block))
(local pdat-processor { (local pdat-processor {
:op {} :op {}
@ -338,6 +348,17 @@
(self.dbgfile:close) (self.dbgfile:close)
(set self.dbgfile nil)) (set self.dbgfile nil))
self) self)
:read-hotswap
(fn [self machine]
(let [hotswap {}]
(each [_ block (pairs self.org-to-block)]
(each [label pdat (pairs block.preserved)]
(tset hotswap label (machine:read pdat.addr pdat.size))))
hotswap))
:write-hotswap
(fn [self machine hotswap]
(each [label bytes (pairs hotswap)]
(machine:write (self:lookup-addr label) bytes)))
:upload :upload
(fn [self machine] (fn [self machine]
(if machine.upload (machine:upload self) (if machine.upload (machine:upload self)

View file

@ -385,8 +385,9 @@
(fn vm.var [self name init] (fn vm.var [self name init]
(self.code:append name [:jsr :$dovar] (self.code:append name [:jsr :$dovar]
[:hot-preserve (.. :G-HOT-PRESERVE- name)
(if (= (type init) :table) init (if (= (type init) :table) init
[:dw init]))) [:dw init])]))
(vm:def :$doconst ; usage: [jsr :$doconst] followed by two bytes (vm:def :$doconst ; usage: [jsr :$doconst] followed by two bytes
(vm:reserve) (vm:reserve)

View file

@ -132,7 +132,7 @@
[:jmp (if (= (or map.moveword "") "") :move-noop map.moveword)] [:jmp (if (= (or map.moveword "") "") :move-noop map.moveword)]
[:jmp (if (= (or map.loadword "") "") :next map.loadword)])) [:jmp (if (= (or map.loadword "") "") :next map.loadword)]))
(vm.code:append :map-ptr [:db 0] :map-page [:db 0]) (vm.code:append :map-ptr [:db 0] [:hot-preserve :map-page [:db 0]])
(vm:word :map :lit :map-ptr :get) (vm:word :map :lit :map-ptr :get)
(vm:word :entity-count :map 240 :+ :bget) (vm:word :entity-count :map 240 :+ :bget)
(vm:word :map-player-yx-ptr 241 :+) (vm:word :map-player-yx-ptr 241 :+)

File diff suppressed because one or more lines are too long

View file

@ -45,7 +45,7 @@
[:vm :hires [:vm :hires
:lit :map1 :load-level :lit :map1 :load-level
(vm:forever (vm:forever
(vm:hotswap-sync :lit :map1 :load-level) (vm:hotswap-sync :full-redraw)
:interactive-eval-checkpoint :interactive-eval-checkpoint
:handle-key :handle-key
) )

View file

@ -87,6 +87,20 @@
(when self.monitor (self.monitor:shutdown-session)) (when self.monitor (self.monitor:shutdown-session))
(when (nrepl:connected?) (nrepl:disconnect)) (when (nrepl:connected?) (nrepl:disconnect))
(set self.breakpoints {})) (set self.breakpoints {}))
(fn Machine.read [self addr len]
(-> (self:coro-eval
(.. "(let [bencode (require :bencode)
addr " addr "
len " len "
mem (. manager.machine.devices ::maincpu :spaces :program)]
(var bytes \"\")
(print :reading len :from addr)
(for [i 1 len]
(set bytes (.. bytes (string.char (mem:read_u8 (+ addr i -1))))))
bytes)"))
; result is piped through fennelview; have to eval it to turn it back into bytes
; would be nice if io.write worked
(fennel.eval)))
(fn Machine.write [self addr bytes] (fn Machine.write [self addr bytes]
(if (> (bytes:len) 0x1000) (if (> (bytes:len) 0x1000)
(do (self:write addr (bytes:sub 1 0x1000)) (do (self:write addr (bytes:sub 1 0x1000))
@ -103,11 +117,11 @@
(self:eval "(manager.machine:soft_reset)") (self:eval "(manager.machine:soft_reset)")
(self:eval (string.format "(emu.keypost \"CALL-151\\n %xG\\n\")" (prg:lookup-addr prg.start-symbol)))) (self:eval (string.format "(emu.keypost \"CALL-151\\n %xG\\n\")" (prg:lookup-addr prg.start-symbol))))
(fn Machine.reboot [self] (self:eval "(manager.machine:hard_reset)")) (fn Machine.reboot [self] (self:eval "(manager.machine:hard_reset)"))
(fn Machine.coro-eval [self code] (fn Machine.coro-eval [self code ?handlers]
(var result nil) (var result nil)
(local append-to-result #(set result (.. (or result "") $2))) (local append-to-result #(set result (.. (or result "") $2)))
(self:eval code (self:eval code
(self:coro-handlers (coroutine.running) {:value append-to-result :out append-to-result})) (self:coro-handlers (coroutine.running) {:value append-to-result :out append-to-result} ?handlers))
(coroutine.yield) (coroutine.yield)
(or result "<no result>")) (or result "<no result>"))
(fn Machine.dbgcmd [self cmd ?handlers] (fn Machine.dbgcmd [self cmd ?handlers]
@ -130,10 +144,14 @@
(fn Machine.hotswap [self prg-old prg-new] (fn Machine.hotswap [self prg-old prg-new]
(local addr (prg-old:lookup-addr :debug-stub)) (local addr (prg-old:lookup-addr :debug-stub))
(self:set-bp addr (self:set-bp addr
(fn [] (self:clear-bp addr) #(util.in-coro (fn []
(self:clear-bp addr)
(local hotswap (prg-old:read-hotswap self))
(prg-new:upload self) (prg-new:upload self)
(prg-new:write-hotswap self hotswap)
(self:jump (prg-new:lookup-addr :on-hotswap)) (self:jump (prg-new:lookup-addr :on-hotswap))
(self:continue)))) (self:continue)))))
(fn Machine.overlay [self prg-overlay] (fn Machine.overlay [self prg-overlay]
(self:step) (self:step)
(prg-overlay:upload self) (prg-overlay:upload self)

View file

@ -19,7 +19,7 @@
(fn Session.shutdown-session [self] (fn Session.shutdown-session [self]
(set self.queue []) (set self.queue [])
(set self.in-progress false) (set self.in-progress false)
(set self.sesion nil)) (set self.session nil))
(fn Session.cleanup-handlers [self] (fn Session.cleanup-handlers [self]
{:status/done #(self:done-msg) {:status/done #(self:done-msg)
@ -63,9 +63,11 @@
(fn Session.eval [self code ?handlers] (fn Session.eval [self code ?handlers]
(self:send {:op :eval : code} ?handlers)) (self:send {:op :eval : code} ?handlers))
(fn Session.input-handler [self input]
{:status/need-input #(self:send-oob {:op :stdin :stdin input})})
(fn Session.eval-input [self code input ?handlers] (fn Session.eval-input [self code input ?handlers]
(self:send {:op :eval : code} (self:send {:op :eval : code}
(lume.merge (or ?handlers {}) (lume.merge (or ?handlers {}) (self:input-handler input))))
{:status/need-input #(self:send-oob {:op :stdin :stdin input})})))
Session Session