udpstream: lance_bcast -- raw Ethernet broadcast TX + RX with no ROM code

Normal (promiscuous) mode instead of loopback: programs its own init block,
PADR and LADRF, arms eight RX descriptors, transmits six 60-byte broadcast
frames (ethertype 0x88B5) through its own TX ring with TDMD kicks, then counts
received frames and records the last source MAC and ethertype.

Everything is the payload's own code -- CSR accesses, init block, rings,
descriptors, DMA results. Panel: TXD (transmitted), RXF (received), ET (last
ethertype), MAC (last source), CSR0, REST.
This commit is contained in:
arti committed 2026-10-30 16:05:31 +02:00
1 parent e3d04d6459
commit dfc968e906
2 files changed
+396

No files matched your search

Binary file not shown.
+396
View File
@@ -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;
}