diff --git a/harness/udpstream/build/lance_bcast.coff b/harness/udpstream/build/lance_bcast.coff new file mode 100644 index 0000000..c6ba0d9 Binary files /dev/null and b/harness/udpstream/build/lance_bcast.coff differ diff --git a/harness/udpstream/lance_bcast.c b/harness/udpstream/lance_bcast.c new file mode 100644 index 0000000..37ad5c7 --- /dev/null +++ b/harness/udpstream/lance_bcast.c @@ -0,0 +1,396 @@ +/* + * lance.c -- LANCE loopback probe using LOW-MEMORY rings. + * + * The OS's own init block (pointer at bit 0x23E7A0 -> byte 0xF80 on a live + * boot) puts its rings at byte 0x0A80 / 0x0E80 and stores only the LENGTH in + * the ring words' bits 13-15 (0xE000 / 0xA000), with no address bits above 16. + * MAME's model packs address bits 16+ into that word; if the real C-LANCE does + * not, a high ring address like 0x380028 is seen as 0x0028. This payload + * therefore places the block, rings and buffers below 64 KB. + * + * Memory used (BYTE addresses, well below 64 KB): + * 0x3000 init block (24 B) 0x3020 RX ring (8 * 8 B) 0x3060 TX ring (8 B) + * 0x3100 TX frame (24 B) 0x3200 RX buffer (2048 B) + * + * Result cells at 0x018C8000 (32-bit): 0x160/0x180 CSR0 samples, + * 0x200 RX RMD1, 0x220 RX MCNT, 0x240 TX TMD1, 0x1A0 payload-found flag. + * + * Panel rows (real unit, 256-byte stride): y 670/700 = CSR0, 730 = TMD1, + * 760 = RMD1, 790 = MCNT; blocks y 850: left = payload returned, right = TX done. + */ +#define RAP 0x05900000 +#define RDP 0x05800000 +#define MARK 0x018D0000 /* after .text (which now reaches 0x018CACD0) */ +#define VRAM_BASE 0x04000000 + +#define MODE_LOOP 0x0004 +#define MODE_INTL 0x0040 +#define CSR0_STOP 0x0004 +#define CSR0_STRT 0x0002 +#define CSR0_INIT 0x0001 +#define CSR0_TDMD 0x0008 +#define CSR0_IDON 0x0100 +#define RMD1_OWN 0x8000 +#define TMD1_OWN 0x8000 +#define TMD1_ENP 0x0100 +#define TMD1_STP 0x0200 + +#define B(byte) ((unsigned int)(byte) * 8) /* bit address of a byte */ +#define INITB B(0x3000) +#define RXR B(0x3020) +#define TXR B(0x3060) +#define RXBUF B(0x3200) +#define TXBUF B(0x3180) + +#define RING_ENTRIES 8 + +static void cell(off, v) +unsigned int off, v; +{ + *(unsigned int *)(MARK + off) = v; +} + +static void w16(bit, v) +unsigned int bit, v; +{ + *(unsigned short *)bit = v; +} + +static unsigned int r16(bit) +unsigned int bit; +{ + return *(unsigned short *)bit; +} + +static unsigned int rb(bit) +unsigned int bit; +{ + return *(unsigned char *)bit; +} + +static void wb(bit, v) +unsigned int bit, v; +{ + *(unsigned char *)bit = v; +} + +static void rect(x, y, w, h, v) +unsigned int x, y, w, h, v; +{ + unsigned int row, col; + for (row = 0; row < h; row++) { + for (col = 0; col < w; col = col + 8) { + *(unsigned char *)(VRAM_BASE + (y + row) * 2048 + x + col) = v; + } + } +} + +static void bits16(x, y, v) +unsigned int x, y, v; +{ + unsigned int b; + for (b = 0; b < 16; b++) { + rect(x + b * 30, y, 24, 24, (v & (1 << b)) ? 0xFF : 0x00); + } +} + +static void dot(n) +unsigned int n; +{ + rect(60, 650 + n * 44, 24, 24, 0xFF); +} + +static void settle() +{ + unsigned int i; + for (i = 0; i < 30; i++) { + } +} + +static void csr_w(reg, v) +unsigned int reg, v; +{ + *(unsigned short *)RAP = reg; + settle(); + *(unsigned short *)RDP = v; + settle(); +} + +static unsigned int csr_r(reg) +unsigned int reg; +{ + unsigned int v; + *(unsigned short *)RAP = reg; + settle(); + v = *(unsigned short *)RDP; + settle(); + 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, n, seen, lastet, txd, rxf, ok; + unsigned int m0, m1, m2, txlen; + + cell(0x000, 1); + build_font(); + put4(lab_csr0, 'T', 'X', 'D', ' '); + put4(lab_csr1, 'R', 'X', 'F', ' '); + put4(lab_tmd1, 'E', 'T', ' ', ' '); + put4(lab_rmd1, 'M', 'A', 'C', ' '); + put4(lab_mcnt, 'C', 'S', 'R', '0'); + put4(lab_rest, 'R', 'E', 'S', 'T'); + dot(0); + + /* black panel */ + rect(100, 650, 512, 256, 0x00); + rect(100, 650, 512, 4, 0xFF); + rect(100, 902, 512, 4, 0xFF); + rect(100, 650, 8, 256, 0xFF); + rect(608, 650, 8, 256, 0xFF); + + /* --- chip init: normal mode, our MAC, accept everything --- */ + csr_w(0, CSR0_STOP); + w16(INITB + 0 * 16, 0x8000); /* MODE: PROM, TX/RX enabled */ + w16(INITB + 1 * 16, 0x0008); /* PADR 08:00:2b:16:4b:5a */ + w16(INITB + 2 * 16, 0x162b); + w16(INITB + 3 * 16, 0x5a4b); + w16(INITB + 4 * 16, 0xFFFF); /* LADRF: all multicast */ + w16(INITB + 5 * 16, 0xFFFF); + w16(INITB + 6 * 16, 0xFFFF); + w16(INITB + 7 * 16, 0xFFFF); + w16(INITB + 8 * 16, (RXR >> 3) & 0xFFFF); + w16(INITB + 9 * 16, 3 << 13); /* 8 RX descriptors */ + w16(INITB + 10 * 16, (TXR >> 3) & 0xFFFF); + w16(INITB + 11 * 16, 3 << 13); /* 8 TX descriptors */ + + /* --- arm the 8 RX descriptors, each with its own 1600-byte buffer --- */ + for (i = 0; i < 8; i++) { + unsigned int buf; + buf = 0x4000 + i * 1600; + w16(RXR + i * 64 + 0, buf & 0xFFFF); + w16(RXR + i * 64 + 16, RMD1_OWN | ((buf >> 16) & 0xFF)); + w16(RXR + i * 64 + 32, 0xF9C0); /* -1600 */ + w16(RXR + i * 64 + 48, 0); + } + /* TX descriptors: idle, length set at transmit time */ + for (i = 0; i < 8; i++) { + w16(TXR + i * 64 + 0, (TXBUF >> 3) & 0xFFFF); + w16(TXR + i * 64 + 16, ((TXBUF >> 3) >> 16) & 0xFF); + w16(TXR + i * 64 + 32, 0xF000); + w16(TXR + i * 64 + 48, 0); + } + + csr_w(1, (INITB >> 3) & 0xFFFF); + csr_w(2, ((INITB >> 3) >> 16) & 0xFF); + csr_w(3, 0); + csr_w(0, 0x7F41); + for (idle = 0; idle < 20000; idle++) { + if (csr_r(0) & CSR0_IDON) { + break; + } + } + csr_w(0, 0x0042); /* STRT | INEA */ + dot(1); + + /* --- build a raw Ethernet broadcast frame (60 bytes, ethertype 0x88B5) --- */ + for (i = 0; i < 6; i++) { + wb(TXBUF + i * 8, 0xFF); /* dst: broadcast */ + } + wb(TXBUF + 6 * 8, 0x08); wb(TXBUF + 7 * 8, 0x00); + wb(TXBUF + 8 * 8, 0x2b); wb(TXBUF + 9 * 8, 0x16); + wb(TXBUF + 10 * 8, 0x4b); wb(TXBUF + 11 * 8, 0x5a); + wb(TXBUF + 12 * 8, 0x88); wb(TXBUF + 13 * 8, 0xB5); + for (i = 14; i < 60; i++) { + wb(TXBUF + i * 8, i); + } + txlen = 60; + dot(2); + + /* --- send 6 broadcasts, one every ~160k iterations --- */ + txd = 0; + for (n = 0; n < 6; n++) { + wb(TXBUF + 14 * 8, n); /* sequence byte */ + w16(TXR + 32, (0x10000 - txlen) & 0xFFFF); /* -len */ + w16(TXR + 16, TMD1_OWN | TMD1_STP | TMD1_ENP | (((TXBUF >> 3) >> 16) & 0xFF)); + csr_w(0, 0x0042 | CSR0_TDMD); /* STRT | INEA | TDMD */ + for (idle = 0; idle < 40000; idle++) { + if (!(r16(TXR + 16) & TMD1_OWN)) { + txd = txd + 1; + break; + } + } + for (idle = 0; idle < 120000; idle++) { + } + } + dot(3); + + /* --- listen: count what arrives, remember the last ethertype and MAC --- */ + rxf = 0; lastet = 0; m0 = 0; m1 = 0; m2 = 0; + for (idle = 0; idle < 400000; idle++) { + for (i = 0; i < 8; i++) { + unsigned int buf, len; + if (r16(RXR + i * 64 + 16) & RMD1_OWN) { + continue; + } + buf = 0x4000 + i * 1600; + len = r16(RXR + i * 64 + 48) & 0x0FFF; + if (len > 0) { + rxf = rxf + 1; + lastet = (rb(buf + 12) << 8) | rb(buf + 13); + m0 = (rb(buf + 6) << 8) | rb(buf + 7); + m1 = (rb(buf + 8) << 8) | rb(buf + 9); + m2 = (rb(buf + 10) << 8) | rb(buf + 11); + } + /* re-arm this descriptor */ + w16(RXR + i * 64 + 16, RMD1_OWN | ((buf >> 16) & 0xFF)); + } + } + dot(4); + + /* --- panel --- */ + ok = 1; cell(0x1A0, ok); + cell(0x160, txd); cell(0x180, rxf); cell(0x200, lastet); cell(0x220, m0); + draw_text(104, 654, lab_csr0); hex4(312, 654, txd); /* TXD */ + draw_text(104, 686, lab_csr1); hex4(312, 686, rxf); /* RXF */ + draw_text(104, 718, lab_tmd1); hex4(312, 718, lastet); /* ET */ + draw_text(104, 750, lab_rmd1); + hex4(312, 750, m0); hex4(384, 750, m1); hex4(456, 750, m2); /* MAC */ + draw_text(104, 782, lab_mcnt); hex4(312, 782, csr_r(0)); /* CSR0 */ + + /* give the chip back to the OS */ + { + unsigned int osblk, tries, csr0res; + osblk = *(unsigned int *)0x23E7A0; + csr0res = 0; + if (osblk != 0) { + 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); + for (idle = 0; idle < 20000; idle++) { + if (csr_r(0) & CSR0_IDON) { + break; + } + } + csr_w(0, 0x0042); + for (idle = 0; idle < 2000; idle++) { + } + csr0res = csr_r(0); + if (csr0res & 0x0010) { + break; + } + } + } + draw_text(104, 814, lab_rest); hex4(312, 814, csr0res); + } + return 0; +}