diff --git a/harness/mame/NETWORK_REPORT.md b/harness/mame/NETWORK_REPORT.md index a2d001b..eb28c78 100644 --- a/harness/mame/NETWORK_REPORT.md +++ b/harness/mame/NETWORK_REPORT.md @@ -4200,3 +4200,28 @@ observable on the panel (or in memory if the machine is still up). The CSR1/CSR2 from `0x23E7A0`, `INIT`, poll `IDON`, `STRT|INEA`), but on this run it did not bring the network back; the unit needed a power cycle. Fixing that is open work, not a blocker for the result above. + +### 61.4 The panel is now text, and the restore is instrumented + +Reading 16 white boxes off a photograph of the screen is error-prone, so the +payload now draws **labelled hex text** instead: + +``` +CSR0 7B3 TMD1 8300 MCNT 001C REST 0042 +CSR1 7B3 RMD1 0300 OK YES +``` + +A 5x7 glyph table (`0-9`, `A-F`, and the letters the labels need) is built **at +runtime** — this toolchain never runs `.cinit`, so a statically initialised table +would arrive as zeros, the same reason `harness/c-hello` builds its font in code. +Glyph pixels are 8 px wide (the VRAM write granularity) and 3 px tall, on a +32-pixel row pitch. + +`REST` is new: the CSR0 read back **after** handing the chip to the OS, so a +failed restore is visible rather than inferred. + +Note on verification: the panel coordinates and the 2048-byte VRAM stride come +from the real unit (they are the ones that displayed correctly there). MAME's +frame dump does **not** reproduce the panel — the OS repaints the screen +continuously there, and the real unit's VRAM layout differs slightly — so the +panel is verified on the machine, not from an emulator screenshot. diff --git a/harness/udpstream/build/lance.coff b/harness/udpstream/build/lance.coff index 24627e9..78ee53a 100644 Binary files a/harness/udpstream/build/lance.coff and b/harness/udpstream/build/lance.coff differ diff --git a/harness/udpstream/build/lance_fixlen.coff b/harness/udpstream/build/lance_fixlen.coff index c2b83af..231c3ac 100644 Binary files a/harness/udpstream/build/lance_fixlen.coff and b/harness/udpstream/build/lance_fixlen.coff differ diff --git a/harness/udpstream/lance.c b/harness/udpstream/lance.c index 71ff827..b2dd9e6 100644 --- a/harness/udpstream/lance.c +++ b/harness/udpstream/lance.c @@ -121,12 +121,126 @@ unsigned int reg; return v; } +/* ---- 5x7 text ------------------------------------------------------- + * Glyphs are built at runtime: this toolchain never runs .cinit, so a + * statically initialised table would arrive as zeros (same reason + * harness/c-hello builds its font in code). + */ +static unsigned char glyph[36][7]; +static unsigned char lab_csr0[5], lab_csr1[5], lab_tmd1[5], lab_rmd1[5]; +static unsigned char lab_mcnt[5], lab_rest[5], lab_ok[3], lab_yes[4], lab_no[3]; + +static unsigned int gi(ch) +unsigned int ch; +{ + if (ch >= '0' && ch <= '9') { + return ch - '0'; + } + return 10 + (ch - 'A'); +} + +static void fset(i, r0, r1, r2, r3, r4, r5, r6) +unsigned int i, r0, r1, r2, r3, r4, r5, r6; +{ + glyph[i][0] = r0; glyph[i][1] = r1; glyph[i][2] = r2; glyph[i][3] = r3; + glyph[i][4] = r4; glyph[i][5] = r5; glyph[i][6] = r6; +} + +static void build_font() +{ + fset(0, 0x0E,0x11,0x13,0x15,0x19,0x11,0x0E); /* 0 */ + fset(1, 0x04,0x0C,0x04,0x04,0x04,0x04,0x0E); /* 1 */ + fset(2, 0x0E,0x11,0x01,0x02,0x04,0x08,0x1F); /* 2 */ + fset(3, 0x1F,0x02,0x04,0x02,0x01,0x11,0x0E); /* 3 */ + fset(4, 0x02,0x06,0x0A,0x12,0x1F,0x02,0x02); /* 4 */ + fset(5, 0x1F,0x10,0x1E,0x01,0x01,0x11,0x0E); /* 5 */ + fset(6, 0x06,0x08,0x10,0x1E,0x11,0x11,0x0E); /* 6 */ + fset(7, 0x1F,0x01,0x02,0x04,0x08,0x08,0x08); /* 7 */ + fset(8, 0x0E,0x11,0x11,0x0E,0x11,0x11,0x0E); /* 8 */ + fset(9, 0x0E,0x11,0x11,0x0F,0x01,0x02,0x0C); /* 9 */ + fset(gi('A'), 0x0E,0x11,0x11,0x1F,0x11,0x11,0x11); + fset(gi('B'), 0x1E,0x11,0x11,0x1E,0x11,0x11,0x1E); + fset(gi('C'), 0x0E,0x11,0x10,0x10,0x10,0x11,0x0E); + fset(gi('D'), 0x1E,0x11,0x11,0x11,0x11,0x11,0x1E); + fset(gi('E'), 0x1F,0x10,0x10,0x1E,0x10,0x10,0x1F); + fset(gi('F'), 0x1F,0x10,0x10,0x1E,0x10,0x10,0x10); + fset(gi('K'), 0x11,0x12,0x14,0x18,0x14,0x12,0x11); + fset(gi('M'), 0x11,0x1B,0x15,0x15,0x11,0x11,0x11); + fset(gi('N'), 0x11,0x19,0x19,0x15,0x13,0x13,0x11); + fset(gi('O'), 0x0E,0x11,0x11,0x11,0x11,0x11,0x0E); + fset(gi('R'), 0x1E,0x11,0x11,0x1E,0x14,0x12,0x11); + fset(gi('S'), 0x0F,0x10,0x10,0x0E,0x01,0x01,0x1E); + fset(gi('T'), 0x1F,0x04,0x04,0x04,0x04,0x04,0x04); + fset(gi('Y'), 0x11,0x11,0x0A,0x04,0x04,0x04,0x04); +} + +static void put4(a, c0, c1, c2, c3) +unsigned char *a; +unsigned int c0, c1, c2, c3; +{ + a[0] = c0; a[1] = c1; a[2] = c2; a[3] = c3; a[4] = 0; +} + +static void draw_glyph(x, y, ch) +unsigned int x, y, ch; +{ + unsigned int r, c, row, idx; + + idx = gi(ch); + for (r = 0; r < 7; r++) { + row = glyph[idx][r]; + for (c = 0; c < 5; c++) { + if (row & (1 << (4 - c))) { + rect(x + c * 8, y + r * 3, 8, 3, 0xFF); + } + } + } +} + +static void draw_text(x, y, s) +unsigned int x, y; +unsigned char *s; +{ + while (*s) { + if (*s != ' ') { + draw_glyph(x, y, *s); + } + x = x + 48; + s = s + 1; + } +} + +static void hex4(x, y, v) +unsigned int x, y, v; +{ + unsigned int d, nib; + + for (d = 0; d < 4; d++) { + nib = (v >> ((3 - d) * 4)) & 0xF; + if (nib < 10) { + draw_glyph(x + d * 48, y, '0' + nib); + } else { + draw_glyph(x + d * 48, y, 'A' + nib - 10); + } + } +} + int main() { unsigned int i, r, idle, ok, rxmd1, txmd1, mcnt; unsigned int s0[2]; cell(0x000, 1); + build_font(); + put4(lab_csr0, 'C', 'S', 'R', '0'); + put4(lab_csr1, 'C', 'S', 'R', '1'); + put4(lab_tmd1, 'T', 'M', 'D', '1'); + put4(lab_rmd1, 'R', 'M', 'D', '1'); + put4(lab_mcnt, 'M', 'C', 'N', 'T'); + put4(lab_rest, 'R', 'E', 'S', 'T'); + lab_ok[0] = 'O'; lab_ok[1] = 'K'; lab_ok[2] = 0; + lab_yes[0] = 'Y'; lab_yes[1] = 'E'; lab_yes[2] = 'S'; lab_yes[3] = 0; + lab_no[0] = 'N'; lab_no[1] = 'O'; lab_no[2] = 0; dot(0); csr_w(0, CSR0_STOP); @@ -239,11 +353,17 @@ int main() cell(0x240, txmd1); cell(0x1A0, ok); - bits16(120, 670, s0[0]); - bits16(120, 700, s0[1]); - bits16(120, 730, txmd1); - bits16(120, 760, rxmd1); - bits16(120, 790, mcnt); + draw_text(104, 654, lab_csr0); hex4(312, 654, s0[0]); + draw_text(104, 686, lab_csr1); hex4(312, 686, s0[1]); + draw_text(104, 718, lab_tmd1); hex4(312, 718, txmd1); + draw_text(104, 750, lab_rmd1); hex4(312, 750, rxmd1); + draw_text(104, 782, lab_mcnt); hex4(312, 782, mcnt); + draw_text(104, 814, lab_ok); + if (ok) { + draw_text(312, 804, lab_yes); + } else { + draw_text(312, 804, lab_no); + } if (ok) { rect(120, 850, 24, 24, 0xFF); } @@ -251,24 +371,49 @@ int main() rect(160, 850, 24, 24, 0xFF); } - /* best effort: give the chip back to the OS */ + /* Give the chip back to the OS. + * + * The firmware's own init (io5800_5900_init, 0x3FDDCBE0) writes + * CSR0 = 0x7F41 = INIT | INEA | all status bits set (they are + * write-1-to-clear), then its caller polls IDON and writes + * 0x0042 = STRT | INEA. Match that exactly -- a plain INIT (0x0001) + * leaves INEA clear and the status bits latched, which is why the + * network did not come back on the first attempt. + */ { - unsigned int osblk; - osblk = *(unsigned int *)0x23E7A0; + unsigned int osblk, tries, csr0res; + + osblk = *(unsigned int *)0x23E7A0; /* init block, BYTE address */ + csr0res = 0; if (osblk != 0) { - csr_w(0, CSR0_STOP); - csr_w(1, osblk & 0xFFFF); - csr_w(2, (osblk >> 16) & 0xFF); - csr_w(3, 0); - csr_w(0, CSR0_INIT); - for (idle = 0; idle < 10000; idle++) { - r = csr_r(0); - if (r & CSR0_IDON) { + for (tries = 0; tries < 2; tries++) { + csr_w(0, CSR0_STOP); + for (idle = 0; idle < 200; idle++) { + } + csr_w(1, osblk & 0xFFFF); + csr_w(2, (osblk >> 16) & 0xFF); + csr_w(3, 0); + csr_w(0, 0x7F41); /* INIT | INEA, clear status */ + for (idle = 0; idle < 20000; idle++) { + r = csr_r(0); + if (r & CSR0_IDON) { + break; + } + } + csr_w(0, 0x0042); /* STRT | INEA */ + for (idle = 0; idle < 2000; idle++) { + } + csr0res = csr_r(0); + if (csr0res & 0x0010) { /* TXON: the chip is running */ break; } } - csr_w(0, 0x0042); + /* keep the driver's command shadow consistent with the chip */ + *(unsigned int *)0x23CC50 = 0x0042; } + cell(0x260, csr0res); /* CSR0 after the restore */ + cell(0x280, osblk); /* init block we handed back */ + draw_text(104, 846, lab_rest); hex4(312, 846, csr0res); } return 0; } diff --git a/harness/udpstream/lance_fixlen.c b/harness/udpstream/lance_fixlen.c index ea22923..c8b8ec5 100644 --- a/harness/udpstream/lance_fixlen.c +++ b/harness/udpstream/lance_fixlen.c @@ -121,12 +121,126 @@ unsigned int reg; return v; } +/* ---- 5x7 text ------------------------------------------------------- + * Glyphs are built at runtime: this toolchain never runs .cinit, so a + * statically initialised table would arrive as zeros (same reason + * harness/c-hello builds its font in code). + */ +static unsigned char glyph[36][7]; +static unsigned char lab_csr0[5], lab_csr1[5], lab_tmd1[5], lab_rmd1[5]; +static unsigned char lab_mcnt[5], lab_rest[5], lab_ok[3], lab_yes[4], lab_no[3]; + +static unsigned int gi(ch) +unsigned int ch; +{ + if (ch >= '0' && ch <= '9') { + return ch - '0'; + } + return 10 + (ch - 'A'); +} + +static void fset(i, r0, r1, r2, r3, r4, r5, r6) +unsigned int i, r0, r1, r2, r3, r4, r5, r6; +{ + glyph[i][0] = r0; glyph[i][1] = r1; glyph[i][2] = r2; glyph[i][3] = r3; + glyph[i][4] = r4; glyph[i][5] = r5; glyph[i][6] = r6; +} + +static void build_font() +{ + fset(0, 0x0E,0x11,0x13,0x15,0x19,0x11,0x0E); /* 0 */ + fset(1, 0x04,0x0C,0x04,0x04,0x04,0x04,0x0E); /* 1 */ + fset(2, 0x0E,0x11,0x01,0x02,0x04,0x08,0x1F); /* 2 */ + fset(3, 0x1F,0x02,0x04,0x02,0x01,0x11,0x0E); /* 3 */ + fset(4, 0x02,0x06,0x0A,0x12,0x1F,0x02,0x02); /* 4 */ + fset(5, 0x1F,0x10,0x1E,0x01,0x01,0x11,0x0E); /* 5 */ + fset(6, 0x06,0x08,0x10,0x1E,0x11,0x11,0x0E); /* 6 */ + fset(7, 0x1F,0x01,0x02,0x04,0x08,0x08,0x08); /* 7 */ + fset(8, 0x0E,0x11,0x11,0x0E,0x11,0x11,0x0E); /* 8 */ + fset(9, 0x0E,0x11,0x11,0x0F,0x01,0x02,0x0C); /* 9 */ + fset(gi('A'), 0x0E,0x11,0x11,0x1F,0x11,0x11,0x11); + fset(gi('B'), 0x1E,0x11,0x11,0x1E,0x11,0x11,0x1E); + fset(gi('C'), 0x0E,0x11,0x10,0x10,0x10,0x11,0x0E); + fset(gi('D'), 0x1E,0x11,0x11,0x11,0x11,0x11,0x1E); + fset(gi('E'), 0x1F,0x10,0x10,0x1E,0x10,0x10,0x1F); + fset(gi('F'), 0x1F,0x10,0x10,0x1E,0x10,0x10,0x10); + fset(gi('K'), 0x11,0x12,0x14,0x18,0x14,0x12,0x11); + fset(gi('M'), 0x11,0x1B,0x15,0x15,0x11,0x11,0x11); + fset(gi('N'), 0x11,0x19,0x19,0x15,0x13,0x13,0x11); + fset(gi('O'), 0x0E,0x11,0x11,0x11,0x11,0x11,0x0E); + fset(gi('R'), 0x1E,0x11,0x11,0x1E,0x14,0x12,0x11); + fset(gi('S'), 0x0F,0x10,0x10,0x0E,0x01,0x01,0x1E); + fset(gi('T'), 0x1F,0x04,0x04,0x04,0x04,0x04,0x04); + fset(gi('Y'), 0x11,0x11,0x0A,0x04,0x04,0x04,0x04); +} + +static void put4(a, c0, c1, c2, c3) +unsigned char *a; +unsigned int c0, c1, c2, c3; +{ + a[0] = c0; a[1] = c1; a[2] = c2; a[3] = c3; a[4] = 0; +} + +static void draw_glyph(x, y, ch) +unsigned int x, y, ch; +{ + unsigned int r, c, row, idx; + + idx = gi(ch); + for (r = 0; r < 7; r++) { + row = glyph[idx][r]; + for (c = 0; c < 5; c++) { + if (row & (1 << (4 - c))) { + rect(x + c * 8, y + r * 3, 8, 3, 0xFF); + } + } + } +} + +static void draw_text(x, y, s) +unsigned int x, y; +unsigned char *s; +{ + while (*s) { + if (*s != ' ') { + draw_glyph(x, y, *s); + } + x = x + 48; + s = s + 1; + } +} + +static void hex4(x, y, v) +unsigned int x, y, v; +{ + unsigned int d, nib; + + for (d = 0; d < 4; d++) { + nib = (v >> ((3 - d) * 4)) & 0xF; + if (nib < 10) { + draw_glyph(x + d * 48, y, '0' + nib); + } else { + draw_glyph(x + d * 48, y, 'A' + nib - 10); + } + } +} + int main() { unsigned int i, r, idle, ok, rxmd1, txmd1, mcnt; unsigned int s0[2]; cell(0x000, 1); + build_font(); + put4(lab_csr0, 'C', 'S', 'R', '0'); + put4(lab_csr1, 'C', 'S', 'R', '1'); + put4(lab_tmd1, 'T', 'M', 'D', '1'); + put4(lab_rmd1, 'R', 'M', 'D', '1'); + put4(lab_mcnt, 'M', 'C', 'N', 'T'); + put4(lab_rest, 'R', 'E', 'S', 'T'); + lab_ok[0] = 'O'; lab_ok[1] = 'K'; lab_ok[2] = 0; + lab_yes[0] = 'Y'; lab_yes[1] = 'E'; lab_yes[2] = 'S'; lab_yes[3] = 0; + lab_no[0] = 'N'; lab_no[1] = 'O'; lab_no[2] = 0; dot(0); csr_w(0, CSR0_STOP); @@ -239,11 +353,17 @@ int main() cell(0x240, txmd1); cell(0x1A0, ok); - bits16(120, 670, s0[0]); - bits16(120, 700, s0[1]); - bits16(120, 730, txmd1); - bits16(120, 760, rxmd1); - bits16(120, 790, mcnt); + draw_text(104, 654, lab_csr0); hex4(312, 654, s0[0]); + draw_text(104, 686, lab_csr1); hex4(312, 686, s0[1]); + draw_text(104, 718, lab_tmd1); hex4(312, 718, txmd1); + draw_text(104, 750, lab_rmd1); hex4(312, 750, rxmd1); + draw_text(104, 782, lab_mcnt); hex4(312, 782, mcnt); + draw_text(104, 814, lab_ok); + if (ok) { + draw_text(312, 804, lab_yes); + } else { + draw_text(312, 804, lab_no); + } if (ok) { rect(120, 850, 24, 24, 0xFF); } @@ -251,24 +371,49 @@ int main() rect(160, 850, 24, 24, 0xFF); } - /* best effort: give the chip back to the OS */ + /* Give the chip back to the OS. + * + * The firmware's own init (io5800_5900_init, 0x3FDDCBE0) writes + * CSR0 = 0x7F41 = INIT | INEA | all status bits set (they are + * write-1-to-clear), then its caller polls IDON and writes + * 0x0042 = STRT | INEA. Match that exactly -- a plain INIT (0x0001) + * leaves INEA clear and the status bits latched, which is why the + * network did not come back on the first attempt. + */ { - unsigned int osblk; - osblk = *(unsigned int *)0x23E7A0; + unsigned int osblk, tries, csr0res; + + osblk = *(unsigned int *)0x23E7A0; /* init block, BYTE address */ + csr0res = 0; if (osblk != 0) { - csr_w(0, CSR0_STOP); - csr_w(1, osblk & 0xFFFF); - csr_w(2, (osblk >> 16) & 0xFF); - csr_w(3, 0); - csr_w(0, CSR0_INIT); - for (idle = 0; idle < 10000; idle++) { - r = csr_r(0); - if (r & CSR0_IDON) { + for (tries = 0; tries < 2; tries++) { + csr_w(0, CSR0_STOP); + for (idle = 0; idle < 200; idle++) { + } + csr_w(1, osblk & 0xFFFF); + csr_w(2, (osblk >> 16) & 0xFF); + csr_w(3, 0); + csr_w(0, 0x7F41); /* INIT | INEA, clear status */ + for (idle = 0; idle < 20000; idle++) { + r = csr_r(0); + if (r & CSR0_IDON) { + break; + } + } + csr_w(0, 0x0042); /* STRT | INEA */ + for (idle = 0; idle < 2000; idle++) { + } + csr0res = csr_r(0); + if (csr0res & 0x0010) { /* TXON: the chip is running */ break; } } - csr_w(0, 0x0042); + /* keep the driver's command shadow consistent with the chip */ + *(unsigned int *)0x23CC50 = 0x0042; } + cell(0x260, csr0res); /* CSR0 after the restore */ + cell(0x280, osblk); /* init block we handed back */ + draw_text(104, 846, lab_rest); hex4(312, 846, csr0res); } return 0; }