(local json (require :json)) (local inspect (require :inspect)) (local l6502 (require :l6502-lua)) (fn slurp [path] (let [f (io.open path)] (f:read "*all"))) (fn contains? [x xs] (each [_ y (pairs xs)] (when (= x y) (lua "return true"))) nil) (fn must-match [st fnm a e] (if (= a e) true true (do (io.stderr:write (.. "\n -> in field " fnm ", expected " (tostring e) " but found " (tostring a))) ;; (io.stderr:write (.. "\n -> initial emulator state:\n" (inspect st.initial))) (io.stderr:write (.. "\n -> final emulator state:\n" (inspect st.final))) (io.stderr:write "\n") (os.exit 1)))) (fn u8-flag? [v f] (not (= (band v f) 0))) (local flag-masks { :carry l6502.flag.CARRY :zero l6502.flag.ZERO :interrupt_disable l6502.flag.INTERRUPT_DISABLE :decimal l6502.flag.DECIMAL :break_command l6502.flag.BREAK_COMMAND :overflow l6502.flag.OVERFLOW :negative l6502.flag.NEGATIVE }) (fn must-match-flag [st e nm f] (must-match st nm (e:flag (. flag-masks nm)) (u8-flag? f.p (. flag-masks nm)))) (fn summary-compare-testcase [e s t] (fn ae [actual expected] { : actual : expected }) { :pc (ae s.pc t.pc) :regs { :sp (ae s.regs.sp t.s) :a (ae s.regs.a t.a) :x (ae s.regs.x t.x) :y (ae s.regs.y t.y) :flags (ae s.regs.flags t.p) } :flags (collect [nm mask (pairs flag-masks)] (values nm (ae (. s.flags nm) (if (u8-flag? t.p mask) 1 0)))) :ram (collect [_ [addr v] (ipairs t.ram)] (values (.. :addr (tostring addr)) (ae (e:read addr) v))) }) (fn run-test [e tc] (io.stderr:write (.. "running test: " tc.name "...")) (let [i tc.initial] (e:set-pc i.pc) (e:set-reg l6502.reg.SP i.s) (e:set-reg l6502.reg.A i.a) (e:set-reg l6502.reg.X i.x) (e:set-reg l6502.reg.Y i.y) (e:set-reg l6502.reg.FLAGS i.p) (each [_ [addr v] (ipairs i.ram)] (e:write addr v))) (let [ initial-summary (e:summary) ins (e:emulate) st { :initial (summary-compare-testcase e initial-summary tc.initial) :final (summary-compare-testcase e (e:summary) tc.final) } f tc.final] (io.stderr:write (.. " " ins "...")) (must-match st :pc (e:pc) f.pc) (must-match st :sp (e:reg l6502.reg.SP) f.s) (must-match st :a (e:reg l6502.reg.A) f.a) (must-match st :x (e:reg l6502.reg.X) f.x) (must-match st :y (e:reg l6502.reg.Y) f.y) (must-match-flag st e :carry f) (must-match-flag st e :zero f) (must-match-flag st e :interrupt_disable f) (must-match-flag st e :decimal f) (must-match-flag st e :break_command f) (must-match-flag st e :overflow f) (must-match-flag st e :negative f) (each [_ [addr v] (ipairs f.ram)] (must-match st (.. :addr (tostring addr)) (e:read addr) v))) (io.stderr:write " done\n") ) (local villains [ 0x02 0x03 0x04 0x07 0x0b 0x0c 0x0f 0x12 0x13 0x14 0x17 0x1a 0x1b 0x1c 0x1f 0x22 0x23 0x27 0x2b 0x2f 0x32 0x33 0x34 0x37 0x3a 0x3b 0x3c 0x3f 0x42 0x43 0x44 0x47 0x4b 0x4f 0x52 0x53 0x54 0x57 0x5a 0x5b 0x5c 0x5f ;; 0x539 <3 0x62 0x63 0x64 0x67 0x6b 0x6f 0x72 0x73 0x74 0x77 0x7a 0x7b 0x7c 0x7f 0x80 0x82 0x83 0x87 0x89 0x8b 0x8f 0x92 0x93 0x97 0x9b 0x9c 0x9e 0x9f 0xa3 0xa7 0xab 0xaf 0xb2 0xb3 0xb7 0xbb 0xbf 0xc2 0xc3 0xc7 0xcb 0xcf 0xd2 0xd3 0xd4 0xd7 0xda 0xdb 0xdc 0xdf 0xe2 0xe3 0xe7 0xeb 0xef 0xf2 0xf3 0xf4 0xf7 0xfa 0xfb 0xfc 0xff ]) (fn run-tests-file [e p] (let [tcs (json.decode (slurp p))] (each [_ tc (ipairs tcs)] (when (not (u8-flag? tc.initial.p l6502.flag.DECIMAL)) (run-test e tc))))) (let [e (l6502.new)] (for [i 0x00 0xff] (when (not (contains? i villains)) (run-tests-file e (string.format "testcases/6502/v1/%02x.json" i)))))