nonogamer9

OC-ZX : A 48K ZX Spectrum Emulator for OpenComputers

Oct 8th, 2026
64
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 54.03 KB | Source Code | 0 0
  1. local component = require("component")
  2. local computer = require("computer")
  3. local shell = require("shell")
  4. local fs = require("filesystem")
  5.  
  6. local PUMP_INTERVAL = 0.15
  7. local RENDER_EVERY = 2
  8. local MASTER_VOLUME = 0.6
  9. local FRAME_TS = 69888
  10. local CPU_HZ = 3500000
  11. local CONTENTION = true
  12. local KEY_HOLD = 3
  13. local AUTOLOAD_FRAME = 150
  14.  
  15. local args = {...}
  16. local gpu = component.gpu
  17. local snd = component.isAvailable("sound") and component.sound or nil
  18.  
  19. local function readFile(path)
  20.   local p = shell.resolve(path)
  21.   local f = io.open(p, "rb")
  22.   if not f then return nil end
  23.   local d = f:read("*a")
  24.   f:close()
  25.   return d
  26. end
  27.  
  28. local function rd16(d, i)
  29.   return d:byte(i) | (d:byte(i + 1) << 8)
  30. end
  31.  
  32. local function rd24(d, i)
  33.   return d:byte(i) | (d:byte(i + 1) << 8) | (d:byte(i + 2) << 16)
  34. end
  35.  
  36. local function rd32(d, i)
  37.   return d:byte(i) | (d:byte(i + 1) << 8) |
  38.          (d:byte(i + 2) << 16) | (d:byte(i + 3) << 24)
  39. end
  40.  
  41. local romPath, snaPath, tapPath, z80Path, tzxPath, scrPath, binPath
  42.  
  43. for _, a in ipairs(args) do
  44.   local ext = a:lower():match("%.(%w+)$")
  45.   if ext == "rom" then
  46.     romPath = a
  47.   elseif ext == "bin" then
  48.     binPath = a
  49.   elseif ext == "sna" then
  50.     snaPath = a
  51.   elseif ext == "tap" then
  52.     tapPath = a
  53.   elseif ext == "z80" then
  54.     z80Path = a
  55.   elseif ext == "tzx" then
  56.     tzxPath = a
  57.   elseif ext == "scr" then
  58.     scrPath = a
  59.   else
  60.     io.stderr:write("zx: unknown file type: " .. a .. "\n")
  61.     return
  62.   end
  63. end
  64.  
  65. local romData
  66. do
  67.   local candidates = {
  68.     romPath,
  69.     "48.rom",
  70.     "/home/48.rom",
  71.     "/usr/share/zx/48.rom"
  72.   }
  73.  
  74.   for _, p in ipairs(candidates) do
  75.     if p and fs.exists(shell.resolve(p)) then
  76.       romData = readFile(p)
  77.       if romData then break end
  78.     end
  79.   end
  80. end
  81.  
  82. if not romData or #romData ~= 16384 then
  83.   io.stderr:write("zx: need the 16384-byte 48K ROM image (48.rom).\n")
  84.   io.stderr:write("usage: zx [48.rom] [game.sna|.z80|.tap|.tzx|.scr|.bin]\n")
  85.   return
  86. end
  87.  
  88. local snaData, tapBlocks, z80Data, tzxData, scrData, binData
  89.  
  90. if snaPath then
  91.   snaData = readFile(snaPath)
  92.   if not snaData then
  93.     io.stderr:write("zx: cannot read " .. snaPath .. "\n")
  94.     return
  95.   end
  96.   if #snaData ~= 49179 then
  97.     io.stderr:write("zx: only 48K .sna snapshots (49179 bytes) are supported\n")
  98.     return
  99.   end
  100. end
  101.  
  102. if z80Path then
  103.   z80Data = readFile(z80Path)
  104.   if not z80Data then
  105.     io.stderr:write("zx: cannot read " .. z80Path .. "\n")
  106.     return
  107.   end
  108.   if #z80Data < 30 then
  109.     io.stderr:write("zx: .z80 file too short\n")
  110.     return
  111.   end
  112. end
  113.  
  114. if tzxPath then
  115.   tzxData = readFile(tzxPath)
  116.   if not tzxData then
  117.     io.stderr:write("zx: cannot read " .. tzxPath .. "\n")
  118.     return
  119.   end
  120. end
  121.  
  122. if scrPath then
  123.   scrData = readFile(scrPath)
  124.   if not scrData or #scrData ~= 6912 then
  125.     io.stderr:write("zx: .scr must be exactly 6912 bytes\n")
  126.     return
  127.   end
  128. end
  129.  
  130. if binPath then
  131.   binData = readFile(binPath)
  132.   if not binData then
  133.     io.stderr:write("zx: cannot read " .. binPath .. "\n")
  134.     return
  135.   end
  136.   if #binData > 49152 then
  137.     io.stderr:write("zx: .bin larger than 48K\n")
  138.     return
  139.   end
  140. end
  141.  
  142. if tapPath then
  143.   local d = readFile(tapPath)
  144.   if not d then
  145.     io.stderr:write("zx: cannot read " .. tapPath .. "\n")
  146.     return
  147.   end
  148.  
  149.   tapBlocks = {}
  150.   local p = 1
  151.  
  152.   while p + 1 <= #d do
  153.     local len = d:byte(p) | (d:byte(p + 1) << 8)
  154.     if p + 1 + len > #d then break end
  155.     tapBlocks[#tapBlocks + 1] = d:sub(p + 2, p + 1 + len)
  156.     p = p + 2 + len
  157.   end
  158. end
  159.  
  160. local function loadTZX(d)
  161.   local blocks = {}
  162.   local p = 1
  163.   local n = #d
  164.  
  165.   if d:sub(1, 7) == "ZXTape!" then
  166.     p = 11
  167.   end
  168.  
  169.   while p <= n do
  170.     local id = d:byte(p)
  171.     p = p + 1
  172.  
  173.     if id == 0x10 then
  174.       local len = rd16(d, p + 2)
  175.       blocks[#blocks + 1] = d:sub(p + 4, p + 3 + len)
  176.       p = p + 4 + len
  177.  
  178.     elseif id == 0x11 then
  179.       local len = rd24(d, p + 15)
  180.       blocks[#blocks + 1] = d:sub(p + 18, p + 17 + len)
  181.       p = p + 18 + len
  182.  
  183.     elseif id == 0x12 then
  184.       p = p + 4
  185.  
  186.     elseif id == 0x13 then
  187.       p = p + 1 + d:byte(p) * 2
  188.  
  189.     elseif id == 0x14 then
  190.       p = p + 10 + rd24(d, p + 7)
  191.  
  192.     elseif id == 0x15 then
  193.       p = p + 8 + rd24(d, p + 5)
  194.  
  195.     elseif id == 0x18 or id == 0x19 then
  196.       p = p + 4 + rd32(d, p)
  197.  
  198.     elseif id == 0x20 or id == 0x23 or id == 0x24 then
  199.       p = p + 2
  200.  
  201.     elseif id == 0x21 or id == 0x30 then
  202.       p = p + 1 + d:byte(p)
  203.  
  204.     elseif id == 0x22 or id == 0x25 or id == 0x27 then
  205.  
  206.     elseif id == 0x26 then
  207.       p = p + 2 + rd16(d, p) * 2
  208.  
  209.     elseif id == 0x28 or id == 0x32 then
  210.       p = p + 2 + rd16(d, p)
  211.  
  212.     elseif id == 0x2A then
  213.       p = p + 4
  214.  
  215.     elseif id == 0x2B then
  216.       p = p + 5
  217.  
  218.     elseif id == 0x31 then
  219.       p = p + 2 + d:byte(p + 1)
  220.  
  221.     elseif id == 0x33 then
  222.       p = p + 1 + d:byte(p) * 3
  223.  
  224.     elseif id == 0x34 then
  225.       p = p + 8
  226.  
  227.     elseif id == 0x35 then
  228.       p = p + 20 + rd32(d, p + 16)
  229.  
  230.     elseif id == 0x40 then
  231.       p = p + 4 + rd24(d, p + 1)
  232.  
  233.     elseif id == 0x5A then
  234.       p = p + 9
  235.  
  236.     else
  237.       break
  238.     end
  239.   end
  240.  
  241.   return blocks
  242. end
  243.  
  244. if tzxData then
  245.   tapBlocks = loadTZX(tzxData)
  246. end
  247.  
  248. local tapePos = 1
  249.  
  250. local M = {}
  251. for i = 0, 65535 do M[i] = 0 end
  252. for i = 0, 16383 do M[i] = romData:byte(i + 1) end
  253.  
  254. local dirty = {}
  255. local anyDirty = true
  256.  
  257. local ox, oy = 0, 0
  258. local border = 7
  259. local borderDirty = true
  260. local flashOn = false
  261.  
  262. local ts = 0
  263. local frameStart = 0
  264.  
  265. local function markScreenByte(a)
  266.   if a < 0x4000 or a > 0x5AFF then return end
  267.  
  268.   if a < 0x5800 then
  269.     local y = ((a >> 5) & 0xC0) | ((a >> 2) & 0x38) | ((a >> 8) & 7)
  270.     dirty[(y >> 2) * 32 + (a & 31)] = true
  271.   else
  272.     local n = a - 0x5800
  273.     local k = (n >> 5) * 64 + (n & 31)
  274.     dirty[k] = true
  275.     dirty[k + 32] = true
  276.   end
  277.  
  278.   anyDirty = true
  279. end
  280.  
  281. local CT = {[0]=6, 5, 4, 3, 2, 1, 0, 0}
  282.  
  283. local function wr(a, v)
  284.   a = a & 0xFFFF
  285.   v = v & 255
  286.  
  287.   if a >= 0x4000 then
  288.     if CONTENTION and a < 0x8000 then
  289.       local t = ts - frameStart - 14335
  290.       if t >= 0 and t < 43008 then
  291.         local c = t % 224
  292.         if c < 128 then
  293.           ts = ts + CT[c & 7]
  294.         end
  295.       end
  296.     end
  297.  
  298.     if M[a] ~= v then
  299.       M[a] = v
  300.       markScreenByte(a)
  301.     end
  302.   end
  303. end
  304.  
  305. local R = {[0]=0,0,0,0,0,0,0,0}
  306. local S = {[0]=0,0,0,0,0,0,0,0}
  307.  
  308. local F, F2 = 0, 0
  309. local PC, SP, IX, IY = 0, 0, 0, 0
  310. local I = 0
  311. local RR = 0
  312. local IFF1, IFF2 = false, false
  313. local IM = 0
  314. local halted = false
  315. local eiDelay = 0
  316.  
  317. local prefixed = false
  318. local sh, sl = 0, 0
  319.  
  320. local function incR()
  321.   RR = (RR & 0x80) | ((RR + 1) & 0x7F)
  322. end
  323.  
  324. local function fetch()
  325.   local v = M[PC]
  326.   PC = (PC + 1) & 0xFFFF
  327.   return v
  328. end
  329.  
  330. local function fetchOp()
  331.   local v = M[PC]
  332.   PC = (PC + 1) & 0xFFFF
  333.   RR = (RR & 0x80) | ((RR + 1) & 0x7F)
  334.   return v
  335. end
  336.  
  337. local function fetch16()
  338.   local lo = fetch()
  339.   local hi = fetch()
  340.   return lo | (hi << 8)
  341. end
  342.  
  343. local function push(v)
  344.   SP = (SP - 2) & 0xFFFF
  345.   wr(SP, v & 255)
  346.   wr((SP + 1) & 0xFFFF, (v >> 8) & 255)
  347. end
  348.  
  349. local function pop()
  350.   local lo = M[SP]
  351.   local hi = M[(SP + 1) & 0xFFFF]
  352.   SP = (SP + 2) & 0xFFFF
  353.   return lo | (hi << 8)
  354. end
  355.  
  356. local function getrp(p)
  357.   if p == 0 then
  358.     return (R[0] << 8) | R[1]
  359.   elseif p == 1 then
  360.     return (R[2] << 8) | R[3]
  361.   elseif p == 2 then
  362.     return (R[4] << 8) | R[5]
  363.   else
  364.     return SP
  365.   end
  366. end
  367.  
  368. local function setrp(p, v)
  369.   v = v & 0xFFFF
  370.   if p == 0 then
  371.     R[0], R[1] = v >> 8, v & 255
  372.   elseif p == 1 then
  373.     R[2], R[3] = v >> 8, v & 255
  374.   elseif p == 2 then
  375.     R[4], R[5] = v >> 8, v & 255
  376.   else
  377.     SP = v
  378.   end
  379. end
  380.  
  381. local SZ53, SZ53P = {}, {}
  382.  
  383. for i = 0, 255 do
  384.   local v = i
  385.   v = v ~ (v >> 4)
  386.   v = v ~ (v >> 2)
  387.   v = v ~ (v >> 1)
  388.  
  389.   local b = (i & 0xA8) | ((i == 0) and 0x40 or 0)
  390.   SZ53[i] = b
  391.   SZ53P[i] = b | (((v & 1) == 0) and 4 or 0)
  392. end
  393.  
  394. local CM = {[0]=0x40,0x01,0x04,0x80}
  395.  
  396. local function cc(y)
  397.   local set = (F & CM[y >> 1]) ~= 0
  398.   if (y & 1) == 0 then
  399.     return not set
  400.   end
  401.   return set
  402. end
  403.  
  404. local function alu(op, v)
  405.   local a = R[7]
  406.  
  407.   if op == 0 or op == 1 then
  408.     local r = a + v + ((op == 1) and (F & 1) or 0)
  409.     local res = r & 255
  410.  
  411.     F = SZ53[res]
  412.       | ((r >> 8) & 1)
  413.       | ((a ~ v ~ res) & 0x10)
  414.       | (((~(a ~ v)) & (a ~ res) & 0x80) >> 5)
  415.  
  416.     R[7] = res
  417.  
  418.   elseif op == 2 or op == 3 or op == 7 then
  419.     local r = a - v - ((op == 3) and (F & 1) or 0)
  420.     local res = r & 255
  421.  
  422.     local fl = ((r >> 8) & 1)
  423.       | 2
  424.       | ((a ~ v ~ res) & 0x10)
  425.       | (((a ~ v) & (a ~ res) & 0x80) >> 5)
  426.  
  427.     if op == 7 then
  428.       F = (SZ53[res] & 0xC0)
  429.         | (v & 0x28)
  430.         | (fl & 0x17)
  431.     else
  432.       F = SZ53[res] | fl
  433.       R[7] = res
  434.     end
  435.  
  436.   elseif op == 4 then
  437.     local res = a & v
  438.     F = SZ53P[res] | 0x10
  439.     R[7] = res
  440.  
  441.   elseif op == 5 then
  442.     local res = a ~ v
  443.     F = SZ53P[res]
  444.     R[7] = res
  445.  
  446.   else
  447.     local res = a | v
  448.     F = SZ53P[res]
  449.     R[7] = res
  450.   end
  451. end
  452.  
  453. local function inc8(v)
  454.   local res = (v + 1) & 255
  455.   F = (F & 1)
  456.     | SZ53[res]
  457.     | (((v & 15) == 15) and 0x10 or 0)
  458.     | ((v == 0x7F) and 4 or 0)
  459.   return res
  460. end
  461.  
  462. local function dec8(v)
  463.   local res = (v - 1) & 255
  464.   F = (F & 1)
  465.     | SZ53[res]
  466.     | 2
  467.     | (((v & 15) == 0) and 0x10 or 0)
  468.     | ((v == 0x80) and 4 or 0)
  469.   return res
  470. end
  471.  
  472. local function rot(op, v)
  473.   local c, r
  474.  
  475.   if op == 0 then
  476.     c = v >> 7
  477.     r = ((v << 1) | c) & 255
  478.   elseif op == 1 then
  479.     c = v & 1
  480.     r = (v >> 1) | (c << 7)
  481.   elseif op == 2 then
  482.     c = v >> 7
  483.     r = ((v << 1) | (F & 1)) & 255
  484.   elseif op == 3 then
  485.     c = v & 1
  486.     r = (v >> 1) | ((F & 1) << 7)
  487.   elseif op == 4 then
  488.     c = v >> 7
  489.     r = (v << 1) & 255
  490.   elseif op == 5 then
  491.     c = v & 1
  492.     r = (v >> 1) | (v & 0x80)
  493.   elseif op == 6 then
  494.     c = v >> 7
  495.     r = ((v << 1) | 1) & 255
  496.   else
  497.     c = v & 1
  498.     r = v >> 1
  499.   end
  500.  
  501.   F = SZ53P[r] | c
  502.   return r
  503. end
  504.  
  505. local function ea()
  506.   if prefixed then
  507.     local d = fetch()
  508.     if d >= 128 then d = d - 256 end
  509.  
  510.     local base = (R[4] << 8) | R[5]
  511.     return (base + d) & 0xFFFF
  512.   end
  513.  
  514.   return (R[4] << 8) | R[5]
  515. end
  516.  
  517. local spk = 0
  518. local tgN = 0
  519. local tgT = {}
  520. local tgL = {}
  521.  
  522. local kb = {}
  523. local kcount = {}
  524.  
  525. for r = 0, 7 do
  526.   kb[r] = 0x1F
  527. end
  528.  
  529. local function portIn(p)
  530.   if (p & 1) == 0 then
  531.     local k = 0x1F
  532.     local hi = (p >> 8) & 255
  533.  
  534.     for r = 0, 7 do
  535.       if (hi & (1 << r)) == 0 then
  536.         k = k & kb[r]
  537.       end
  538.     end
  539.  
  540.     return 0xA0 | k
  541.   end
  542.  
  543.   if (p & 0xFF) == 0x1F then
  544.     return 0
  545.   end
  546.  
  547.   return 0xFF
  548. end
  549.  
  550. local function portOut(p, v)
  551.   if (p & 1) == 0 then
  552.     local b = v & 7
  553.  
  554.     if b ~= border then
  555.       border = b
  556.       borderDirty = true
  557.     end
  558.  
  559.     local s = (v >> 4) & 1
  560.     if s ~= spk then
  561.       spk = s
  562.       if snd and tgN < 4096 then
  563.         tgN = tgN + 1
  564.         tgT[tgN] = ts
  565.         tgL[tgN] = s
  566.       end
  567.     end
  568.   end
  569. end
  570.  
  571. local function exec(op)
  572.   local x = op >> 6
  573.  
  574.   if x == 1 then
  575.     local y = (op >> 3) & 7
  576.     local z = op & 7
  577.  
  578.     if z == 6 then
  579.       if y == 6 then
  580.         halted = true
  581.         return 4
  582.       end
  583.  
  584.       local a = ea()
  585.       local v = M[a]
  586.  
  587.       if prefixed and (y == 4 or y == 5) then
  588.         if y == 4 then sh = v else sl = v end
  589.       else
  590.         R[y] = v
  591.       end
  592.  
  593.       return prefixed and 19 or 7
  594.  
  595.     elseif y == 6 then
  596.       local a = ea()
  597.       local v
  598.  
  599.       if prefixed and (z == 4 or z == 5) then
  600.         v = (z == 4) and sh or sl
  601.       else
  602.         v = R[z]
  603.       end
  604.  
  605.       wr(a, v)
  606.       return prefixed and 19 or 7
  607.  
  608.     else
  609.       R[y] = R[z]
  610.       return 4
  611.     end
  612.  
  613.   elseif x == 2 then
  614.     local y = (op >> 3) & 7
  615.     local z = op & 7
  616.  
  617.     if z == 6 then
  618.       alu(y, M[ea()])
  619.       return prefixed and 19 or 7
  620.     end
  621.  
  622.     alu(y, R[z])
  623.     return 4
  624.  
  625.   elseif x == 0 then
  626.     local y = (op >> 3) & 7
  627.     local z = op & 7
  628.  
  629.     if z == 0 then
  630.       if y == 0 then
  631.         return 4
  632.  
  633.       elseif y == 1 then
  634.         R[7], S[7] = S[7], R[7]
  635.         F, F2 = F2, F
  636.         return 4
  637.  
  638.       elseif y == 2 then
  639.         local d = fetch()
  640.         local b = (R[0] - 1) & 255
  641.         R[0] = b
  642.  
  643.         if b ~= 0 then
  644.           PC = (PC + (d >= 128 and d - 256 or d)) & 0xFFFF
  645.           return 13
  646.         end
  647.  
  648.         return 8
  649.  
  650.       elseif y == 3 then
  651.         local d = fetch()
  652.         PC = (PC + (d >= 128 and d - 256 or d)) & 0xFFFF
  653.         return 12
  654.  
  655.       else
  656.         local d = fetch()
  657.         if cc(y - 4) then
  658.           PC = (PC + (d >= 128 and d - 256 or d)) & 0xFFFF
  659.           return 12
  660.         end
  661.         return 7
  662.       end
  663.  
  664.     elseif z == 1 then
  665.       local p = y >> 1
  666.  
  667.       if (y & 1) == 0 then
  668.         setrp(p, fetch16())
  669.         return prefixed and 14 or 10
  670.       end
  671.  
  672.       local hl = (R[4] << 8) | R[5]
  673.       local rr = getrp(p)
  674.       local r = hl + rr
  675.  
  676.       F = (F & 0xC4)
  677.         | ((r >> 8) & 0x28)
  678.         | (((hl ~ rr ~ r) >> 8) & 0x10)
  679.         | ((r >> 16) & 1)
  680.  
  681.       r = r & 0xFFFF
  682.       R[4], R[5] = r >> 8, r & 255
  683.       return prefixed and 15 or 11
  684.  
  685.     elseif z == 2 then
  686.       local p = y >> 1
  687.  
  688.       if (y & 1) == 0 then
  689.         if p == 0 then
  690.           wr((R[0] << 8) | R[1], R[7])
  691.           return 7
  692.  
  693.         elseif p == 1 then
  694.           wr((R[2] << 8) | R[3], R[7])
  695.           return 7
  696.  
  697.         elseif p == 2 then
  698.           local a = fetch16()
  699.           wr(a, R[5])
  700.           wr((a + 1) & 0xFFFF, R[4])
  701.           return 16
  702.  
  703.         else
  704.           wr(fetch16(), R[7])
  705.           return 13
  706.         end
  707.  
  708.       else
  709.         if p == 0 then
  710.           R[7] = M[(R[0] << 8) | R[1]]
  711.           return 7
  712.  
  713.         elseif p == 1 then
  714.           R[7] = M[(R[2] << 8) | R[3]]
  715.           return 7
  716.  
  717.         elseif p == 2 then
  718.           local a = fetch16()
  719.           R[5] = M[a]
  720.           R[4] = M[(a + 1) & 0xFFFF]
  721.           return 16
  722.  
  723.         else
  724.           R[7] = M[fetch16()]
  725.           return 13
  726.         end
  727.       end
  728.  
  729.     elseif z == 3 then
  730.       local p = y >> 1
  731.       local v = getrp(p)
  732.  
  733.       if (y & 1) == 0 then
  734.         setrp(p, (v + 1) & 0xFFFF)
  735.       else
  736.         setrp(p, (v - 1) & 0xFFFF)
  737.       end
  738.  
  739.       return prefixed and 10 or 6
  740.  
  741.     elseif z == 4 then
  742.       if y == 6 then
  743.         local a = ea()
  744.         wr(a, inc8(M[a]))
  745.         return prefixed and 23 or 11
  746.       end
  747.  
  748.       R[y] = inc8(R[y])
  749.       return 4
  750.  
  751.     elseif z == 5 then
  752.       if y == 6 then
  753.         local a = ea()
  754.         wr(a, dec8(M[a]))
  755.         return prefixed and 23 or 11
  756.       end
  757.  
  758.       R[y] = dec8(R[y])
  759.       return 4
  760.  
  761.     elseif z == 6 then
  762.       if y == 6 then
  763.         local a = ea()
  764.         wr(a, fetch())
  765.         return prefixed and 19 or 10
  766.       end
  767.  
  768.       R[y] = fetch()
  769.       return 7
  770.  
  771.     else
  772.       local a = R[7]
  773.  
  774.       if y == 0 then
  775.         local c = a >> 7
  776.         a = ((a << 1) | c) & 255
  777.         R[7] = a
  778.         F = (F & 0xC4) | (a & 0x28) | c
  779.  
  780.       elseif y == 1 then
  781.         local c = a & 1
  782.         a = (a >> 1) | (c << 7)
  783.         R[7] = a
  784.         F = (F & 0xC4) | (a & 0x28) | c
  785.  
  786.       elseif y == 2 then
  787.         local c = a >> 7
  788.         a = ((a << 1) | (F & 1)) & 255
  789.         R[7] = a
  790.         F = (F & 0xC4) | (a & 0x28) | c
  791.  
  792.       elseif y == 3 then
  793.         local c = a & 1
  794.         a = (a >> 1) | ((F & 1) << 7)
  795.         R[7] = a
  796.         F = (F & 0xC4) | (a & 0x28) | c
  797.  
  798.       elseif y == 4 then
  799.         local f = F
  800.         local corr = 0
  801.         local c = f & 1
  802.  
  803.         if (f & 0x10) ~= 0 or (a & 15) > 9 then
  804.           corr = 6
  805.         end
  806.  
  807.         if c ~= 0 or a > 0x99 then
  808.           corr = corr | 0x60
  809.           c = 1
  810.         else
  811.           c = 0
  812.         end
  813.  
  814.         local na
  815.         local h
  816.  
  817.         if (f & 2) ~= 0 then
  818.           na = (a - corr) & 255
  819.           h = (((f & 0x10) ~= 0) and (a & 15) < 6) and 0x10 or 0
  820.         else
  821.           na = (a + corr) & 255
  822.           h = ((a & 15) > 9) and 0x10 or 0
  823.         end
  824.  
  825.         R[7] = na
  826.         F = SZ53P[na] | (f & 2) | c | h
  827.  
  828.       elseif y == 5 then
  829.         a = a ~ 255
  830.         R[7] = a
  831.         F = (F & 0xC5) | 0x12 | (a & 0x28)
  832.  
  833.       elseif y == 6 then
  834.         F = (F & 0xC4) | 1 | (a & 0x28)
  835.  
  836.       else
  837.         local c = F & 1
  838.         F = (F & 0xC4) | (c << 4) | (a & 0x28) | (1 - c)
  839.       end
  840.  
  841.       return 4
  842.     end
  843.  
  844.   else
  845.     local y = (op >> 3) & 7
  846.     local z = op & 7
  847.  
  848.     if z == 0 then
  849.       if cc(y) then
  850.         PC = pop()
  851.         return 11
  852.       end
  853.       return 5
  854.  
  855.     elseif z == 1 then
  856.       local p = y >> 1
  857.  
  858.       if (y & 1) == 0 then
  859.         local v = pop()
  860.  
  861.         if p == 3 then
  862.           R[7] = v >> 8
  863.           F = v & 255
  864.         else
  865.           setrp(p, v)
  866.         end
  867.  
  868.         return 10
  869.       end
  870.  
  871.       if p == 0 then
  872.         PC = pop()
  873.         return 10
  874.  
  875.       elseif p == 1 then
  876.         for i = 0, 5 do
  877.           R[i], S[i] = S[i], R[i]
  878.         end
  879.         return 4
  880.  
  881.       elseif p == 2 then
  882.         PC = (R[4] << 8) | R[5]
  883.         return prefixed and 8 or 4
  884.       end
  885.  
  886.       SP = (R[4] << 8) | R[5]
  887.       return prefixed and 10 or 6
  888.  
  889.     elseif z == 2 then
  890.       local nn = fetch16()
  891.       if cc(y) then PC = nn end
  892.       return 10
  893.  
  894.     elseif z == 3 then
  895.       if y == 0 then
  896.         PC = fetch16()
  897.         return 10
  898.  
  899.       elseif y == 2 then
  900.         local n = fetch()
  901.         portOut((R[7] << 8) | n, R[7])
  902.         return 11
  903.  
  904.       elseif y == 3 then
  905.         local n = fetch()
  906.         R[7] = portIn((R[7] << 8) | n)
  907.         return 11
  908.  
  909.       elseif y == 4 then
  910.         local lo = M[SP]
  911.         local hi = M[(SP + 1) & 0xFFFF]
  912.  
  913.         wr(SP, R[5])
  914.         wr((SP + 1) & 0xFFFF, R[4])
  915.  
  916.         R[5], R[4] = lo, hi
  917.         return prefixed and 23 or 19
  918.  
  919.       elseif y == 5 then
  920.         R[2], R[4] = R[4], R[2]
  921.         R[3], R[5] = R[5], R[3]
  922.         return 4
  923.  
  924.       elseif y == 6 then
  925.         IFF1 = false
  926.         IFF2 = false
  927.         return 4
  928.  
  929.       else
  930.         IFF1 = true
  931.         IFF2 = true
  932.         eiDelay = 2
  933.         return 4
  934.       end
  935.  
  936.     elseif z == 4 then
  937.       local nn = fetch16()
  938.       if cc(y) then
  939.         push(PC)
  940.         PC = nn
  941.         return 17
  942.       end
  943.       return 10
  944.  
  945.     elseif z == 5 then
  946.       if (y & 1) == 0 then
  947.         local p = y >> 1
  948.         local v
  949.  
  950.         if p == 3 then
  951.           v = (R[7] << 8) | F
  952.         else
  953.           v = getrp(p)
  954.         end
  955.  
  956.         push(v)
  957.         return 11
  958.       end
  959.  
  960.       local nn = fetch16()
  961.       push(PC)
  962.       PC = nn
  963.       return 17
  964.  
  965.     elseif z == 6 then
  966.       alu(y, fetch())
  967.       return 7
  968.  
  969.     else
  970.       push(PC)
  971.       PC = y << 3
  972.       return 11
  973.     end
  974.   end
  975. end
  976.  
  977. local function cbop()
  978.   local op = fetchOp()
  979.  
  980.   local x = op >> 6
  981.   local y = (op >> 3) & 7
  982.   local z = op & 7
  983.  
  984.   local a, v
  985.  
  986.   if z == 6 then
  987.     a = (R[4] << 8) | R[5]
  988.     v = M[a]
  989.   else
  990.     v = R[z]
  991.   end
  992.  
  993.   if x == 0 then
  994.     v = rot(y, v)
  995.  
  996.   elseif x == 1 then
  997.     local m = v & (1 << y)
  998.     F = (F & 1)
  999.       | 0x10
  1000.       | (v & 0x28)
  1001.       | ((m == 0) and 0x44 or (m & 0x80))
  1002.  
  1003.     return (z == 6) and 12 or 8
  1004.  
  1005.   elseif x == 2 then
  1006.     v = v & ~(1 << y)
  1007.  
  1008.   else
  1009.     v = v | (1 << y)
  1010.   end
  1011.  
  1012.   if z == 6 then
  1013.     wr(a, v)
  1014.     return 15
  1015.   end
  1016.  
  1017.   R[z] = v
  1018.   return 8
  1019. end
  1020.  
  1021. local function edop()
  1022.   local op = fetchOp()
  1023.  
  1024.   local x = op >> 6
  1025.   local y = (op >> 3) & 7
  1026.   local z = op & 7
  1027.  
  1028.   if x == 1 then
  1029.     local p = y >> 1
  1030.  
  1031.     if z == 0 then
  1032.       local v = portIn((R[0] << 8) | R[1])
  1033.  
  1034.       F = (F & 1) | SZ53P[v]
  1035.  
  1036.       if y ~= 6 then
  1037.         R[y] = v
  1038.       end
  1039.  
  1040.       return 12
  1041.  
  1042.     elseif z == 1 then
  1043.       portOut(
  1044.         (R[0] << 8) | R[1],
  1045.         (y == 6) and 0 or R[y]
  1046.       )
  1047.       return 12
  1048.  
  1049.     elseif z == 2 then
  1050.       local hl = (R[4] << 8) | R[5]
  1051.       local rr = getrp(p)
  1052.       local c = F & 1
  1053.  
  1054.       local r, res
  1055.  
  1056.       if (y & 1) == 0 then
  1057.         r = hl - rr - c
  1058.         res = r & 0xFFFF
  1059.  
  1060.         F = ((res >> 8) & 0xA8)
  1061.           | ((res == 0) and 0x40 or 0)
  1062.           | (((hl ~ rr ~ res) >> 8) & 0x10)
  1063.           | (((hl ~ rr) & (hl ~ res) & 0x8000) >> 13)
  1064.           | 2
  1065.           | ((r >> 16) & 1)
  1066.       else
  1067.         r = hl + rr + c
  1068.         res = r & 0xFFFF
  1069.  
  1070.         F = ((res >> 8) & 0xA8)
  1071.           | ((res == 0) and 0x40 or 0)
  1072.           | (((hl ~ rr ~ res) >> 8) & 0x10)
  1073.           | (((~(hl ~ rr)) & (hl ~ res) & 0x8000) >> 13)
  1074.           | ((r >> 16) & 1)
  1075.       end
  1076.  
  1077.       R[4], R[5] = res >> 8, res & 255
  1078.       return 15
  1079.  
  1080.     elseif z == 3 then
  1081.       local nn = fetch16()
  1082.  
  1083.       if (y & 1) == 0 then
  1084.         local v = getrp(p)
  1085.         wr(nn, v & 255)
  1086.         wr((nn + 1) & 0xFFFF, v >> 8)
  1087.       else
  1088.         setrp(
  1089.           p,
  1090.           M[nn] | (M[(nn + 1) & 0xFFFF] << 8)
  1091.         )
  1092.       end
  1093.  
  1094.       return 20
  1095.  
  1096.     elseif z == 4 then
  1097.       local v = R[7]
  1098.       local res = (-v) & 255
  1099.  
  1100.       F = SZ53[res]
  1101.         | 2
  1102.         | ((v ~ res) & 0x10)
  1103.         | ((v == 0x80) and 4 or 0)
  1104.         | ((v ~= 0) and 1 or 0)
  1105.  
  1106.       R[7] = res
  1107.       return 8
  1108.  
  1109.     elseif z == 5 then
  1110.       PC = pop()
  1111.       IFF1 = IFF2
  1112.       eiDelay = 0
  1113.       return 14
  1114.  
  1115.     elseif z == 6 then
  1116.       if y == 0 or y == 1 or y == 4 or y == 5 then
  1117.         IM = 0
  1118.       elseif y == 2 or y == 6 then
  1119.         IM = 1
  1120.       else
  1121.         IM = 2
  1122.       end
  1123.       return 8
  1124.  
  1125.     else
  1126.       if y == 0 then
  1127.         I = R[7]
  1128.         return 9
  1129.  
  1130.       elseif y == 1 then
  1131.         RR = R[7]
  1132.         return 9
  1133.  
  1134.       elseif y == 2 then
  1135.         R[7] = I
  1136.         F = (F & 1) | SZ53[I] | (IFF2 and 4 or 0)
  1137.         return 9
  1138.  
  1139.       elseif y == 3 then
  1140.         R[7] = RR
  1141.         F = (F & 1) | SZ53[RR] | (IFF2 and 4 or 0)
  1142.         return 9
  1143.  
  1144.       elseif y == 4 then
  1145.         local hl = (R[4] << 8) | R[5]
  1146.         local m = M[hl]
  1147.         local a = R[7]
  1148.  
  1149.         wr(hl, ((a & 15) << 4) | (m >> 4))
  1150.         a = (a & 0xF0) | (m & 15)
  1151.  
  1152.         R[7] = a
  1153.         F = (F & 1) | SZ53P[a]
  1154.         return 18
  1155.  
  1156.       elseif y == 5 then
  1157.         local hl = (R[4] << 8) | R[5]
  1158.         local m = M[hl]
  1159.         local a = R[7]
  1160.  
  1161.         wr(hl, ((m << 4) & 0xF0) | (a & 15))
  1162.         a = (a & 0xF0) | (m >> 4)
  1163.  
  1164.         R[7] = a
  1165.         F = (F & 1) | SZ53P[a]
  1166.         return 18
  1167.       end
  1168.  
  1169.       return 8
  1170.     end
  1171.  
  1172.   elseif x == 2 and y >= 4 and z <= 3 then
  1173.     local dec = (y & 1) == 1
  1174.     local rep = y >= 6
  1175.     local d = dec and -1 or 1
  1176.  
  1177.     local hl = (R[4] << 8) | R[5]
  1178.  
  1179.     if z == 0 then
  1180.       local de = (R[2] << 8) | R[3]
  1181.       local bc = (((R[0] << 8) | R[1]) - 1) & 0xFFFF
  1182.       local v = M[hl]
  1183.  
  1184.       wr(de, v)
  1185.  
  1186.       hl = (hl + d) & 0xFFFF
  1187.       de = (de + d) & 0xFFFF
  1188.  
  1189.       R[4], R[5] = hl >> 8, hl & 255
  1190.       R[2], R[3] = de >> 8, de & 255
  1191.       R[0], R[1] = bc >> 8, bc & 255
  1192.  
  1193.       local n = v + R[7]
  1194.  
  1195.       F = (F & 0xC1)
  1196.         | ((bc ~= 0) and 4 or 0)
  1197.         | (n & 8)
  1198.         | ((n & 2) << 4)
  1199.  
  1200.       if rep and bc ~= 0 then
  1201.         PC = (PC - 2) & 0xFFFF
  1202.         return 21
  1203.       end
  1204.  
  1205.       return 16
  1206.  
  1207.     elseif z == 1 then
  1208.       local bc = (((R[0] << 8) | R[1]) - 1) & 0xFFFF
  1209.       local v = M[hl]
  1210.  
  1211.       local res = (R[7] - v) & 255
  1212.       local hf = (R[7] ~ v ~ res) & 0x10
  1213.       local n = res - (hf >> 4)
  1214.  
  1215.       hl = (hl + d) & 0xFFFF
  1216.  
  1217.       R[4], R[5] = hl >> 8, hl & 255
  1218.       R[0], R[1] = bc >> 8, bc & 255
  1219.  
  1220.       F = (F & 1)
  1221.         | 2
  1222.         | (res & 0x80)
  1223.         | ((res == 0) and 0x40 or 0)
  1224.         | hf
  1225.         | ((bc ~= 0) and 4 or 0)
  1226.         | (n & 8)
  1227.         | ((n & 2) << 4)
  1228.  
  1229.       if rep and bc ~= 0 and res ~= 0 then
  1230.         PC = (PC - 2) & 0xFFFF
  1231.         return 21
  1232.       end
  1233.  
  1234.       return 16
  1235.  
  1236.     elseif z == 2 then
  1237.       local v = portIn((R[0] << 8) | R[1])
  1238.  
  1239.       wr(hl, v)
  1240.  
  1241.       R[0] = (R[0] - 1) & 255
  1242.       hl = (hl + d) & 0xFFFF
  1243.  
  1244.       R[4], R[5] = hl >> 8, hl & 255
  1245.       F = SZ53[R[0]] | 2
  1246.  
  1247.       if rep and R[0] ~= 0 then
  1248.         PC = (PC - 2) & 0xFFFF
  1249.         return 21
  1250.       end
  1251.  
  1252.       return 16
  1253.  
  1254.     else
  1255.       local v = M[hl]
  1256.  
  1257.       R[0] = (R[0] - 1) & 255
  1258.       portOut((R[0] << 8) | R[1], v)
  1259.  
  1260.       hl = (hl + d) & 0xFFFF
  1261.       R[4], R[5] = hl >> 8, hl & 255
  1262.  
  1263.       F = SZ53[R[0]] | 2
  1264.  
  1265.       if rep and R[0] ~= 0 then
  1266.         PC = (PC - 2) & 0xFFFF
  1267.         return 21
  1268.       end
  1269.  
  1270.       return 16
  1271.     end
  1272.   end
  1273.  
  1274.   return 8
  1275. end
  1276.  
  1277. local function indexedCB(ireg)
  1278.   local d = fetch()
  1279.   if d >= 128 then d = d - 256 end
  1280.  
  1281.   local op = fetch()
  1282.   local a = (ireg + d) & 0xFFFF
  1283.  
  1284.   local x = op >> 6
  1285.   local y = (op >> 3) & 7
  1286.   local z = op & 7
  1287.  
  1288.   local v = M[a]
  1289.  
  1290.   if x == 0 then
  1291.     v = rot(y, v)
  1292.  
  1293.   elseif x == 1 then
  1294.     local m = v & (1 << y)
  1295.  
  1296.     F = (F & 1)
  1297.       | 0x10
  1298.       | ((a >> 8) & 0x28)
  1299.       | ((m == 0) and 0x44 or (m & 0x80))
  1300.  
  1301.     return 20
  1302.  
  1303.   elseif x == 2 then
  1304.     v = v & ~(1 << y)
  1305.  
  1306.   else
  1307.     v = v | (1 << y)
  1308.   end
  1309.  
  1310.   wr(a, v)
  1311.  
  1312.   if z ~= 6 then
  1313.     R[z] = v
  1314.   end
  1315.  
  1316.   return 23
  1317. end
  1318.  
  1319. local function prefTotal(ins)
  1320.   local x = ins >> 6
  1321.   local y = (ins >> 3) & 7
  1322.   local z = ins & 7
  1323.  
  1324.   if x == 1 then
  1325.     return z == 6 or y == 6
  1326.   elseif x == 2 then
  1327.     return z == 6
  1328.   elseif x == 0 then
  1329.     if z == 1 or z == 3 then return true end
  1330.     return y == 6 and (z == 4 or z == 5 or z == 6)
  1331.   else
  1332.     if z == 1 then return y == 5 or y == 7 end
  1333.     if z == 3 then return y == 4 end
  1334.   end
  1335.  
  1336.   return false
  1337. end
  1338.  
  1339. local function prefix(op)
  1340.   local isIX = (op == 0xDD)
  1341.   local extra = 0
  1342.  
  1343.   while true do
  1344.     local n = M[PC]
  1345.  
  1346.     if n == 0xDD then
  1347.       fetchOp()
  1348.       isIX = true
  1349.       extra = extra + 4
  1350.     elseif n == 0xFD then
  1351.       fetchOp()
  1352.       isIX = false
  1353.       extra = extra + 4
  1354.     else
  1355.       break
  1356.     end
  1357.   end
  1358.  
  1359.   local ireg = isIX and IX or IY
  1360.   local nxt = M[PC]
  1361.  
  1362.   if nxt == 0xCB then
  1363.     fetchOp()
  1364.     return indexedCB(ireg) + extra
  1365.   end
  1366.  
  1367.   if nxt == 0xED then
  1368.     fetchOp()
  1369.     return edop() + 4 + extra
  1370.   end
  1371.  
  1372.   if nxt == 0xEB then
  1373.     fetchOp()
  1374.     R[2], R[4] = R[4], R[2]
  1375.     R[3], R[5] = R[5], R[3]
  1376.     return 8 + extra
  1377.   end
  1378.  
  1379.   if nxt == 0xD9 then
  1380.     fetchOp()
  1381.     for i = 0, 5 do
  1382.       R[i], S[i] = S[i], R[i]
  1383.     end
  1384.     return 8 + extra
  1385.   end
  1386.  
  1387.   local ignored =
  1388.       nxt == 0x00 or nxt == 0x08 or nxt == 0x10 or nxt == 0x18
  1389.    or nxt == 0x20 or nxt == 0x28 or nxt == 0x30 or nxt == 0x38
  1390.    or nxt == 0x76
  1391.    or nxt == 0xC3 or nxt == 0xC9
  1392.    or nxt == 0xCD
  1393.    or nxt == 0xC0 or nxt == 0xC8 or nxt == 0xD0 or nxt == 0xD8
  1394.    or nxt == 0xE0 or nxt == 0xE8 or nxt == 0xF0 or nxt == 0xF8
  1395.    or nxt == 0xC7 or nxt == 0xCF or nxt == 0xD7 or nxt == 0xDF
  1396.    or nxt == 0xE7 or nxt == 0xEF or nxt == 0xF7 or nxt == 0xFF
  1397.    or nxt == 0xF3 or nxt == 0xFB
  1398.    or nxt == 0x27 or nxt == 0x2F or nxt == 0x37 or nxt == 0x3F
  1399.  
  1400.   if ignored then
  1401.     return exec(fetchOp()) + 4 + extra
  1402.   end
  1403.  
  1404.   sh, sl = R[4], R[5]
  1405.  
  1406.   R[4] = ireg >> 8
  1407.   R[5] = ireg & 255
  1408.  
  1409.   prefixed = true
  1410.  
  1411.   local instruction = fetchOp()
  1412.   local t = exec(instruction)
  1413.  
  1414.   prefixed = false
  1415.  
  1416.   local nv = (R[4] << 8) | R[5]
  1417.  
  1418.   if isIX then
  1419.     IX = nv
  1420.   else
  1421.     IY = nv
  1422.   end
  1423.  
  1424.   R[4], R[5] = sh, sl
  1425.  
  1426.   if not prefTotal(instruction) then
  1427.     t = t + 4
  1428.   end
  1429.  
  1430.   return t + extra
  1431. end
  1432.  
  1433. local function tapTrap()
  1434.   local want = R[7]
  1435.   local isLoad = (F & 1) ~= 0
  1436.  
  1437.   local de = (R[2] << 8) | R[3]
  1438.   local ok = false
  1439.  
  1440.   while tapePos <= #tapBlocks do
  1441.     local blk = tapBlocks[tapePos]
  1442.     tapePos = tapePos + 1
  1443.  
  1444.     if #blk > 0 and blk:byte(1) == want then
  1445.       if isLoad then
  1446.         local n = #blk - 2
  1447.         local cnt = math.min(n, de)
  1448.  
  1449.         for i = 0, cnt - 1 do
  1450.           wr((IX + i) & 0xFFFF, blk:byte(2 + i))
  1451.         end
  1452.  
  1453.         ok = (n == de)
  1454.  
  1455.         IX = (IX + cnt) & 0xFFFF
  1456.         de = de - cnt
  1457.       else
  1458.         ok = true
  1459.       end
  1460.  
  1461.       break
  1462.     end
  1463.   end
  1464.  
  1465.   R[2], R[3] = de >> 8, de & 255
  1466.  
  1467.   if ok then
  1468.     F = F | 1
  1469.   else
  1470.     F = F & 0xFE
  1471.   end
  1472.  
  1473.   PC = pop()
  1474.  
  1475.   IFF1 = true
  1476.   IFF2 = true
  1477.   eiDelay = 0
  1478.  
  1479.   return 10
  1480. end
  1481.  
  1482. local function step()
  1483.   if PC == 0x0556 and tapBlocks then
  1484.     return tapTrap()
  1485.   end
  1486.  
  1487.   local op = fetchOp()
  1488.  
  1489.   if op == 0xCB then
  1490.     return cbop()
  1491.  
  1492.   elseif op == 0xED then
  1493.     return edop()
  1494.  
  1495.   elseif op == 0xDD or op == 0xFD then
  1496.     return prefix(op)
  1497.   end
  1498.  
  1499.   return exec(op)
  1500. end
  1501.  
  1502. local function resetMachine()
  1503.   for i = 0x4000, 0xFFFF do
  1504.     M[i] = 0
  1505.   end
  1506.  
  1507.   for i = 0, 7 do
  1508.     R[i] = 0
  1509.     S[i] = 0
  1510.   end
  1511.  
  1512.   R[7] = 0xFF
  1513.   S[7] = 0xFF
  1514.   F = 0xFF
  1515.   F2 = 0xFF
  1516.  
  1517.   PC = 0
  1518.   SP = 0xFFFF
  1519.   IX = 0xFFFF
  1520.   IY = 0xFFFF
  1521.   I = 0
  1522.   RR = 0
  1523.  
  1524.   IFF1 = false
  1525.   IFF2 = false
  1526.   IM = 0
  1527.   halted = false
  1528.   eiDelay = 0
  1529.  
  1530.   border = 7
  1531.   borderDirty = true
  1532.  
  1533.   spk = 0
  1534.   tgN = 0
  1535.  
  1536.   tapePos = 1
  1537.  
  1538.   for i = 0, 1535 do
  1539.     dirty[i] = true
  1540.   end
  1541.  
  1542.   anyDirty = true
  1543. end
  1544.  
  1545. local function loadSNA(d)
  1546.   local function b(i)
  1547.     return d:byte(i + 1)
  1548.   end
  1549.  
  1550.   I = b(0)
  1551.  
  1552.   S[5], S[4] = b(1), b(2)
  1553.   S[3], S[2] = b(3), b(4)
  1554.   S[1], S[0] = b(5), b(6)
  1555.   F2, S[7] = b(7), b(8)
  1556.  
  1557.   R[5], R[4] = b(9), b(10)
  1558.   R[3], R[2] = b(11), b(12)
  1559.   R[1], R[0] = b(13), b(14)
  1560.  
  1561.   IY = b(15) | (b(16) << 8)
  1562.   IX = b(17) | (b(18) << 8)
  1563.  
  1564.   IFF2 = (b(19) & 4) ~= 0
  1565.   IFF1 = IFF2
  1566.  
  1567.   RR = b(20)
  1568.  
  1569.   F, R[7] = b(21), b(22)
  1570.  
  1571.   SP = b(23) | (b(24) << 8)
  1572.   IM = b(25) & 3
  1573.   border = b(26) & 7
  1574.  
  1575.   for i = 0, 49151 do
  1576.     M[0x4000 + i] = d:byte(28 + i)
  1577.   end
  1578.  
  1579.   PC = pop()
  1580.  
  1581.   halted = false
  1582.   eiDelay = 0
  1583.   borderDirty = true
  1584.  
  1585.   for i = 0, 1535 do
  1586.     dirty[i] = true
  1587.   end
  1588.  
  1589.   anyDirty = true
  1590. end
  1591.  
  1592. local function z80Unpack(d, pos, last, want)
  1593.   local out, n, o = {}, 0, 0
  1594.  
  1595.   while o < want and pos <= last do
  1596.     local b = d:byte(pos)
  1597.  
  1598.     if b == 0xED and pos + 3 <= last and d:byte(pos + 1) == 0xED then
  1599.       local cnt = d:byte(pos + 2)
  1600.       local v = d:byte(pos + 3)
  1601.       n = n + 1
  1602.       out[n] = string.rep(string.char(v), cnt)
  1603.       o = o + cnt
  1604.       pos = pos + 4
  1605.     else
  1606.       n = n + 1
  1607.       out[n] = string.char(b)
  1608.       o = o + 1
  1609.       pos = pos + 1
  1610.     end
  1611.   end
  1612.  
  1613.   local s = table.concat(out)
  1614.  
  1615.   if #s < want then
  1616.     s = s .. string.rep("\0", want - #s)
  1617.   end
  1618.  
  1619.   return s:sub(1, want)
  1620. end
  1621.  
  1622. local function loadZ80(d)
  1623.   local function b(i)
  1624.     return d:byte(i + 1) or 0
  1625.   end
  1626.  
  1627.   R[7] = b(0)
  1628.   F = b(1)
  1629.   R[1], R[0] = b(2), b(3)
  1630.   R[5], R[4] = b(4), b(5)
  1631.  
  1632.   local pc = b(6) | (b(7) << 8)
  1633.  
  1634.   SP = b(8) | (b(9) << 8)
  1635.   I = b(10)
  1636.  
  1637.   local f12 = b(12)
  1638.   if f12 == 255 then f12 = 1 end
  1639.  
  1640.   RR = (b(11) & 0x7F) | ((f12 & 1) << 7)
  1641.   border = (f12 >> 1) & 7
  1642.  
  1643.   local compressed = (f12 & 0x20) ~= 0
  1644.  
  1645.   R[3], R[2] = b(13), b(14)
  1646.   S[1], S[0] = b(15), b(16)
  1647.   S[3], S[2] = b(17), b(18)
  1648.   S[5], S[4] = b(19), b(20)
  1649.   S[7], F2 = b(21), b(22)
  1650.  
  1651.   IY = b(23) | (b(24) << 8)
  1652.   IX = b(25) | (b(26) << 8)
  1653.  
  1654.   IFF1 = b(27) ~= 0
  1655.   IFF2 = b(28) ~= 0
  1656.   IM = b(29) & 3
  1657.  
  1658.   if pc ~= 0 then
  1659.     local mem
  1660.  
  1661.     if compressed then
  1662.       mem = z80Unpack(d, 31, #d, 49152)
  1663.     else
  1664.       mem = d:sub(31, 30 + 49152)
  1665.     end
  1666.  
  1667.     for i = 0, 49151 do
  1668.       M[0x4000 + i] = mem:byte(i + 1) or 0
  1669.     end
  1670.  
  1671.     PC = pc
  1672.  
  1673.   else
  1674.     local hlen = b(30) | (b(31) << 8)
  1675.  
  1676.     PC = b(32) | (b(33) << 8)
  1677.  
  1678.     local mode = b(34)
  1679.  
  1680.     if (hlen == 23 and mode >= 3) or (hlen ~= 23 and mode >= 4) then
  1681.       error("z80: only 48K snapshots are supported")
  1682.     end
  1683.  
  1684.     local pos = 33 + hlen
  1685.  
  1686.     while pos + 2 <= #d do
  1687.       local len = d:byte(pos) | (d:byte(pos + 1) << 8)
  1688.       local page = d:byte(pos + 2)
  1689.  
  1690.       pos = pos + 3
  1691.  
  1692.       local mem
  1693.  
  1694.       if len == 0xFFFF then
  1695.         mem = d:sub(pos, pos + 16384)
  1696.         pos = pos + 16384
  1697.       else
  1698.         mem = z80Unpack(d, pos, pos + len - 1, 16384)
  1699.         pos = pos + len
  1700.       end
  1701.  
  1702.       local base
  1703.  
  1704.       if page == 8 then
  1705.         base = 0x4000
  1706.       elseif page == 4 then
  1707.         base = 0x8000
  1708.       elseif page == 5 then
  1709.         base = 0xC000
  1710.       end
  1711.  
  1712.       if base then
  1713.         for i = 0, 16383 do
  1714.           M[base + i] = mem:byte(i + 1) or 0
  1715.         end
  1716.       end
  1717.     end
  1718.   end
  1719.  
  1720.   halted = false
  1721.   eiDelay = 0
  1722.   borderDirty = true
  1723.  
  1724.   for i = 0, 1535 do dirty[i] = true end
  1725.   anyDirty = true
  1726. end
  1727.  
  1728. local function loadSCR(d)
  1729.   for i = 0, 6911 do
  1730.     M[0x4000 + i] = d:byte(i + 1)
  1731.   end
  1732.   for i = 0, 1535 do
  1733.     dirty[i] = true
  1734.   end
  1735.   anyDirty = true
  1736. end
  1737.  
  1738. local function loadBIN(d)
  1739.   local addr = tonumber(os.getenv("BIN_ADDR") or "0x8000") or 0x8000
  1740.   for i = 1, #d do
  1741.     M[(addr + i - 1) & 0xFFFF] = d:byte(i)
  1742.   end
  1743.   for i = 0, 1535 do dirty[i] = true end
  1744.   anyDirty = true
  1745. end
  1746.  
  1747. local LINE = {}
  1748.  
  1749. for y = 0, 191 do
  1750.   LINE[y] =
  1751.       0x4000
  1752.     | ((y & 0xC0) << 5)
  1753.     | ((y & 7) << 8)
  1754.     | ((y & 0x38) << 2)
  1755. end
  1756.  
  1757. local BL = {1, 2, 4, 0x40}
  1758. local BR = {8, 0x10, 0x20, 0x80}
  1759.  
  1760. local PX = {}
  1761.  
  1762. for k = 1, 4 do
  1763.   PX[k] = {}
  1764.  
  1765.   for pair = 0, 3 do
  1766.     PX[k][pair] =
  1767.       (((pair & 2) ~= 0) and BL[k] or 0)
  1768.       | (((pair & 1) ~= 0) and BR[k] or 0)
  1769.   end
  1770. end
  1771.  
  1772. local PX1, PX2, PX3, PX4 =
  1773.   PX[1], PX[2], PX[3], PX[4]
  1774.  
  1775. local uchar
  1776. do
  1777.   local ok, unicode = pcall(require, "unicode")
  1778.   if ok and unicode and unicode.char then
  1779.     uchar = unicode.char
  1780.   else
  1781.     uchar = utf8.char
  1782.   end
  1783. end
  1784.  
  1785. local curFG, curBG = -1, -1
  1786.  
  1787. local function cell(by, bx)
  1788.   local y0 = by << 2
  1789.  
  1790.   local attr =
  1791.     M[0x5800 + ((y0 >> 3) << 5) + bx]
  1792.  
  1793.   local ink = attr & 7
  1794.   local paper = (attr >> 3) & 7
  1795.  
  1796.   if (attr & 0x80) ~= 0 and flashOn then
  1797.     ink, paper = paper, ink
  1798.   end
  1799.  
  1800.   if (attr & 0x40) ~= 0 then
  1801.     ink = ink + 8
  1802.     paper = paper + 8
  1803.   end
  1804.  
  1805.   local b0 = M[LINE[y0] + bx]
  1806.   local b1 = M[LINE[y0 + 1] + bx]
  1807.   local b2 = M[LINE[y0 + 2] + bx]
  1808.   local b3 = M[LINE[y0 + 3] + bx]
  1809.  
  1810.   local s = uchar(
  1811.       0x2800
  1812.       | PX1[(b0 >> 6) & 3]
  1813.       | PX2[(b1 >> 6) & 3]
  1814.       | PX3[(b2 >> 6) & 3]
  1815.       | PX4[(b3 >> 6) & 3],
  1816.  
  1817.       0x2800
  1818.       | PX1[(b0 >> 4) & 3]
  1819.       | PX2[(b1 >> 4) & 3]
  1820.       | PX3[(b2 >> 4) & 3]
  1821.       | PX4[(b3 >> 4) & 3],
  1822.  
  1823.       0x2800
  1824.       | PX1[(b0 >> 2) & 3]
  1825.       | PX2[(b1 >> 2) & 3]
  1826.       | PX3[(b2 >> 2) & 3]
  1827.       | PX4[(b3 >> 2) & 3],
  1828.  
  1829.       0x2800
  1830.       | PX1[b0 & 3]
  1831.       | PX2[b1 & 3]
  1832.       | PX3[b2 & 3]
  1833.       | PX4[b3 & 3]
  1834.   )
  1835.  
  1836.   return ink, paper, s
  1837. end
  1838.  
  1839. local function flush(by, x0, fg, bg, str)
  1840.   if fg ~= curFG then
  1841.     gpu.setForeground(fg, true)
  1842.     curFG = fg
  1843.   end
  1844.  
  1845.   if bg ~= curBG then
  1846.     gpu.setBackground(bg, true)
  1847.     curBG = bg
  1848.   end
  1849.  
  1850.   gpu.set(
  1851.     ox + x0 * 4 + 1,
  1852.     oy + by + 1,
  1853.     str
  1854.   )
  1855. end
  1856.  
  1857. local function drawBorder()
  1858.   borderDirty = false
  1859.  
  1860.   if ox == 0 then return end
  1861.  
  1862.   if curBG ~= border then
  1863.     gpu.setBackground(border, true)
  1864.     curBG = border
  1865.   end
  1866.  
  1867.   gpu.fill(1, 1, 160, oy, " ")
  1868.   gpu.fill(1, 51 - oy, 160, oy, " ")
  1869.   gpu.fill(1, oy + 1, ox, 48, " ")
  1870.   gpu.fill(161 - ox, oy + 1, ox, 48, " ")
  1871. end
  1872.  
  1873. local function render()
  1874.   if borderDirty then
  1875.     drawBorder()
  1876.   end
  1877.  
  1878.   if not anyDirty then
  1879.     return
  1880.   end
  1881.  
  1882.   anyDirty = false
  1883.  
  1884.   for by = 0, 47 do
  1885.     local base = by * 32
  1886.     local bx = 0
  1887.  
  1888.     while bx < 32 do
  1889.       if dirty[base + bx] then
  1890.         local x0 = bx
  1891.         local fg, bg, str = cell(by, bx)
  1892.  
  1893.         dirty[base + bx] = nil
  1894.         bx = bx + 1
  1895.  
  1896.         while bx < 32 and dirty[base + bx] do
  1897.           local f2, b2, s2 = cell(by, bx)
  1898.  
  1899.           if f2 ~= fg or b2 ~= bg then
  1900.             break
  1901.           end
  1902.  
  1903.           dirty[base + bx] = nil
  1904.           str = str .. s2
  1905.           bx = bx + 1
  1906.         end
  1907.  
  1908.         flush(by, x0, fg, bg, str)
  1909.       else
  1910.         bx = bx + 1
  1911.       end
  1912.     end
  1913.   end
  1914. end
  1915.  
  1916. local function markFlash()
  1917.   for n = 0, 767 do
  1918.     if (M[0x5800 + n] & 0x80) ~= 0 then
  1919.       local k = (n >> 5) * 64 + (n & 31)
  1920.  
  1921.       dirty[k] = true
  1922.       dirty[k + 32] = true
  1923.  
  1924.       anyDirty = true
  1925.     end
  1926.   end
  1927. end
  1928.  
  1929. local CAPS = {{0, 0}}
  1930. local SYM = {{7, 1}}
  1931.  
  1932. local KEYS = {
  1933.   [42] = CAPS,
  1934.   [54] = SYM,
  1935.   [29] = SYM,
  1936.   [157] = SYM,
  1937.  
  1938.   [44] = {{0,1}},
  1939.   [45] = {{0,2}},
  1940.   [46] = {{0,3}},
  1941.   [47] = {{0,4}},
  1942.  
  1943.   [30] = {{1,0}},
  1944.   [31] = {{1,1}},
  1945.   [32] = {{1,2}},
  1946.   [33] = {{1,3}},
  1947.   [34] = {{1,4}},
  1948.  
  1949.   [16] = {{2,0}},
  1950.   [17] = {{2,1}},
  1951.   [18] = {{2,2}},
  1952.   [19] = {{2,3}},
  1953.   [20] = {{2,4}},
  1954.  
  1955.   [2] = {{3,0}},
  1956.   [3] = {{3,1}},
  1957.   [4] = {{3,2}},
  1958.   [5] = {{3,3}},
  1959.   [6] = {{3,4}},
  1960.  
  1961.   [11] = {{4,0}},
  1962.   [10] = {{4,1}},
  1963.   [9]  = {{4,2}},
  1964.   [8]  = {{4,3}},
  1965.   [7]  = {{4,4}},
  1966.  
  1967.   [25] = {{5,0}},
  1968.   [24] = {{5,1}},
  1969.   [23] = {{5,2}},
  1970.   [22] = {{5,3}},
  1971.   [21] = {{5,4}},
  1972.  
  1973.   [28] = {{6,0}},
  1974.   [38] = {{6,1}},
  1975.   [37] = {{6,2}},
  1976.   [36] = {{6,3}},
  1977.   [35] = {{6,4}},
  1978.  
  1979.   [57] = {{7,0}},
  1980.   [50] = {{7,2}},
  1981.   [49] = {{7,3}},
  1982.   [48] = {{7,4}},
  1983.  
  1984.   [14] = {CAPS[1], {4,0}},
  1985.  
  1986.   [203] = {CAPS[1], {3,4}},
  1987.   [208] = {CAPS[1], {4,4}},
  1988.   [200] = {CAPS[1], {4,3}},
  1989.   [205] = {CAPS[1], {4,2}},
  1990.  
  1991.   [51] = {SYM[1], {7,3}},
  1992.   [52] = {SYM[1], {7,2}},
  1993.   [53] = {SYM[1], {0,4}},
  1994.   [39] = {SYM[1], {5,1}},
  1995.   [12] = {SYM[1], {6,3}},
  1996.   [13] = {SYM[1], {6,1}},
  1997.   [40] = {SYM[1], {4,3}},
  1998. }
  1999.  
  2000. local function pressList(list)
  2001.   for _, k in ipairs(list) do
  2002.     local idx = k[1] * 8 + k[2]
  2003.     local n = (kcount[idx] or 0) + 1
  2004.  
  2005.     kcount[idx] = n
  2006.  
  2007.     if n == 1 then
  2008.       kb[k[1]] = kb[k[1]] & ~(1 << k[2])
  2009.     end
  2010.   end
  2011. end
  2012.  
  2013. local function releaseList(list)
  2014.   for _, k in ipairs(list) do
  2015.     local idx = k[1] * 8 + k[2]
  2016.     local n = (kcount[idx] or 0) - 1
  2017.  
  2018.     if n <= 0 then
  2019.       kcount[idx] = 0
  2020.       kb[k[1]] = kb[k[1]] | (1 << k[2])
  2021.     else
  2022.       kcount[idx] = n
  2023.     end
  2024.   end
  2025. end
  2026.  
  2027. local frames = 0
  2028. local running = true
  2029. local muted = false
  2030. local resetAudio
  2031. local adjustVolume
  2032.  
  2033. local downAt = {}
  2034. local pendingUp = {}
  2035.  
  2036. local typeQ
  2037. local typeI = 0
  2038. local typeT = 0
  2039.  
  2040. local LOAD_SEQ = {
  2041.   {{6,3}},
  2042.   {SYM[1], {5,0}},
  2043.   {SYM[1], {5,0}},
  2044.   {{6,0}},
  2045. }
  2046.  
  2047. local function typeTick()
  2048.   if not typeQ then return end
  2049.  
  2050.   typeT = typeT + 1
  2051.  
  2052.   local e = typeQ[typeI]
  2053.  
  2054.   if typeT == 1 then
  2055.     pressList(e)
  2056.  
  2057.   elseif typeT == 5 then
  2058.     releaseList(e)
  2059.  
  2060.   elseif typeT >= 8 then
  2061.     typeT = 0
  2062.     typeI = typeI + 1
  2063.  
  2064.     if typeI > #typeQ then
  2065.       typeQ = nil
  2066.     end
  2067.   end
  2068. end
  2069.  
  2070. local function handle(name, _, _, code)
  2071.   if name == "key_down" then
  2072.  
  2073.     if code == 88 then
  2074.       running = false
  2075.       return
  2076.     end
  2077.  
  2078.     if code == 63 then
  2079.       resetMachine()
  2080.       return
  2081.     end
  2082.  
  2083.     if code == 61 then
  2084.       typeQ = LOAD_SEQ
  2085.       typeI = 1
  2086.       typeT = 0
  2087.       return
  2088.     end
  2089.  
  2090.     if code == 62 then
  2091.       tapePos = 1
  2092.       return
  2093.     end
  2094.  
  2095.     if code == 64 then
  2096.       if adjustVolume then adjustVolume(-0.1) end
  2097.       return
  2098.     end
  2099.  
  2100.     if code == 65 then
  2101.       if adjustVolume then adjustVolume(0.1) end
  2102.       return
  2103.     end
  2104.  
  2105.     if code == 60 then
  2106.       muted = not muted
  2107.       if resetAudio then resetAudio() end
  2108.       return
  2109.     end
  2110.  
  2111.     local list = KEYS[code]
  2112.  
  2113.     if list then
  2114.       if not downAt[code] then
  2115.         downAt[code] = frames
  2116.         pressList(list)
  2117.       end
  2118.  
  2119.       pendingUp[code] = nil
  2120.     end
  2121.  
  2122.   elseif name == "key_up" then
  2123.     local t = downAt[code]
  2124.  
  2125.     if t then
  2126.       if frames - t >= KEY_HOLD then
  2127.         releaseList(KEYS[code])
  2128.         downAt[code] = nil
  2129.       else
  2130.         pendingUp[code] = t + KEY_HOLD
  2131.       end
  2132.     end
  2133.  
  2134.   elseif name == "interrupted" then
  2135.     running = false
  2136.   end
  2137. end
  2138.  
  2139. local function pump(timeout)
  2140.   local s, a, b, c = computer.pullSignal(timeout)
  2141.  
  2142.   while s and running do
  2143.     handle(s, a, b, c)
  2144.     s, a, b, c = computer.pullSignal(0)
  2145.   end
  2146. end
  2147.  
  2148. local SNDCFG = {spFs = 16384, spN = 1024, polyMin = 0.02, polyRel = 0.06, polyMax = 8, gain = 0.85, tilt = 0.2, maxHz = 15000}
  2149.  
  2150. local SP_FS = SNDCFG.spFs or 16384
  2151. local SP_N = SNDCFG.spN or 1024
  2152. local SP_M = SP_N // 2
  2153. local SP_TS = CPU_HZ / SP_FS
  2154. local SP_DF = SP_FS / SP_N
  2155. local SP_NYQ = SP_FS / 2
  2156. local SP_KMIN = math.max(2, math.ceil(45 / SP_DF))
  2157.  
  2158. local spRing, spW, spS, spLast, spAcc, spLvl = {}, 0, 0, 0, 0, 0
  2159. local spHann, spBR, spTwr, spTwi, spPwr, spPwi = {}, {}, {}, {}, {}, {}
  2160. local spX, spRe, spIm, spAmp, spMark = {}, {}, {}, {}, {}
  2161. local spPrev = {}
  2162. local spStamp = 0
  2163. local spCount = 0
  2164. local spCache = nil
  2165.  
  2166. do
  2167.   for i = 1, SP_N do
  2168.     spHann[i] = 0.5 - 0.5 * math.cos(2 * math.pi * (i - 1) / SP_N)
  2169.     spX[i] = 0
  2170.     spRing[i] = 0
  2171.   end
  2172.  
  2173.   local bits = 0
  2174.   while (1 << bits) < SP_M do bits = bits + 1 end
  2175.  
  2176.   for m = 0, SP_M - 1 do
  2177.     local r, x = 0, m
  2178.     for _ = 1, bits do
  2179.       r = (r << 1) | (x & 1)
  2180.       x = x >> 1
  2181.     end
  2182.     spBR[m + 1] = r + 1
  2183.     spRe[m + 1] = 0
  2184.     spIm[m + 1] = 0
  2185.   end
  2186.  
  2187.   for t = 0, SP_M // 2 - 1 do
  2188.     spTwr[t + 1] = math.cos(2 * math.pi * t / SP_M)
  2189.     spTwi[t + 1] = -math.sin(2 * math.pi * t / SP_M)
  2190.   end
  2191.  
  2192.   for k = 0, SP_M do
  2193.     spPwr[k + 1] = math.cos(2 * math.pi * k / SP_N)
  2194.     spPwi[k + 1] = -math.sin(2 * math.pi * k / SP_N)
  2195.     spAmp[k + 1] = 0
  2196.     spMark[k + 1] = 0
  2197.   end
  2198. end
  2199.  
  2200. local function spInit(t)
  2201.   spW = 0
  2202.   spS = t
  2203.   spLast = t
  2204.   spAcc = 0
  2205.   spPrev = {}
  2206.   spCache = nil
  2207.   spCount = 0
  2208.  
  2209.   for i = 1, SP_N do spRing[i] = 0 end
  2210. end
  2211.  
  2212. local function spAdvance(t)
  2213.   if t <= spLast then return end
  2214.  
  2215.   local lvl = spLvl
  2216.  
  2217.   while spS + SP_TS <= t do
  2218.     local e = spS + SP_TS
  2219.     local v = (spAcc + lvl * (e - spLast)) / SP_TS
  2220.  
  2221.     spW = spW + 1
  2222.     spRing[(spW - 1) % SP_N + 1] = v
  2223.  
  2224.     spS = e
  2225.     spLast = e
  2226.     spAcc = 0
  2227.   end
  2228.  
  2229.   spAcc = spAcc + lvl * (t - spLast)
  2230.   spLast = t
  2231. end
  2232.  
  2233. local function spFeed(fe, tT, tL, tN)
  2234.   for i = 1, tN do
  2235.     spAdvance(tT[i])
  2236.     spLvl = tL[i]
  2237.   end
  2238.  
  2239.   spAdvance(fe)
  2240. end
  2241.  
  2242. local function spSpectrum()
  2243.   local N, M = SP_N, SP_M
  2244.   local base = spW - N
  2245.   local sum = 0
  2246.  
  2247.   for i = 1, N do
  2248.     local idx = base + i
  2249.     local v = 0
  2250.  
  2251.     if idx >= 1 then v = spRing[(idx - 1) % N + 1] end
  2252.  
  2253.     spX[i] = v
  2254.     sum = sum + v
  2255.   end
  2256.  
  2257.   local mean = sum / N
  2258.  
  2259.   for m = 0, M - 1 do
  2260.     local j = spBR[m + 1]
  2261.     local i0 = 2 * m + 1
  2262.     spRe[j] = (spX[i0] - mean) * spHann[i0]
  2263.     spIm[j] = (spX[i0 + 1] - mean) * spHann[i0 + 1]
  2264.   end
  2265.  
  2266.   local re, im = spRe, spIm
  2267.   local size = 2
  2268.  
  2269.   while size <= M do
  2270.     local half = size >> 1
  2271.     local step = M // size
  2272.  
  2273.     for st = 0, M - 1, size do
  2274.       local tw = 1
  2275.  
  2276.       for k = st + 1, st + half do
  2277.         local wr, wi = spTwr[tw], spTwi[tw]
  2278.         local b = k + half
  2279.         local br, bi = re[b], im[b]
  2280.         local xr = br * wr - bi * wi
  2281.         local xi = br * wi + bi * wr
  2282.         local ar, ai = re[k], im[k]
  2283.  
  2284.         re[b] = ar - xr
  2285.         im[b] = ai - xi
  2286.         re[k] = ar + xr
  2287.         im[k] = ai + xi
  2288.  
  2289.         tw = tw + step
  2290.       end
  2291.     end
  2292.  
  2293.     size = size << 1
  2294.   end
  2295.  
  2296.   local scale = 4 / N
  2297.  
  2298.   for k = 0, M do
  2299.     local ka = k % M
  2300.     local kb = (M - k) % M
  2301.     local zr, zi = re[ka + 1], im[ka + 1]
  2302.     local cr, ci = re[kb + 1], -im[kb + 1]
  2303.     local er, ei = (zr + cr) * 0.5, (zi + ci) * 0.5
  2304.     local orr, oi = (zi - ci) * 0.5, -(zr - cr) * 0.5
  2305.     local wr, wi = spPwr[k + 1], spPwi[k + 1]
  2306.     local xr = er + orr * wr - oi * wi
  2307.     local xi = ei + orr * wi + oi * wr
  2308.  
  2309.     spAmp[k + 1] = math.sqrt(xr * xr + xi * xi) * scale
  2310.   end
  2311. end
  2312.  
  2313. local function spBand(f, tol)
  2314.   local k0 = math.floor(f * (1 - tol) / SP_DF)
  2315.   local k1 = math.ceil(f * (1 + tol) / SP_DF)
  2316.  
  2317.   if k0 < 1 then k0 = 1 end
  2318.   if k1 > SP_M then k1 = SP_M end
  2319.  
  2320.   local best = 0
  2321.  
  2322.   for k = k0, k1 do
  2323.     local a = spAmp[k + 1]
  2324.     if a > best then best = a end
  2325.   end
  2326.  
  2327.   return best
  2328. end
  2329.  
  2330. local SP_FUND = {sq = 4 / math.pi, tri = 8 / (math.pi * math.pi), sin = 1}
  2331. local SP_HARM = {
  2332.   sq = function(h) return (h % 2 == 1) and 1 / h or 0 end,
  2333.   tri = function(h) return (h % 2 == 1) and 1 / (h * h) or 0 end,
  2334.   sin = function(h) return 0 end,
  2335. }
  2336.  
  2337. local function spVoices()
  2338.   spSpectrum()
  2339.  
  2340.   local amp = spAmp
  2341.   local kmax = SP_M - 1
  2342.   local top = 0
  2343.   local tot = 0
  2344.  
  2345.   for k = SP_KMIN, kmax do
  2346.     local a = amp[k + 1]
  2347.     tot = tot + a * a
  2348.     if a > top then top = a end
  2349.   end
  2350.  
  2351.   if top < (SNDCFG.polyMin or 0.02) or tot <= 0 then return nil, 0 end
  2352.  
  2353.   local thr = math.max(SNDCFG.polyMin or 0.02, (SNDCFG.polyRel or 0.06) * top)
  2354.   local cands = {}
  2355.  
  2356.   for k = SP_KMIN, kmax do
  2357.     local a = amp[k + 1]
  2358.  
  2359.     if a >= thr * 0.6 and a >= amp[k] and a > amp[k + 2] then
  2360.       local al, ac, ar = amp[k], a, amp[k + 2]
  2361.       local la, lb, lc = math.log(math.max(al, 1e-9)), math.log(ac),
  2362.                          math.log(math.max(ar, 1e-9))
  2363.       local den = la - 2 * lb + lc
  2364.       local d = 0
  2365.  
  2366.       if den < -1e-9 then d = 0.5 * (la - lc) / den end
  2367.       if d > 0.5 then d = 0.5 elseif d < -0.5 then d = -0.5 end
  2368.  
  2369.       local f = (k + d) * SP_DF
  2370.       local pa = math.exp(lb - 0.25 * (la - lc) * d)
  2371.       local keep = pa >= thr
  2372.  
  2373.       if not keep then
  2374.         for i = 1, #spPrev do
  2375.           if math.abs(f / spPrev[i] - 1) < 0.04 then keep = true break end
  2376.         end
  2377.       end
  2378.  
  2379.       if keep then cands[#cands + 1] = {f = f, a = pa, k = k} end
  2380.     end
  2381.   end
  2382.  
  2383.   if #cands == 0 then return nil, 0 end
  2384.  
  2385.   table.sort(cands, function(x, y) return x.a > y.a end)
  2386.  
  2387.   spStamp = spStamp + 1
  2388.  
  2389.   local pe = 0
  2390.  
  2391.   for i = 1, math.min(#cands, 10) do
  2392.     local k = cands[i].k
  2393.  
  2394.     for j = math.max(SP_KMIN, k - 2), math.min(kmax, k + 2) do
  2395.       if spMark[j + 1] ~= spStamp then
  2396.         spMark[j + 1] = spStamp
  2397.         pe = pe + amp[j + 1] * amp[j + 1]
  2398.       end
  2399.     end
  2400.   end
  2401.  
  2402.   local conc = pe / tot
  2403.  
  2404.   local maxV = math.min(8, SNDCFG.polyMax or 8)
  2405.   local voices = {}
  2406.  
  2407.   for _, p in ipairs(cands) do
  2408.     local harmonic = false
  2409.  
  2410.     for _, v in ipairs(voices) do
  2411.       local h = math.floor(p.f / v.f + 0.5)
  2412.  
  2413.       if h >= 2 and h <= 8 then
  2414.         local near = math.abs(p.f / (h * v.f) - 1) < 0.03
  2415.                      or math.abs(p.f - h * v.f) < 1.3 * SP_DF
  2416.  
  2417.         if near and p.a <= 1.6 * v.a / h then
  2418.           v.harm[#v.harm + 1] = {h = h, f = p.f, a = p.a}
  2419.           harmonic = true
  2420.           break
  2421.         end
  2422.       end
  2423.     end
  2424.  
  2425.     if not harmonic and #voices < maxV then
  2426.       voices[#voices + 1] = {f = p.f, a = p.a, harm = {}}
  2427.     end
  2428.   end
  2429.  
  2430.   local g = SNDCFG.gain or 0.85
  2431.   local tilt = SNDCFG.tilt or 0.2
  2432.   local out, extras = {}, {}
  2433.   local sumv = 0
  2434.  
  2435.   for _, v in ipairs(voices) do
  2436.     local r2 = (2 * v.f < SP_NYQ) and spBand(2 * v.f, 0.03) / v.a or 0
  2437.     local r3 = (3 * v.f < SP_NYQ) and spBand(3 * v.f, 0.03) / v.a or 1 / 3
  2438.     local wave
  2439.  
  2440.     if r3 < 0.05 and r2 < 0.1 then
  2441.       wave = "sin"
  2442.     elseif r3 < 0.2 and r2 < 0.2 then
  2443.       wave = "tri"
  2444.     else
  2445.       wave = "sq"
  2446.     end
  2447.  
  2448.     local fm = SP_HARM[wave]
  2449.     local lift = math.min(1.6, math.max(0.85, (v.f / 250) ^ tilt))
  2450.     local vol = v.a * 2 * g * lift / SP_FUND[wave]
  2451.  
  2452.     out[#out + 1] = {v.f, vol, wave, v.a}
  2453.     sumv = sumv + vol
  2454.  
  2455.     for _, hm in ipairs(v.harm) do
  2456.       local res = hm.a - fm(hm.h) * v.a
  2457.  
  2458.       if res >= math.max(SNDCFG.polyMin or 0.02, 0.12 * v.a)
  2459.          and hm.f < SNDCFG.maxHz then
  2460.         extras[#extras + 1] = {hm.f, res * 2 * g, "sin", res}
  2461.       end
  2462.     end
  2463.   end
  2464.  
  2465.   table.sort(extras, function(x, y) return x[4] > y[4] end)
  2466.  
  2467.   for i = 1, #extras do
  2468.     if #out >= 8 then break end
  2469.  
  2470.     out[#out + 1] = extras[i]
  2471.     sumv = sumv + extras[i][2]
  2472.   end
  2473.  
  2474.   local sc = 1
  2475.  
  2476.   if sumv > 1.15 then sc = 1.15 / sumv end
  2477.  
  2478.   for _, o in ipairs(out) do
  2479.     o[2] = math.min(1, o[2] * sc)
  2480.   end
  2481.  
  2482.   spPrev = {}
  2483.  
  2484.   for i = 1, #out do spPrev[i] = out[i][1] end
  2485.  
  2486.   return out, conc
  2487. end
  2488.  
  2489. local masterVol = MASTER_VOLUME
  2490. local chs = { held = false, cw = {}, cv = {}, cf = {}, co = {} }
  2491.  
  2492. local function resetChannels()
  2493.   chs.cw, chs.cv, chs.cf, chs.co = {}, {}, {}, {}
  2494.   chs.init = false
  2495.   chs.held = false
  2496. end
  2497.  
  2498. resetChannels()
  2499.  
  2500. local function cardClear()
  2501.   if snd and snd.clear then
  2502.     pcall(function() snd.clear() end)
  2503.   end
  2504.  
  2505.   if chs.held and snd then
  2506.     pcall(function()
  2507.       for c = 1, 8 do snd.close(c) end
  2508.       snd.process()
  2509.     end)
  2510.   end
  2511.  
  2512.   resetChannels()
  2513. end
  2514.  
  2515. resetAudio = function()
  2516.   tgN = 0
  2517.   spInit(ts)
  2518.   cardClear()
  2519. end
  2520.  
  2521. adjustVolume = function(delta)
  2522.   if not snd then return end
  2523.   masterVol = math.max(0, math.min(1, masterVol + delta))
  2524.   pcall(function() snd.setTotalVolume(masterVol) end)
  2525. end
  2526.  
  2527. local function initSound()
  2528.   if not snd then return end
  2529.   pcall(function() snd.setTotalVolume(masterVol) end)
  2530.   spInit(0)
  2531. end
  2532.  
  2533. local function closeSound()
  2534.   if not snd then return end
  2535.   pcall(function()
  2536.     for c = 1, 8 do snd.close(c) end
  2537.     snd.process()
  2538.   end)
  2539. end
  2540.  
  2541. local WAVE_MAP = {
  2542.   sq = 1,
  2543.   sin = 2,
  2544.   tri = 3
  2545. }
  2546.  
  2547. local function analyseBeeper(fs, fe)
  2548.   if not snd or muted then
  2549.     tgN = 0
  2550.     return
  2551.   end
  2552.  
  2553.   spFeed(fe, tgT, tgL, tgN)
  2554.   tgN = 0
  2555. end
  2556.  
  2557. local function submitAudio()
  2558.   if not snd or muted then return end
  2559.  
  2560.   local voices, conc = spVoices()
  2561.  
  2562.   if not voices or #voices == 0 then
  2563.     if chs.held then
  2564.       pcall(function()
  2565.         for c = 1, 8 do snd.close(c) end
  2566.         snd.process()
  2567.       end)
  2568.       resetChannels()
  2569.     end
  2570.     return
  2571.   end
  2572.  
  2573.   pcall(function()
  2574.     local modes = snd.modes or {}
  2575.     local waveTypes = {
  2576.       sq = modes.square or 1,
  2577.       sin = modes.sine or modes.square or 1,
  2578.       tri = modes.triangle or modes.square or 1
  2579.     }
  2580.  
  2581.     if not chs.init then
  2582.       for c = 1, 8 do
  2583.         snd.close(c)
  2584.         pcall(snd.setADSR, c, 1, 1, 1, 1)
  2585.       end
  2586.       chs.init = true
  2587.     end
  2588.  
  2589.     local usedChannels = #voices
  2590.  
  2591.     for c = 1, usedChannels do
  2592.       local v = voices[c]
  2593.       local freq = v[1]
  2594.       local vol = v[2]
  2595.       local waveStr = v[3]
  2596.       local waveType = waveTypes[waveStr] or 1
  2597.  
  2598.       if chs.cw[c] ~= waveType then
  2599.         snd.setWave(c, waveType)
  2600.         chs.cw[c] = waveType
  2601.       end
  2602.  
  2603.       if not chs.cv[c] or math.abs(chs.cv[c] - vol) > 0.02 then
  2604.         snd.setVolume(c, vol)
  2605.         chs.cv[c] = vol
  2606.       end
  2607.  
  2608.       local fi = math.max(1, math.floor(freq + 0.5))
  2609.       if chs.cf[c] ~= fi then
  2610.         snd.setFrequency(c, fi)
  2611.         chs.cf[c] = fi
  2612.       end
  2613.  
  2614.       if not chs.co[c] then
  2615.         snd.open(c)
  2616.         chs.co[c] = true
  2617.       end
  2618.     end
  2619.  
  2620.     for c = usedChannels + 1, 8 do
  2621.       if chs.co[c] then
  2622.         snd.close(c)
  2623.         chs.co[c] = false
  2624.       end
  2625.     end
  2626.  
  2627.     snd.delay(20)
  2628.     snd.process()
  2629.     chs.held = true
  2630.   end)
  2631. end
  2632.  
  2633. local saved = {}
  2634.  
  2635. local function setupGPU()
  2636.   local mw, mh = gpu.maxResolution()
  2637.  
  2638.   saved.w, saved.h = gpu.getResolution()
  2639.   saved.depth = gpu.getDepth()
  2640.   saved.fg, saved.fgp = gpu.getForeground()
  2641.   saved.bg, saved.bgp = gpu.getBackground()
  2642.  
  2643.   if mw >= 160 and mh >= 50 then
  2644.     gpu.setResolution(160, 50)
  2645.     ox, oy = 16, 1
  2646.  
  2647.   elseif mw >= 128 and mh >= 48 then
  2648.     gpu.setResolution(128, 48)
  2649.     ox, oy = 0, 0
  2650.  
  2651.   else
  2652.     error(
  2653.       "a Tier 3 GPU and screen (at least 128x48 characters) are required"
  2654.     )
  2655.   end
  2656.  
  2657.   gpu.setDepth(gpu.maxDepth())
  2658.  
  2659.   saved.pal = {}
  2660.  
  2661.   for c = 0, 15 do
  2662.     local v = (c >= 8) and 0xFF or 0xD7
  2663.     local cc = c & 7
  2664.  
  2665.     local r = ((cc & 2) ~= 0) and v or 0
  2666.     local g = ((cc & 4) ~= 0) and v or 0
  2667.     local b = ((cc & 1) ~= 0) and v or 0
  2668.  
  2669.     saved.pal[c] =
  2670.       gpu.setPaletteColor(
  2671.         c,
  2672.         (r << 16) | (g << 8) | b
  2673.       )
  2674.   end
  2675.  
  2676.   local w, h = gpu.getResolution()
  2677.  
  2678.   gpu.setBackground(7, true)
  2679.   curBG = 7
  2680.  
  2681.   gpu.fill(1, 1, w, h, " ")
  2682.  
  2683.   curFG = -1
  2684. end
  2685.  
  2686. local function restoreGPU()
  2687.   pcall(function()
  2688.     if saved.pal then
  2689.       for c = 0, 15 do
  2690.         if saved.pal[c] then
  2691.           gpu.setPaletteColor(c, saved.pal[c])
  2692.         end
  2693.       end
  2694.     end
  2695.  
  2696.     if saved.depth then
  2697.       gpu.setDepth(saved.depth)
  2698.     end
  2699.  
  2700.     if saved.w then
  2701.       gpu.setResolution(saved.w, saved.h)
  2702.     end
  2703.  
  2704.     if saved.fg then
  2705.       gpu.setForeground(saved.fg, saved.fgp)
  2706.     end
  2707.  
  2708.     if saved.bg then
  2709.       gpu.setBackground(saved.bg, saved.bgp)
  2710.     end
  2711.  
  2712.     local w, h = gpu.getResolution()
  2713.     gpu.fill(1, 1, w, h, " ")
  2714.   end)
  2715. end
  2716.  
  2717. local function serviceKeyboard()
  2718.   for code, f in pairs(pendingUp) do
  2719.     if frames >= f then
  2720.       local list = KEYS[code]
  2721.  
  2722.       if list then
  2723.         releaseList(list)
  2724.       end
  2725.  
  2726.       downAt[code] = nil
  2727.       pendingUp[code] = nil
  2728.     end
  2729.   end
  2730. end
  2731.  
  2732. local function acceptInterrupt()
  2733.   halted = false
  2734.   IFF1 = false
  2735.   IFF2 = false
  2736.   incR()
  2737.  
  2738.   if IM == 2 then
  2739.     push(PC)
  2740.  
  2741.     local v = (I << 8) | 0xFF
  2742.     PC =
  2743.       M[v]
  2744.       | (M[(v + 1) & 0xFFFF] << 8)
  2745.  
  2746.     return 19
  2747.   end
  2748.  
  2749.   push(PC)
  2750.   PC = 0x38
  2751.  
  2752.   return 13
  2753. end
  2754.  
  2755. local function main()
  2756.   setupGPU()
  2757.   initSound()
  2758.  
  2759.   resetMachine()
  2760.  
  2761.   local haveSnapshot = false
  2762.  
  2763.   if snaData then
  2764.     loadSNA(snaData)
  2765.     haveSnapshot = true
  2766.   elseif z80Data then
  2767.     loadZ80(z80Data)
  2768.     haveSnapshot = true
  2769.   elseif scrData then
  2770.     loadSCR(scrData)
  2771.   elseif binData then
  2772.     loadBIN(binData)
  2773.     haveSnapshot = true
  2774.   end
  2775.  
  2776.   local autoLoad = tapBlocks ~= nil and not haveSnapshot
  2777.  
  2778.   frameStart = ts
  2779.  
  2780.   local nextT = computer.uptime()
  2781.   local lastPump = nextT
  2782.  
  2783.   while running do
  2784.     frames = frames + 1
  2785.  
  2786.     local frameEnd = frameStart + FRAME_TS
  2787.  
  2788.     local intPending = true
  2789.     local intEnd = frameStart + 32
  2790.  
  2791.     while ts < frameEnd do
  2792.       if intPending then
  2793.         if ts >= intEnd then
  2794.           intPending = false
  2795.         elseif IFF1 and eiDelay == 0 then
  2796.           intPending = false
  2797.           ts = ts + acceptInterrupt()
  2798.         end
  2799.       end
  2800.  
  2801.       if halted then
  2802.         ts = frameEnd
  2803.       else
  2804.         ts = ts + step()
  2805.  
  2806.         if eiDelay > 0 then
  2807.           eiDelay = eiDelay - 1
  2808.         end
  2809.       end
  2810.     end
  2811.  
  2812.     analyseBeeper(frameStart, frameEnd)
  2813.  
  2814.     frameStart = frameEnd
  2815.  
  2816.     if (frames & 15) == 0 then
  2817.       flashOn = not flashOn
  2818.       markFlash()
  2819.     end
  2820.  
  2821.     if autoLoad and frames == AUTOLOAD_FRAME then
  2822.       typeQ = LOAD_SEQ
  2823.       typeI = 1
  2824.       typeT = 0
  2825.     end
  2826.  
  2827.     typeTick()
  2828.     serviceKeyboard()
  2829.  
  2830.     if frames % RENDER_EVERY == 0 then
  2831.       render()
  2832.     end
  2833.  
  2834.     submitAudio()
  2835.  
  2836.     local now = computer.uptime()
  2837.  
  2838.     if now < nextT then
  2839.       repeat
  2840.         pump(nextT - now)
  2841.         now = computer.uptime()
  2842.       until now >= nextT or not running
  2843.  
  2844.       lastPump = now
  2845.  
  2846.     elseif now - lastPump >= PUMP_INTERVAL then
  2847.       pump(0)
  2848.       lastPump = computer.uptime()
  2849.     end
  2850.  
  2851.     nextT = nextT + FRAME_TS / CPU_HZ
  2852.  
  2853.     if nextT < now - 0.1 then
  2854.       nextT = now
  2855.     end
  2856.   end
  2857. end
  2858.  
  2859. local ok, err = xpcall(main, debug.traceback)
  2860.  
  2861. closeSound()
  2862. restoreGPU()
  2863.  
  2864. if not ok then
  2865.   io.stderr:write(tostring(err) .. "\n")
  2866. end
Add Comment
Please, Sign In to add comment