-- Drive src/player/scsigate.s: can the 68000 reach the MB89352? (ROADMAP P4) -- -- Bus errors are EXPECTED and are data: the gate probes one address at a time -- and survives each fault, so a hole in the decode costs an entry in the map -- rather than the rest of the run. See src/player/scsigate.s. -- -- THE APPARATUS, STATED UP FRONT. This runs `x68000 -exp1 cz6bs1`, which is -- the board FINDINGS 42.5 says to benchmark and never `x68ksupr` (whose -- internal SCSI is PIO-only in MAME -- `// TODO: duplicate DMA glue from -- CZ-6BS1`). MAME refuses to instantiate the card without an 8 KB -- `scsiexrom.bin`, which is not in this tree; the rig supplies a ZERO-FILLED -- placeholder on a SEPARATE rompath so the user's own romset is untouched. -- -- THAT PLACEHOLDER IS HONEST HERE AND WOULD NOT BE EVERYWHERE. The CZ-6BS1's -- boot ROM exists to make the card bootable through IOCS. This player drives -- the SPC registers directly and never executes a byte of it -- that was -- already the plan in docs/BENCHMARK.md item 4, long before the ROM was missing -- -- so a blank one changes nothing this rig measures. What it WOULD change is -- anything that booted from the card or called SCSI IOCS; do not reuse it for -- that. The run prints the substitution rather than burying it. -- -- WHAT A GREEN RUN MEANS, and what it does not. It means the 68000 reaches the -- SPC and the register map is the one the driver will be written against. It -- says NOTHING about rate: MAME's device models are functional, not -- transfer-timing accurate (docs/BENCHMARK.md), and 42.5 shows its DMAC is -- configured in wall-clock attotimes rather than per-operand cycles. `W` is -- untouched by anything here. local M = manager.machine local SP = M.devices[":maincpu"].spaces["program"] local function P(s) print("[SCSI] "..s) end local function T() local t=M.time; return t.seconds + t.attoseconds/1e18 end local SCFLAG, SCN, SCVAL, SCOK, SCTMP, SCTMPOK = 0x18080, 64, 0x18100, 0x18140, 0x180D0, 0x180D4 local SCRD, SCDST, SCBLKS = 0x180D8, 0x20000, 8 local SC_ERR, SC_STAT, SC_PH = 0x18200, 0x18204, 0x18208 local ERRNAME = {[0]="OK", "SELECTION TIMEOUT -- no target answered", "UNEXPECTED PHASE", "POLL TIMEOUT -- a phase never arrived", "NON-ZERO SCSI STATUS"} local DISK = os.getenv("DLX_SCSI_IMG") or "dlxdisk.img" local code do local f=io.open("scsigate.bin","rb"); code=f:read("a"); f:close() end local st = "boot" SUB = emu.add_machine_frame_notifier(function() local ok, err = pcall(function() if st == "boot" then if T() < 3.0 then return end for i = 1, #code do SP:write_u8(0x10000+i-1, string.byte(code,i)) end SP:write_u32(SCFLAG, 0) local cpu = M.devices[":maincpu"] cpu.state["SR"].value = 0x2700 cpu.state["SP"].value = 0x8000 cpu.state["PC"].value = 0x10000 P(string.format("scsigate.bin=%d B loaded at $10000", #code)) st = "wait"; return end if st == "wait" then local fl = SP:read_u32(SCFLAG) if fl ~= 1 then if T() > 30 then P("TIMEOUT: the gate never finished"); P("done"); M:exit() end return end -- THE MAP, address by address. A dead address is a bus error the -- gate survived, not a run that stopped. local live, dead = {}, {} for i = 0, SCN-1 do if SP:read_u8(SCOK+i) == 1 then live[#live+1] = i else dead[#dead+1] = i end end for row = 0, (SCN/16)-1 do local t = {} for i = 0, 15 do local a = row*16 + i t[#t+1] = (SP:read_u8(SCOK+a) == 1) and string.format("%02X", SP:read_u8(SCVAL+a)) or "--" end P(string.format(" $EA%04X: %s", row*16, table.concat(t, " "))) end P(string.format("ANSWERED %d of %d addresses; \"--\" is a bus error.", #live, SCN)) -- The lane question, decided by which addresses answer. local odd_live, even_live = 0, 0 for _, a in ipairs(live) do if a % 2 == 1 then odd_live = odd_live + 1 else even_live = even_live + 1 end end P(string.format("LANES: %d odd addresses answer, %d even.", odd_live, even_live)) if SP:read_u32(SCTMPOK) == 1 then P(string.format("TEMP writeback ($EA0017): wrote $A5, read back $%02X", SP:read_u32(SCTMP) & 0xFF)) else P("TEMP writeback ($EA0017): BUS ERROR -- not a writable register here.") end P(string.format("DREG writeback ($EA0015): wrote $5A, SSTS then $%02X " .."(FIFO %s), read back $%02X", SP:read_u32(0x180E0) & 0xFF, ((SP:read_u32(0x180E0) & 1) == 1) and "EMPTY -- the write " .."never reached dreg_w" or "has a byte", SP:read_u32(0x180DC) & 0xFF)) -- The trace, whatever happened. local ntr = SP:read_u32(0x18230) if ntr > 0 then P("trace (SSTS PSNS INTS SERR | TCH TCM TCL | where):") for i = 0, ntr-1 do local b = {} for k = 0, 7 do b[k+1] = string.format("%02X", SP:read_u8(0x18240+i*8+k)) end local WH = {[0]="init", "selected", "INTS cleared", "phase loop saw REQ", "TRANSFER issued (out)", "bytes handed over", "after xfer wait", "TRANSFER issued (in)", "bytes taken from FIFO", "after IN xfer wait", "after bus release"} P(string.format(" %2d: %s %s %s %s | %s %s %s | %s", i, b[1], b[2], b[3], b[4], b[5], b[6], b[7], WH[tonumber(b[8], 16)] or b[8])) end end -- THE READ. Verified against the host's copy of the same image: a -- transport that returns the wrong bytes without saying so is exactly the -- failure a checksum-free ring cannot survive (49.2). local rd = SP:read_u32(SCRD) local e = SP:read_u32(0x180E8) if rd ~= 0 or e ~= 0 then P(string.format("scsi_read FAILED: err=%d (%s), status=$%02X, phase=%d", e, ERRNAME[e] or "?", SP:read_u32(SC_STAT) & 0xFF, SP:read_u32(SC_PH))) else local f = io.open(DISK, "rb") if not f then P("scsi_read returned OK but "..DISK.." is not here to check it against.") else local want = f:read(SCBLKS * 512); f:close() local bad, first = 0, nil for i = 1, #want do if SP:read_u8(SCDST + i - 1) ~= string.byte(want, i) then bad = bad + 1; first = first or (i-1) end end if bad == 0 then P(string.format("READ(10) OK: %d B from LBA 0 match %s byte for byte.", #want, DISK)) else P(string.format("READ(10) WRONG: %d of %d bytes differ, first at +%d.", bad, #want, first)) end end end -- The second read, at a non-zero LBA. local rd2 = SP:read_u32(0x180E4) if rd2 ~= 0 then P(string.format("second scsi_read FAILED: err=%d (%s)", SP:read_u32(0x180EC), ERRNAME[SP:read_u32(0x180EC)] or "?")) else local f = io.open(DISK, "rb") if f then f:seek("set", 1000 * 512) local want = f:read(4 * 512); f:close() local bad = 0 for i = 1, #want do if SP:read_u8(0x28000 + i - 1) ~= string.byte(want, i) then bad = bad + 1 end end P(bad == 0 and string.format("READ(10) OK: %d B from LBA 1000 match too.", #want) or string.format("READ(10) WRONG at LBA 1000: %d of %d differ.", bad, #want)) end end P("done"); M:exit(); return end end) if not ok then P("LUA ERROR: "..tostring(err)); P("done"); M:exit() end end)