First Commit of my working state
[simh.git] / PDP11 / pdp11_xu.c
1 /* pdp11_xu.c: DEUNA/DELUA ethernet controller simulator
2 ------------------------------------------------------------------------------
3
4 Copyright (c) 2003-2007, David T. Hittner
5
6 Permission is hereby granted, free of charge, to any person obtaining a
7 copy of this software and associated documentation files (the "Software"),
8 to deal in the Software without restriction, including without limitation
9 the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 and/or sell copies of the Software, and to permit persons to whom the
11 Software is furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
23 Except as contained in this notice, the name of the author shall not be
24 used in advertising or otherwise to promote the sale, use or other dealings
25 in this Software without prior written authorization from the author.
26
27 ------------------------------------------------------------------------------
28
29 This DEUNA/DELUA simulation is based on:
30 Digital DELUA Users Guide, Part# EK-DELUA-UG-002
31 Digital DEUNA Users Guide, Part# EK-DEUNA-UG-001
32 These manuals can be found online at:
33 http://www.spies.com/~aek/pdf/dec/unibus
34
35 Testing performed:
36 1) Receives/Transmits single packet under custom RSX driver
37 2) Passes RSTS 10.1 controller probe diagnostics during boot
38 3) VMS 7.2 on VAX780 summary:
39 (May/2007: WinXP x64 host; MS VC++ 2005; SIMH v3.7-0 base; WinPcap 4.0)
40 LAT - SET HOST/LAT in/out
41 DECNET - SET HOST in/out, COPY in/out
42 TCP/IP - PING in/out; SET HOST/TELNET in/out, COPY/FTP in/out
43 Clustering - Successfully clustered with AlphaVMS 8.2
44 4) Runs VAX EVDWA diagnostic tests 1-10; tests 11-19 (M68000/ROM/RAM) fail
45
46 Known issues:
47 1) Most auxiliary commands are not implemented yet.
48 2) System_ID broadcast is not implemented.
49 3) There are residual Map_ReadB and Map_WriteB from the FvK version that
50 probably need to be converted to Map_ReadW and Map_WriteW calls.
51 4) Some jerkiness seen during interactive I/O with remote systems;
52 this is probably attributable to changed polling times from when
53 the poll duration was standardized for idling support.
54
55 ------------------------------------------------------------------------------
56
57 Modification history:
58
59 18-Jun-07 RMS Added UNIT_IDLE flag
60 03-May-07 DTH Added missing FC_RMAL command; cleared multicast on write
61 29-Oct-06 RMS Synced poll and clock
62 08-Dec-05 DTH Implemented ancilliary functions 022/023/024/025
63 18-Nov-05 DTH Corrected time between system ID packets
64 07-Sep-05 DTH Corrected runt packet processing (found by Tim Chapman),
65 Removed unused variable
66 16-Aug-05 RMS Fixed C++ declaration and cast problems
67 10-Mar-05 RMS Fixed equality test in RCSTAT (from Mark Hittinger)
68 16-Jan-04 DTH Added more info to SHOW MOD commands
69 09-Jan-04 DTH Made XU floating address so that XUB will float correctly
70 08-Jan-04 DTH Added system_id message
71 06-Jan-04 DTH Added protection against changing mac and type if attached
72 05-Jan-04 DTH Moved most of xu_setmac to sim_ether
73 Implemented auxiliary function 12/13
74 Added SET/SHOW XU STATS
75 31-Dec-03 DTH RSTS 10.1 accepts controller during boot tests
76 Implemented chained buffers in transmit/receive processing
77 29-Dec-03 DTH Primitive RSX packet sending succeeds
78 23-Dec-03 DTH Implemented write function
79 17-Dec-03 DTH Implemented read function
80 05-May-03 DTH Started XU simulation -
81 core logic pirated from unreleased FvK PDP10 variant
82
83 ------------------------------------------------------------------------------
84 */
85
86 #include "pdp11_xu.h"
87
88 extern int32 tmxr_poll, tmr_poll, clk_tps, cpu_astop;
89 extern FILE *sim_log;
90
91 t_stat xu_rd(int32* data, int32 PA, int32 access);
92 t_stat xu_wr(int32 data, int32 PA, int32 access);
93 t_stat xu_svc(UNIT * uptr);
94 t_stat xu_reset (DEVICE * dptr);
95 t_stat xu_attach (UNIT * uptr, char * cptr);
96 t_stat xu_detach (UNIT * uptr);
97 t_stat xu_showmac (FILE* st, UNIT* uptr, int32 val, void* desc);
98 t_stat xu_setmac (UNIT* uptr, int32 val, char* cptr, void* desc);
99 t_stat xu_show_stats (FILE* st, UNIT* uptr, int32 val, void* desc);
100 t_stat xu_set_stats (UNIT* uptr, int32 val, char* cptr, void* desc);
101 t_stat xu_show_type (FILE* st, UNIT* uptr, int32 val, void* desc);
102 t_stat xu_set_type (UNIT* uptr, int32 val, char* cptr, void* desc);
103 int32 xu_int (void);
104 t_stat xu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
105 t_stat xu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
106 void xua_read_callback(int status);
107 void xub_read_callback(int status);
108 void xua_write_callback(int status);
109 void xub_write_callback(int status);
110 void xu_setint (CTLR* xu);
111 void xu_clrint (CTLR* xu);
112 void xu_process_receive(CTLR* xu);
113 void xu_dump_rxring(CTLR* xu);
114 void xu_dump_txring(CTLR* xu);
115
116 DIB xua_dib = { IOBA_XU, IOLN_XU, &xu_rd, &xu_wr,
117 1, IVCL (XU), VEC_XU, {&xu_int} };
118
119 UNIT xua_unit[] = {
120 { UDATA (&xu_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE, 0) } /* receive timer */
121 };
122
123 struct xu_device xua = {
124 xua_read_callback, /* read callback routine */
125 xua_write_callback, /* write callback routine */
126 {0x08, 0x00, 0x2B, 0xCC, 0xDD, 0xEE}, /* mac */
127 XU_T_DELUA /* type */
128 };
129
130 MTAB xu_mod[] = {
131 #if defined (VM_PDP11)
132 { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS",
133 &set_addr, &show_addr, NULL },
134 #else
135 { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", NULL,
136 NULL, &show_addr, NULL },
137 #endif
138 { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL,
139 NULL, &show_vec, NULL },
140 { MTAB_XTD | MTAB_VDV, 0, "MAC", "MAC=xx:xx:xx:xx:xx:xx",
141 &xu_setmac, &xu_showmac, NULL },
142 { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "ETH", "ETH",
143 NULL, &eth_show, NULL },
144 { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATS", "STATS",
145 &xu_set_stats, &xu_show_stats, NULL },
146 { MTAB_XTD | MTAB_VDV, 0, "TYPE", "TYPE={DEUNA|DELUA}",
147 &xu_set_type, &xu_show_type, NULL },
148 { 0 },
149 };
150
151 REG xua_reg[] = {
152 { NULL } };
153
154 DEBTAB xu_debug[] = {
155 {"TRACE", DBG_TRC},
156 {"WARN", DBG_WRN},
157 {"REG", DBG_REG},
158 {"PACKET", DBG_PCK},
159 {"ETH", DBG_ETH},
160 {0}
161 };
162
163
164 DEVICE xu_dev = {
165 "XU", xua_unit, xua_reg, xu_mod,
166 1, XU_RDX, 8, 1, XU_RDX, 8,
167 &xu_ex, &xu_dep, &xu_reset,
168 NULL, &xu_attach, &xu_detach,
169 &xua_dib, DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_DEBUG,
170 0, xu_debug
171 };
172
173
174 /* XUB does not exist in the PDP10 simulation */
175 #if defined(IOBA_XUB)
176
177 DIB xub_dib = { IOBA_XUB, IOLN_XUB, &xu_rd, &xu_wr,
178 1, IVCL (XU), 0, { &xu_int } };
179
180 UNIT xub_unit[] = {
181 { UDATA (&xu_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE, 0) } /* receive timer */
182 };
183
184 struct xu_device xub = {
185 xub_read_callback, /* read callback routine */
186 xub_write_callback, /* write callback routine */
187 {0x08, 0x00, 0x2B, 0xDD, 0xEE, 0xFF}, /* mac */
188 XU_T_DELUA /* type */
189 };
190
191 REG xub_reg[] = {
192 { NULL } };
193
194 DEVICE xub_dev = {
195 "XUB", xub_unit, xub_reg, xu_mod,
196 1, XU_RDX, 8, 1, XU_RDX, 8,
197 &xu_ex, &xu_dep, &xu_reset,
198 NULL, &xu_attach, &xu_detach,
199 &xub_dib, DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_DEBUG,
200 0, xu_debug
201 };
202
203 #define XU_MAX_CONTROLLERS 2
204 CTLR xu_ctrl[] = {
205 {&xu_dev, xua_unit, &xua_dib, &xua} /* XUA controller */
206 ,{&xub_dev, xub_unit, &xub_dib, &xub} /* XUB controller */
207 };
208 #else /* IOBA_XUB */
209 #define XU_MAX_CONTROLLERS 1
210 CTLR xu_ctrl[] = {
211 {&xu_dev, xua_unit, &xua_dib, &xua} /* XUA controller */
212 };
213 #endif /* IOBA_XUB */
214
215 /*============================================================================*/
216
217 /* Multicontroller support */
218
219 CTLR* xu_unit2ctlr(UNIT* uptr)
220 {
221 int i;
222 unsigned int j;
223 for (i=0; i<XU_MAX_CONTROLLERS; i++)
224 for (j=0; j<xu_ctrl[i].dev->numunits; j++)
225 if (&xu_ctrl[i].unit[j] == uptr)
226 return &xu_ctrl[i];
227 /* not found */
228 return 0;
229 }
230
231 CTLR* xu_dev2ctlr(DEVICE* dptr)
232 {
233 int i;
234 for (i=0; i<XU_MAX_CONTROLLERS; i++)
235 if (xu_ctrl[i].dev == dptr)
236 return &xu_ctrl[i];
237 /* not found */
238 return 0;
239 }
240
241 CTLR* xu_pa2ctlr(uint32 PA)
242 {
243 int i;
244 for (i=0; i<XU_MAX_CONTROLLERS; i++)
245 if ((PA >= xu_ctrl[i].dib->ba) && (PA < (xu_ctrl[i].dib->ba + xu_ctrl[i].dib->lnt)))
246 return &xu_ctrl[i];
247 /* not found */
248 return 0;
249 }
250
251 /*============================================================================*/
252
253 /* stop simh from reading non-existant unit data stream */
254 t_stat xu_ex (t_value* vptr, t_addr addr, UNIT* uptr, int32 sw)
255 {
256 return SCPE_NOFNC;
257 }
258
259 /* stop simh from writing non-existant unit data stream */
260 t_stat xu_dep (t_value val, t_addr addr, UNIT* uptr, int32 sw)
261 {
262 return SCPE_NOFNC;
263 }
264
265 t_stat xu_showmac (FILE* st, UNIT* uptr, int32 val, void* desc)
266 {
267 CTLR* xu = xu_unit2ctlr(uptr);
268 char buffer[20];
269
270 eth_mac_fmt((ETH_MAC*)xu->var->mac, buffer);
271 fprintf(st, "MAC=%s", buffer);
272 return SCPE_OK;
273 }
274
275 t_stat xu_setmac (UNIT* uptr, int32 val, char* cptr, void* desc)
276 {
277 t_stat status;
278 CTLR* xu = xu_unit2ctlr(uptr);
279
280 if (!cptr) return SCPE_IERR;
281 if (uptr->flags & UNIT_ATT) return SCPE_ALATT;
282 status = eth_mac_scan(&xu->var->mac, cptr);
283 return status;
284 }
285
286 t_stat xu_set_stats (UNIT* uptr, int32 val, char* cptr, void* desc)
287 {
288 CTLR* xu = xu_unit2ctlr(uptr);
289
290 /* set stats to zero, regardless of passed parameter */
291 memset(&xu->var->stats, 0, sizeof(struct xu_stats));
292 return SCPE_OK;
293 }
294
295 t_stat xu_show_stats (FILE* st, UNIT* uptr, int32 val, void* desc)
296 {
297 char* fmt = " %-24s%d\n";
298 CTLR* xu = xu_unit2ctlr(uptr);
299 struct xu_stats* stats = &xu->var->stats;
300
301 fprintf(st, "Ethernet statistics:\n");
302 fprintf(st, fmt, "Seconds since cleared:", stats->secs);
303 fprintf(st, fmt, "Recv frames:", stats->frecv);
304 fprintf(st, fmt, "Recv dbytes:", stats->rbytes);
305 fprintf(st, fmt, "Xmit frames:", stats->ftrans);
306 fprintf(st, fmt, "Xmit dbytes:", stats->tbytes);
307 fprintf(st, fmt, "Recv frames(multicast):", stats->mfrecv);
308 fprintf(st, fmt, "Recv dbytes(multicast):", stats->mrbytes);
309 fprintf(st, fmt, "Xmit frames(multicast):", stats->mftrans);
310 fprintf(st, fmt, "Xmit dbytes(multicast):", stats->mtbytes);
311 return SCPE_OK;
312 }
313
314 t_stat xu_show_type (FILE* st, UNIT* uptr, int32 val, void* desc)
315 {
316 CTLR* xu = xu_unit2ctlr(uptr);
317 fprintf(st, "type=");
318 switch (xu->var->type) {
319 case XU_T_DEUNA: fprintf(st, "DEUNA"); break;
320 case XU_T_DELUA: fprintf(st, "DELUA"); break;
321 }
322 return SCPE_OK;
323 }
324
325 t_stat xu_set_type (UNIT* uptr, int32 val, char* cptr, void* desc)
326 {
327 CTLR* xu = xu_unit2ctlr(uptr);
328 if (!cptr) return SCPE_IERR;
329 if (uptr->flags & UNIT_ATT) return SCPE_ALATT;
330
331 /* this assumes that the parameter has already been upcased */
332 if (!strcmp(cptr, "DEUNA")) xu->var->type = XU_T_DEUNA;
333 else if (!strcmp(cptr, "DELUA")) xu->var->type = XU_T_DELUA;
334 else return SCPE_ARG;
335
336 return SCPE_OK;
337 }
338
339 /*============================================================================*/
340
341 void upd_stat16(uint16* stat, uint16 add)
342 {
343 *stat += add;
344 /* did stat roll over? latches at maximum */
345 if (*stat < add)
346 *stat = 0xFFFF;
347 }
348
349 void upd_stat32(uint32* stat, uint32 add)
350 {
351 *stat += add;
352 /* did stat roll over? latches at maximum */
353 if (*stat < add)
354 *stat = 0xFFFFFFFF;
355 }
356
357 void bit_stat16(uint16* stat, uint16 bits)
358 {
359 *stat |= bits;
360 }
361
362 t_stat xu_process_local (CTLR* xu, ETH_PACK* pack)
363 {
364 return SCPE_NOFNC; /* not implemented yet */
365 }
366
367 void xu_read_callback(CTLR* xu, int status)
368 {
369 /* process any packets locally that can be */
370 status = xu_process_local (xu, &xu->var->read_buffer);
371
372 /* add packet to read queue */
373 if (status != SCPE_OK)
374 ethq_insert(&xu->var->ReadQ, 2, &xu->var->read_buffer, 0);
375 }
376
377 void xua_read_callback(int status)
378 {
379 xu_read_callback(&xu_ctrl[0], status);
380 }
381
382 void xub_read_callback(int status)
383 {
384 xu_read_callback(&xu_ctrl[1], status);
385 }
386
387 t_stat xu_system_id (CTLR* xu, const ETH_MAC dest, uint16 receipt_id)
388 {
389 static uint16 receipt = 0;
390 ETH_PACK system_id;
391 uint8* const msg = &system_id.msg[0];
392 t_stat status;
393
394 sim_debug(DBG_TRC, xu->dev, "xu_system_id()\n");
395 memset (&system_id, 0, sizeof(system_id));
396 memcpy (&msg[0], dest, sizeof(ETH_MAC));
397 memcpy (&msg[6], xu->var->setup.macs[0], sizeof(ETH_MAC));
398 msg[12] = 0x60; /* type */
399 msg[13] = 0x02; /* type */
400 msg[14] = 0x1C; /* character count */
401 msg[15] = 0x00; /* character count */
402 msg[16] = 0x07; /* code */
403 msg[17] = 0x00; /* zero pad */
404 if (receipt_id) {
405 msg[18] = receipt_id & 0xFF; /* receipt number */
406 msg[19] = (receipt_id >> 8) & 0xFF; /* receipt number */
407 } else {
408 msg[18] = receipt & 0xFF; /* receipt number */
409 msg[19] = (receipt++ >> 8) & 0xFF; /* receipt number */
410 }
411
412 /* MOP VERSION */
413 msg[20] = 0x01; /* type */
414 msg[21] = 0x00; /* type */
415 msg[22] = 0x03; /* length */
416 msg[23] = 0x03; /* version */
417 msg[24] = 0x00; /* eco */
418 msg[25] = 0x00; /* user eco */
419
420 /* FUNCTION */
421 msg[26] = 0x02; /* type */
422 msg[27] = 0x00; /* type */
423 msg[28] = 0x02; /* length */
424 msg[29] = 0x05; /* value 1 */
425 msg[30] = 0x00; /* value 2 */
426
427 /* HARDWARE ADDRESS */
428 msg[31] = 0x07; /* type */
429 msg[32] = 0x00; /* type */
430 msg[33] = 0x06; /* length */
431 memcpy (&msg[34], xu->var->mac, sizeof(ETH_MAC)); /* ROM address */
432
433 /* DEVICE TYPE */
434 msg[40] = 0x64; /* type */
435 msg[41] = 0x00; /* type */
436 msg[42] = 0x01; /* length */
437 if (xu->var->type == XU_T_DEUNA)
438 msg[43] = 1; /* value (1=DEUNA) */
439 else
440 msg[43] = 11; /* value (11=DELUA) */
441
442 /* write system id */
443 system_id.len = 60;
444 status = eth_write(xu->var->etherface, &system_id, NULL);
445
446 return status;
447 }
448
449 t_stat xu_svc(UNIT* uptr)
450 {
451 int queue_size;
452 t_stat status;
453 CTLR* xu = xu_unit2ctlr(uptr);
454 const ETH_MAC mop_multicast = {0xAB, 0x00, 0x00, 0x02, 0x00, 0x00};
455 const int one_second = clk_tps * tmr_poll;
456
457 /* First pump any queued packets into the system */
458 if ((xu->var->ReadQ.count > 0) && ((xu->var->pcsr1 & PCSR1_STATE) == STATE_RUNNING))
459 xu_process_receive(xu);
460
461 /* Now read and queue packets that have arrived */
462 /* This is repeated as long as they are available and we have room */
463 do
464 {
465 queue_size = xu->var->ReadQ.count;
466 /* read a packet from the ethernet - processing is via the callback */
467 status = eth_read (xu->var->etherface, &xu->var->read_buffer, xu->var->rcallback);
468 } while (queue_size != xu->var->ReadQ.count);
469
470 /* Now pump any still queued packets into the system */
471 if ((xu->var->ReadQ.count > 0) && ((xu->var->pcsr1 & PCSR1_STATE) == STATE_RUNNING))
472 xu_process_receive(xu);
473
474 /* send identity packet when timer expires */
475 if (--xu->var->idtmr <= 0) {
476 if ((xu->var->mode & MODE_DMNT) == 0) /* if maint msg is not disabled */
477 status = xu_system_id(xu, mop_multicast, 0); /* then send ID packet */
478 xu->var->idtmr = XU_ID_TIMER_VAL * one_second; /* reset timer */
479 }
480
481 /* has one second timer expired? if so, update stats and reset timer */
482 if (++xu->var->sectmr >= XU_SERVICE_INTERVAL) {
483 upd_stat16 (&xu->var->stats.secs, 1);
484 xu->var->sectmr = 0;
485 }
486
487 /* resubmit service timer if controller not halted */
488 switch (xu->var->pcsr1 & PCSR1_STATE) {
489 case STATE_READY:
490 case STATE_RUNNING:
491 sim_activate(&xu->unit[0], tmxr_poll);
492 break;
493 };
494
495 return SCPE_OK;
496 }
497
498 void xu_write_callback (CTLR* xu, int status)
499 {
500 xu->var->write_buffer.status = status;
501 }
502
503 void xua_write_callback (int status)
504 {
505 xu_write_callback(&xu_ctrl[0], status);
506 }
507
508 void xub_write_callback (int status)
509 {
510 xu_write_callback(&xu_ctrl[1], status);
511 }
512
513 void xu_setclrint(CTLR* xu, int32 bits)
514 {
515 if (xu->var->pcsr0 & 0xFF00) { /* if any interrupt bits on, */
516 xu->var->pcsr0 |= PCSR0_INTR; /* turn master bit on */
517 xu_setint(xu); /* and trigger interrupt */
518 } else {
519 xu->var->pcsr0 &= ~PCSR0_INTR; /* ... or off */
520 xu_clrint(xu); /* and clear interrupt if needed*/
521 }
522 }
523
524 t_stat xu_sw_reset (CTLR* xu)
525 {
526 t_stat status;
527
528 sim_debug(DBG_TRC, xu->dev, "xu_sw_reset()\n");
529
530 /* Clear the registers. */
531 xu->var->pcsr0 = PCSR0_DNI | PCSR0_INTR;
532 xu->var->pcsr1 = STATE_READY;
533 switch (xu->var->type) {
534 case XU_T_DELUA:
535 xu->var->pcsr1 |= TYPE_DELUA;
536 break;
537 case XU_T_DEUNA:
538 xu->var->pcsr1 |= TYPE_DEUNA;
539 if (!xu->var->etherface) /* if not attached, set transceiver powerfail */
540 xu->var->pcsr1 |= PCSR1_XPWR;
541 break;
542 }
543 xu->var->pcsr2 = 0;
544 xu->var->pcsr3 = 0;
545
546 /* Clear the parameters. */
547 xu->var->mode = 0;
548 xu->var->pcbb = 0;
549 xu->var->stat = 0;
550
551 /* clear read queue */
552 ethq_clear(&xu->var->ReadQ);
553
554 /* clear setup info */
555 memset(&xu->var->setup, 0, sizeof(struct xu_setup));
556
557 /* clear network statistics */
558 memset(&xu->var->stats, 0, sizeof(struct xu_stats));
559
560 /* reset ethernet interface */
561 memcpy (xu->var->setup.macs[0], xu->var->mac, sizeof(ETH_MAC));
562 xu->var->setup.mac_count = 1;
563 if (xu->var->etherface)
564 status = eth_filter (xu->var->etherface, xu->var->setup.mac_count,
565 &xu->var->mac, xu->var->setup.multicast,
566 xu->var->setup.promiscuous);
567
568 /* activate device if not disabled */
569 if ((xu->dev->flags & DEV_DIS) == 0) {
570 sim_activate_abs(&xu->unit[0], clk_cosched (tmxr_poll));
571 }
572
573 /* clear load_server address */
574 memset(xu->var->load_server, 0, sizeof(ETH_MAC));
575
576 return SCPE_OK;
577 }
578
579 /* Reset device. */
580 t_stat xu_reset(DEVICE* dptr)
581 {
582 t_stat status;
583 CTLR* xu = xu_dev2ctlr(dptr);
584
585 sim_debug(DBG_TRC, xu->dev, "xu_reset()\n");
586 /* init read queue (first time only) */
587 status = ethq_init (&xu->var->ReadQ, XU_QUE_MAX);
588 if (status != SCPE_OK)
589 return status;
590
591 /* software reset controller */
592 xu_sw_reset(xu);
593
594 return SCPE_OK;
595 }
596
597
598 /* Perform one of the defined ancillary functions. */
599 int32 xu_command(CTLR* xu)
600 {
601 uint32 udbb;
602 int fnc, mtlen, i, j;
603 uint16 value, pltlen;
604 t_stat status, rstatus, wstatus, wstatus2, wstatus3;
605 struct xu_stats* stats = &xu->var->stats;
606 uint16* udb = xu->var->udb;
607 uint16* mac_w = (uint16*) xu->var->mac;
608 static const ETH_MAC zeros = {0,0,0,0,0,0};
609 static const ETH_MAC mcast_load_server = {0xAB, 0x00, 0x00, 0x01, 0x00, 0x00};
610 static char* command[] = {
611 "NO-OP",
612 "Start Microaddress",
613 "Read Default Physical Address",
614 "NO-OP",
615 "Read Physical Address",
616 "Write Physical Address",
617 "Read Multicast Address List",
618 "Write Multicast Address List",
619 "Read Descriptor Ring Format",
620 "Write Descriptor Ring Format",
621 "Read Counters",
622 "Read/Clear Counters",
623 "Read Mode Register",
624 "Write Mode Register",
625 "Read Status",
626 "Read/Clear Status",
627 "Dump Internal Memory",
628 "Load Internal Memory",
629 "Read System ID",
630 "Write System ID",
631 "Read Load Server Address",
632 "Write Load Server Address"
633 };
634
635 /* Grab the PCB from the host. */
636 rstatus = Map_ReadW(xu->var->pcbb, 8, xu->var->pcb);
637 if (rstatus != 0)
638 return PCSR0_PCEI + 1;
639
640 /* High 8 bits are defined as MBZ. */
641 if (xu->var->pcb[0] & 0177400)
642 return PCSR0_PCEI;
643
644 /* Decode the function to be performed. */
645 fnc = xu->var->pcb[0] & 0377;
646 sim_debug(DBG_TRC, xu->dev, "xu_command(), Command: %s [0%o]\n", command[fnc], fnc);
647
648 switch (fnc) {
649 case FC_NOOP:
650 break;
651
652 case FC_RDPA: /* read default physical address */
653 wstatus = Map_WriteB(xu->var->pcbb + 2, 6, xu->var->mac);
654 if (wstatus)
655 return PCSR0_PCEI + 1;
656 break;
657
658 case FC_RPA: /* read current physical address */
659 wstatus = Map_WriteB(xu->var->pcbb + 2, 6, (uint8*)&xu->var->setup.macs[0]);
660 if (wstatus)
661 return PCSR0_PCEI + 1;
662 break;
663
664 case FC_WPA: /* write current physical address */
665 rstatus = Map_ReadB(xu->var->pcbb + 2, 6, (uint8*)&xu->var->setup.macs[0]);
666 if (xu->var->pcb[1] & 1)
667 return PCSR0_PCEI;
668 break;
669
670 case FC_RMAL: /* read multicast address list */
671 mtlen = (xu->var->pcb[2] & 0xFF00) >> 8;
672 udbb = xu->var->pcb[1] | ((xu->var->pcb[2] & 03) << 16);
673 wstatus = Map_WriteB(udbb, mtlen * 3, (uint8*) &xu->var->setup.macs[1]);
674 break;
675
676 case FC_WMAL: /* write multicast address list */
677 mtlen = (xu->var->pcb[2] & 0xFF00) >> 8;
678 sim_debug(DBG_TRC, xu->dev, "FC_WAL: mtlen=%d\n", mtlen);
679 if (mtlen > 10)
680 return PCSR0_PCEI;
681 udbb = xu->var->pcb[1] | ((xu->var->pcb[2] & 03) << 16);
682 /* clear existing multicast list */
683 for (i=1; i<XU_FILTER_MAX; i++) {
684 for (j=0; j<6; j++)
685 xu->var->setup.macs[i][j] = 0;
686 }
687 /* get multicast list from host */
688 rstatus = Map_ReadB(udbb, mtlen * 6, (uint8*) &xu->var->setup.macs[1]);
689 if (rstatus == 0) {
690 xu->var->setup.mac_count = mtlen + 1;
691 status = eth_filter (xu->var->etherface, xu->var->setup.mac_count,
692 xu->var->setup.macs, xu->var->setup.multicast,
693 xu->var->setup.promiscuous);
694 } else {
695 xu->var->pcsr0 |= PCSR0_PCEI;
696 }
697 break;
698
699 case FC_RRF: /* read ring format */
700 if ((xu->var->pcb[1] & 1) || (xu->var->pcb[2] & 0374))
701 return PCSR0_PCEI;
702 xu->var->udb[0] = xu->var->tdrb & 0177776;
703 xu->var->udb[1] = (xu->var->telen << 8) + ((xu->var->tdrb >> 16) & 3);
704 xu->var->udb[2] = xu->var->trlen;
705 xu->var->udb[3] = xu->var->rdrb & 0177776;
706 xu->var->udb[4] = (xu->var->relen << 8) + ((xu->var->rdrb >> 16) & 3);
707 xu->var->udb[5] = xu->var->rrlen;
708
709 /* Write UDB to host memory. */
710 udbb = xu->var->pcb[1] + ((xu->var->pcb[2] & 3) << 16);
711 wstatus = Map_WriteW(udbb, 12, xu->var->pcb);
712 if (wstatus != 0)
713 return PCSR0_PCEI+1;
714 break;
715
716 case FC_WRF: /* write ring format */
717 if ((xu->var->pcb[1] & 1) || (xu->var->pcb[2] & 0374))
718 return PCSR0_PCEI;
719 if ((xu->var->pcsr1 & PCSR1_STATE) == STATE_RUNNING)
720 return PCSR0_PCEI;
721
722 /* Read UDB into local memory. */
723 udbb = xu->var->pcb[1] + ((xu->var->pcb[2] & 3) << 16);
724 rstatus = Map_ReadW(udbb, 12, xu->var->udb);
725 if (rstatus)
726 return PCSR0_PCEI+1;
727
728 if ((xu->var->udb[0] & 1) || (xu->var->udb[1] & 0374) ||
729 (xu->var->udb[3] & 1) || (xu->var->udb[4] & 0374) ||
730 (xu->var->udb[5] < 2)) {
731 return PCSR0_PCEI;
732 }
733
734 xu->var->tdrb = ((xu->var->udb[1] & 3) << 16) + (xu->var->udb[0] & 0177776);
735 xu->var->telen = (xu->var->udb[1] >> 8) & 0377;
736 xu->var->trlen = xu->var->udb[2];
737 xu->var->rdrb = ((xu->var->udb[4] & 3) << 16) + (xu->var->udb[3] & 0177776);
738 xu->var->relen = (xu->var->udb[4] >> 8) & 0377;
739 xu->var->rrlen = xu->var->udb[5];
740 xu->var->rxnext = 0;
741 xu->var->txnext = 0;
742 // xu_dump_rxring(xu);
743 // xu_dump_txring(xu);
744
745 break;
746
747 case FC_RDCTR: /* read counters */
748 case FC_RDCLCTR: /* read and clear counters */
749 /* prepare udb for stats transfer */
750 memset(xu->var->udb, 0, sizeof(xu->var->udb));
751
752 /* place stats in udb */
753 udb[0] = 68; /* udb length */
754 udb[1] = stats->secs; /* seconds since zeroed */
755 udb[2] = stats->frecv & 0xFFFF; /* frames received <15:00> */
756 udb[3] = stats->frecv >> 16; /* frames received <31:16> */
757 udb[4] = stats->mfrecv & 0xFFFF; /* multicast frames received <15:00> */
758 udb[5] = stats->mfrecv >> 16; /* multicast frames received <31:16> */
759 udb[6] = stats->rxerf; /* receive error status bits */
760 udb[7] = stats->frecve; /* frames received with error */
761 udb[8] = stats->rbytes & 0xFFFF; /* data bytes received <15:00> */
762 udb[9] = stats->rbytes >> 16; /* data bytes received <31:16> */
763 udb[10] = stats->mrbytes & 0xFFFF; /* multicast data bytes received <15:00> */
764 udb[11] = stats->mrbytes >> 16; /* multicast data bytes received <31:16> */
765 udb[12] = stats->rlossi; /* received frames lost - internal buffer */
766 udb[13] = stats->rlossl; /* received frames lost - local buffer */
767 udb[14] = stats->ftrans & 0xFFFF; /* frames transmitted <15:00> */
768 udb[15] = stats->ftrans >> 16; /* frames transmitted <31:16> */
769 udb[16] = stats->mftrans & 0xFFFF; /* multicast frames transmitted <15:00> */
770 udb[17] = stats->mftrans >> 16; /* multicast frames transmitted <31:16> */
771 udb[18] = stats->ftrans3 & 0xFFFF; /* frames transmitted 3+ tries <15:00> */
772 udb[19] = stats->ftrans3 >> 16; /* frames transmitted 3+ tries <31:16> */
773 udb[20] = stats->ftrans2 & 0xFFFF; /* frames transmitted 2 tries <15:00> */
774 udb[21] = stats->ftrans2 >> 16; /* frames transmitted 2 tries <31:16> */
775 udb[22] = stats->ftransd & 0xFFFF; /* frames transmitted deferred <15:00> */
776 udb[23] = stats->ftransd >> 16; /* frames transmitted deferred <31:16> */
777 udb[24] = stats->tbytes & 0xFFFF; /* data bytes transmitted <15:00> */
778 udb[25] = stats->tbytes >> 16; /* data bytes transmitted <31:16> */
779 udb[26] = stats->mtbytes & 0xFFFF; /* multicast data bytes transmitted <15:00> */
780 udb[27] = stats->mtbytes >> 16; /* multicast data bytes transmitted <31:16> */
781 udb[28] = stats->txerf; /* transmit frame error status bits */
782 udb[29] = stats->ftransa; /* transmit frames aborted */
783 udb[30] = stats->txccf; /* transmit collision check failure */
784 udb[31] = 0; /* MBZ */
785 udb[32] = stats->porterr; /* port driver error */
786 udb[33] = stats->bablcnt; /* babble counter */
787
788 /* transfer udb to host */
789 udbb = xu->var->pcb[1] + ((xu->var->pcb[2] & 3) << 16);
790 wstatus = Map_WriteW(udbb, 68, xu->var->udb);
791 if (wstatus) {
792 xu->var->pcsr0 |= PCSR0_PCEI;
793 }
794
795 /* if clear function, clear network stats */
796 if (fnc == FC_RDCLCTR)
797 memset(stats, 0, sizeof(struct xu_stats));
798 break;
799
800 case FC_RMODE: /* read mode register */
801 value = xu->var->mode;
802 wstatus = Map_WriteW(xu->var->pcbb+2, 2, &value);
803 if (wstatus)
804 return PCSR0_PCEI + 1;
805 break;
806
807 case FC_WMODE: /* write mode register */
808 value = xu->var->mode;
809 xu->var->mode = xu->var->pcb[1];
810 sim_debug(DBG_TRC, xu->dev, "FC_WMODE: mode=%04x\n", xu->var->mode);
811
812 /* set promiscuous and multicast flags */
813 xu->var->setup.promiscuous = (xu->var->mode & MODE_PROM) ? 1 : 0;
814 xu->var->setup.multicast = (xu->var->mode & MODE_ENAL) ? 1 : 0;
815
816 /* if promiscuous or multicast flags changed, change filter */
817 if ((value ^ xu->var->mode) & (MODE_PROM | MODE_ENAL))
818 status = eth_filter (xu->var->etherface, xu->var->setup.mac_count,
819 &xu->var->mac, xu->var->setup.multicast,
820 xu->var->setup.promiscuous);
821 break;
822
823 case FC_RSTAT: /* read extended status */
824 case FC_RCSTAT: /* read and clear extended status */
825 value = xu->var->stat;
826 wstatus = Map_WriteW(xu->var->pcbb+2, 2, &value);
827 value = 10;
828 wstatus2 = Map_WriteW(xu->var->pcbb+4, 2, &value);
829 value = 32;
830 wstatus3 = Map_WriteW(xu->var->pcbb+6, 2, &value);
831 if (wstatus + wstatus2 + wstatus3)
832 return PCSR0_PCEI + 1;
833
834 if (fnc == FC_RCSTAT)
835 xu->var->stat &= 0377; /* clear high byte */
836 break;
837
838 case FC_RSID: /* read system id parameters */
839 /* prepare udb for transfer */
840 memset(xu->var->udb, 0, sizeof(xu->var->udb));
841
842 udb[11] = 0x260; /* type */
843 udb[12] = 28/* + parameter size */; /* ccount */
844 udb[13] = 7; /* code */
845 udb[14] = 0; /* recnum */
846 /* mop information */
847 udb[15] = 1; /* mvtype */
848 udb[16] = 0x0303; /* mvver + mvlen */
849 udb[17] = 0; /* mvueco + mveco */
850 /* function information */
851 udb[18] = 2; /* ftype */
852 udb[19] = 0x0502; /* fval1 + flen */
853 udb[20] = 0x0700; /* hatype<07:00> + fval2 */
854 udb[21] = 0x0600; /* halen + hatype<15:08> */
855 /* built-in MAC address */
856 udb[21] = mac_w[0]; /* HA<15:00> */
857 udb[22] = mac_w[1]; /* HA<31:16> */
858 udb[23] = mac_w[2]; /* HA<47:32> */
859 udb[24] = 0x64; /* dtype */
860 udb[25] = (11 << 8) + 1; /* dvalue + dlen */
861
862 /* transfer udb to host */
863 udbb = xu->var->pcb[1] + ((xu->var->pcb[2] & 3) << 16);
864 wstatus = Map_WriteW(udbb, 52, xu->var->udb);
865 if (wstatus)
866 xu->var->pcsr0 |= PCSR0_PCEI;
867 break;
868
869 case FC_WSID: /* write system id parameters */
870 /* get udb base */
871 udbb = xu->var->pcb[1] + ((xu->var->pcb[2] & 3) << 16);
872 /* get udb length */
873 pltlen = xu->var->pcb[3];
874
875 /* transfer udb from host */
876 rstatus = Map_ReadW(udbb, pltlen * 2, xu->var->udb);
877 if (rstatus)
878 return PCSR0_PCEI + 1;
879
880 /* decode and store system ID fields , if we ever need to.
881 for right now, just return "success" */
882
883 break;
884
885 case FC_RLSA: /* read load server address */
886 if (memcmp(xu->var->load_server, zeros, sizeof(ETH_MAC))) {
887 /* not set, use default multicast load address */
888 wstatus = Map_WriteB(xu->var->pcbb + 2, 6, (uint8*) mcast_load_server);
889 } else {
890 /* is set, use load_server */
891 wstatus = Map_WriteB(xu->var->pcbb + 2, 6, xu->var->load_server);
892 }
893 if (wstatus)
894 return PCSR0_PCEI + 1;
895 break;
896
897
898 case FC_WLSA: /* write load server address */
899 rstatus = Map_ReadB(xu->var->pcbb + 2, 6, xu->var->load_server);
900 if (rstatus)
901 return PCSR0_PCEI + 1;
902 break;
903
904 default: /* Unknown (unimplemented) command. */
905 printf("%s: unknown ancilliary command 0%o requested !\n", xu->dev->name, fnc);
906 return PCSR0_PCEI;
907 break;
908
909 } /* switch */
910
911 return PCSR0_DNI;
912 }
913
914 /* Transfer received packets into receive ring. */
915 void xu_process_receive(CTLR* xu)
916 {
917 uint32 segb, ba;
918 int slen, wlen, off;
919 t_stat rstatus, wstatus;
920 ETH_ITEM* item = 0;
921 int state = xu->var->pcsr1 & PCSR1_STATE;
922 int no_buffers = xu->var->pcsr0 & PCSR0_RCBI;
923
924 sim_debug(DBG_TRC, xu->dev, "xu_process_receive(), buffers: %d\n", xu->var->rrlen);
925
926 /* xu_dump_rxring(xu); /* debug receive ring */
927
928 /* process only when in the running state, and host buffers are available */
929 if ((state != STATE_RUNNING) || no_buffers)
930 return;
931
932 /* check read queue for buffer loss */
933 if (xu->var->ReadQ.loss) {
934 upd_stat16(&xu->var->stats.rlossl, (uint16) xu->var->ReadQ.loss);
935 xu->var->ReadQ.loss = 0;
936 }
937
938 /* while there are still packets left to process in the queue */
939 while (xu->var->ReadQ.count > 0) {
940
941 /* get next receive buffer */
942 ba = xu->var->rdrb + (xu->var->relen * 2) * xu->var->rxnext;
943 rstatus = Map_ReadW (ba, 8, xu->var->rxhdr);
944 if (rstatus) {
945 /* tell host bus read failed */
946 xu->var->stat |= STAT_ERRS | STAT_MERR | STAT_TMOT | STAT_RRNG;
947 xu->var->pcsr0 |= PCSR0_SERI;
948 break;
949 }
950
951 /* if buffer not owned by controller, exit [at end of ring] */
952 if (!(xu->var->rxhdr[2] & RXR_OWN)) {
953 /* tell the host there are no more buffers */
954 /* xu->var->pcsr0 |= PCSR0_RCBI; */ /* I don't think this is correct 08-dec-2005 dth */
955 break;
956 }
957
958 /* set buffer length and address */
959 slen = xu->var->rxhdr[0];
960 segb = xu->var->rxhdr[1] + ((xu->var->rxhdr[2] & 3) << 16);
961
962 /* get first packet from receive queue */
963 if (!item) {
964 item = &xu->var->ReadQ.item[xu->var->ReadQ.head];
965 /*
966 * 2.11BSD does not seem to like small packets.
967 * For example.. an incoming ARP packet is:
968 * ETH dstaddr [6]
969 * ETH srcaddr [6]
970 * ETH type [2]
971 * ARP arphdr [8]
972 * ARP dstha [6]
973 * ARP dstpa [4]
974 * ARP srcha [6]
975 * ARP srcpa [4]
976 *
977 * for a total of 42 bytes. According to the 2.11BSD
978 * driver for DEUNA (if_de.c), this is not a legal size,
979 * and the packet is dropped. Therefore, we pad the
980 * thing to minimum size here. Stupid runts...
981 */
982 if (item->packet.len < ETH_MIN_PACKET) {
983 int len = item->packet.len;
984 memset (&item->packet.msg[len], 0, ETH_MIN_PACKET - len);
985 item->packet.len = ETH_MIN_PACKET;
986 }
987 }
988
989 /* is this the start of frame? */
990 if (item->packet.used == 0) {
991 xu->var->rxhdr[2] |= RXR_STF;
992 off = 0;
993 }
994
995 /* figure out chained packet size */
996 wlen = item->packet.crc_len - item->packet.used;
997 if (wlen > slen)
998 wlen = slen;
999
1000 /* transfer chained packet to host buffer */
1001 wstatus = Map_WriteB (segb, wlen, &item->packet.msg[off]);
1002 if (wstatus) {
1003 /* error during write */
1004 xu->var->stat |= STAT_ERRS | STAT_MERR | STAT_TMOT | STAT_RRNG;
1005 xu->var->pcsr0 |= PCSR0_SERI;
1006 break;
1007 }
1008
1009 /* update chained counts */
1010 item->packet.used += wlen;
1011 off += wlen;
1012
1013 /* Is this the end-of-frame? */
1014 if (item->packet.used == item->packet.crc_len) {
1015 /* mark end-of-frame */
1016 xu->var->rxhdr[2] |= RXR_ENF;
1017
1018 /*
1019 * Fill in the Received Message Length field.
1020 * The documenation notes that the DEUNA actually performs
1021 * a full CRC check on the data buffer, and adds this CRC
1022 * value to the data, in the last 4 bytes. The question
1023 * is: does MLEN include these 4 bytes, or not??? --FvK
1024 *
1025 * A quick look at the RSX Process Software driver shows
1026 * that the CRC byte count(4) is added to MLEN, but does
1027 * not show if the DEUNA/DELUA actually transfers the
1028 * CRC bytes to the host buffers, since the driver never
1029 * tries to use them. However, since the host max buffer
1030 * size is only 1514, not 1518, I doubt the CRC is actually
1031 * transferred in normal mode. Maybe CRC is transferred
1032 * and used in Loopback mode.. -- DTH
1033 *
1034 * The VMS XEDRIVER indicates that CRC is transferred as
1035 * part of the packet, and is included in the MLEN count. -- DTH
1036 */
1037 xu->var->rxhdr[3] &= ~RXR_MLEN;
1038 xu->var->rxhdr[3] |= (item->packet.crc_len);
1039 if (xu->var->mode & MODE_DRDC) /* data chaining disabled */
1040 xu->var->rxhdr[3] |= RXR_NCHN;
1041
1042 /* update stats */
1043 upd_stat32(&xu->var->stats.frecv, 1);
1044 upd_stat32(&xu->var->stats.rbytes, item->packet.len - 14);
1045 if (item->packet.msg[0] & 1) { /* multicast? */
1046 upd_stat32(&xu->var->stats.mfrecv, 1);
1047 upd_stat32(&xu->var->stats.mrbytes, item->packet.len - 14);
1048 }
1049
1050 /* remove processed packet from the receive queue */
1051 ethq_remove (&xu->var->ReadQ);
1052 item = 0;
1053
1054 /* tell host we received a packet */
1055 xu->var->pcsr0 |= PCSR0_RXI;
1056 } /* if end-of-frame */
1057
1058 /* give buffer back to host */
1059 xu->var->rxhdr[2] &= ~RXR_OWN; /* clear ownership flag */
1060
1061 /* update the ring entry in host memory. */
1062 wstatus = Map_WriteW (ba, 8, xu->var->rxhdr);
1063 if (wstatus) {
1064 /* tell host bus write failed */
1065 xu->var->stat |= STAT_ERRS | STAT_MERR | STAT_TMOT | STAT_RRNG;
1066 xu->var->pcsr0 |= PCSR0_SERI;
1067 /* if this was end-of-frame, log frame loss */
1068 if (xu->var->rxhdr[2] & RXR_ENF)
1069 upd_stat16(&xu->var->stats.rlossi, 1);
1070 }
1071
1072 /* set to next receive ring buffer */
1073 xu->var->rxnext += 1;
1074 if (xu->var->rxnext == xu->var->rrlen)
1075 xu->var->rxnext = 0;
1076
1077 } /* while */
1078
1079 /* if we failed to finish receiving the frame, flush the packet */
1080 if (item) {
1081 ethq_remove(&xu->var->ReadQ);
1082 upd_stat16(&xu->var->stats.rlossl, 1);
1083 }
1084
1085 /* set or clear interrupt, depending on what happened */
1086 xu_setclrint(xu, 0);
1087 // xu_dump_rxring(xu); /* debug receive ring */
1088
1089 }
1090
1091 void xu_process_transmit(CTLR* xu)
1092 {
1093 uint32 segb, ba;
1094 int slen, wlen, i, off, giant, runt;
1095 t_stat rstatus, wstatus;
1096
1097 sim_debug(DBG_TRC, xu->dev, "xu_process_transmit()\n");
1098 /* xu_dump_txring(xu); /* debug receive ring */
1099
1100 for (;;) {
1101
1102 /* get next transmit buffer */
1103 ba = xu->var->tdrb + (xu->var->telen * 2) * xu->var->txnext;
1104 rstatus = Map_ReadW (ba, 8, xu->var->txhdr);
1105 if (rstatus) {
1106 /* tell host bus read failed */
1107 xu->var->stat |= STAT_ERRS | STAT_MERR | STAT_TMOT | STAT_TRNG;
1108 xu->var->pcsr0 |= PCSR0_SERI;
1109 break;
1110 }
1111
1112 /* if buffer not owned by controller, exit [at end of ring] */
1113 if (!(xu->var->txhdr[2] & TXR_OWN))
1114 break;
1115
1116 /* set buffer length and address */
1117 slen = xu->var->txhdr[0];
1118 segb = xu->var->txhdr[1] + ((xu->var->txhdr[2] & 3) << 16);
1119 wlen = slen;
1120
1121 /* prepare to accumulate transmit information if start of frame */
1122 if (xu->var->txhdr[2] & TXR_STF) {
1123 memset(&xu->var->write_buffer, 0, sizeof(ETH_PACK));
1124 off = giant = runt = 0;
1125 }
1126
1127 /* get packet data from host */
1128 if (xu->var->write_buffer.len + slen > ETH_MAX_PACKET) {
1129 wlen = ETH_MAX_PACKET - xu->var->write_buffer.len;
1130 giant = 1;
1131 }
1132 if (wlen > 0) {
1133 rstatus = Map_ReadB(segb, wlen, &xu->var->write_buffer.msg[off]);
1134 if (rstatus) {
1135 /* tell host bus read failed */
1136 xu->var->stat |= STAT_ERRS | STAT_MERR | STAT_TMOT | STAT_TRNG;
1137 xu->var->pcsr0 |= PCSR0_SERI;
1138 break;
1139 }
1140 }
1141 off += wlen;
1142 xu->var->write_buffer.len += wlen;
1143
1144 /* transmit packet when end-of-frame is reached */
1145 if (xu->var->txhdr[2] & TXR_ENF) {
1146
1147 /* make sure packet is minimum length */
1148 if (xu->var->write_buffer.len < ETH_MIN_PACKET) {
1149 xu->var->write_buffer.len = ETH_MIN_PACKET; /* pad packet to minimum length */
1150 if ((xu->var->mode & MODE_TPAD) == 0) /* if pad mode is NOT on, set runt error flag */
1151 runt = 1;
1152 }
1153
1154 /* are we in internal loopback mode ? */
1155 if ((xu->var->mode & MODE_LOOP) && (xu->var->mode & MODE_INTL)) {
1156 /* just put packet in receive buffer */
1157 ethq_insert (&xu->var->ReadQ, 1, &xu->var->write_buffer, 0);
1158 } else {
1159 /* transmit packet synchronously - write callback sets status */
1160 wstatus = eth_write(xu->var->etherface, &xu->var->write_buffer, xu->var->wcallback);
1161 if (wstatus)
1162 xu->var->pcsr0 |= PCSR0_PCEI;
1163 }
1164
1165 /* update transmit status in transmit buffer */
1166 if (xu->var->write_buffer.status != 0) {
1167 /* failure */
1168 const uint16 tdr = 100 + wlen * 8; /* arbitrary value */
1169 xu->var->txhdr[3] |= TXR_RTRY;
1170 xu->var->txhdr[3] |= tdr & TXR_TDR;
1171 xu->var->txhdr[2] |= TXR_ERRS;
1172 }
1173
1174 /* was packet too big or too small? */
1175 if (giant || runt) {
1176 xu->var->txhdr[3] |= TXR_BUFL;
1177 xu->var->txhdr[2] |= TXR_ERRS;
1178 }
1179
1180 /* was packet self-addressed? */
1181 for (i=0; i<XU_FILTER_MAX; i++)
1182 if (memcmp(xu->var->write_buffer.msg, xu->var->setup.macs[i], sizeof(ETH_MAC)) == 0)
1183 xu->var->txhdr[2] |= TXR_MTCH;
1184
1185 /* tell host we transmitted a packet */
1186 xu->var->pcsr0 |= PCSR0_TXI;
1187
1188 /* update stats */
1189 upd_stat32(&xu->var->stats.ftrans, 1);
1190 upd_stat32(&xu->var->stats.tbytes, xu->var->write_buffer.len - 14);
1191 if (xu->var->write_buffer.msg[0] & 1) { /* multicast? */
1192 upd_stat32(&xu->var->stats.mftrans, 1);
1193 upd_stat32(&xu->var->stats.mtbytes, xu->var->write_buffer.len - 14);
1194 }
1195 if (giant)
1196 bit_stat16(&xu->var->stats.txerf, 0x10);
1197
1198 } /* if end-of-frame */
1199
1200
1201 /* give buffer ownership back to host */
1202 xu->var->txhdr[2] &= ~TXR_OWN;
1203
1204 /* update transmit buffer */
1205 wstatus = Map_WriteW (ba, 8, xu->var->txhdr);
1206 if (wstatus) {
1207 /* tell host bus write failed */
1208 xu->var->pcsr0 |= PCSR0_PCEI;
1209 /* update stats */
1210 upd_stat16(&xu->var->stats.ftransa, 1);
1211 break;
1212 }
1213
1214 /* set to next transmit ring buffer */
1215 xu->var->txnext += 1;
1216 if (xu->var->txnext == xu->var->trlen)
1217 xu->var->txnext = 0;
1218
1219 } /* while */
1220 }
1221
1222 void xu_port_command (CTLR* xu)
1223 {
1224 char* msg;
1225 int command = xu->var->pcsr0 & PCSR0_PCMD;
1226 int state = xu->var->pcsr1 & PCSR1_STATE;
1227 int bits;
1228 static char* commands[] = {
1229 "NO-OP",
1230 "GET PCBB",
1231 "GET CMD",
1232 "SELFTEST",
1233 "START",
1234 "BOOT",
1235 "Reserved NO-OP",
1236 "Reserved NO-OP",
1237 "PDMD",
1238 "Reserved NO-OP",
1239 "Reserved NO-OP",
1240 "Reserved NO-OP",
1241 "Reserved NO-OP",
1242 "Reserved NO-OP",
1243 "HALT",
1244 "STOP"
1245 };
1246
1247 sim_debug(DBG_TRC, xu->dev, "xu_port_command(), Command = %s [0%o]\n", commands[command], command);
1248 switch (command) { /* cases in order of most used to least used */
1249 case CMD_PDMD: /* POLLING DEMAND */
1250 /* process transmit buffers, receive buffers are done in the service timer */
1251 xu_process_transmit(xu);
1252 xu->var->pcsr0 |= PCSR0_DNI;
1253 break;
1254
1255 case CMD_GETCMD: /* GET COMMAND */
1256 bits = xu_command(xu);
1257 xu->var->pcsr0 |= PCSR0_DNI;
1258 break;
1259
1260 case CMD_GETPCBB: /* GET PCB-BASE */
1261 xu->var->pcbb = (xu->var->pcsr3 << 16) | xu->var->pcsr2;
1262 xu->var->pcsr0 |= PCSR0_DNI;
1263 break;
1264
1265 case CMD_SELFTEST: /* SELFTEST */
1266 xu_sw_reset(xu);
1267 xu->var->pcsr0 |= PCSR0_DNI;
1268 break;
1269
1270 case CMD_START: /* START */
1271 if (state == STATE_READY) {
1272 xu->var->pcsr1 &= ~PCSR1_STATE;
1273 xu->var->pcsr1 |= STATE_RUNNING;
1274 xu->var->pcsr0 |= PCSR0_DNI;
1275
1276 /* reset ring pointers */
1277 xu->var->rxnext = 0;
1278 xu->var->txnext = 0;
1279
1280 } else
1281 xu->var->pcsr0 |= PCSR0_PCEI;
1282 break;
1283
1284 case CMD_HALT: /* HALT */
1285 if ((state == STATE_READY) || (state == STATE_RUNNING)) {
1286 sim_cancel (&xu->unit[0]); /* cancel service timer */
1287 xu->var->pcsr1 &= ~PCSR1_STATE;
1288 xu->var->pcsr1 |= STATE_HALT;
1289 xu->var->pcsr0 |= PCSR0_DNI;
1290 } else
1291 xu->var->pcsr0 |= PCSR0_PCEI;
1292 break;
1293
1294 case CMD_STOP: /* STOP */
1295 if (state == STATE_RUNNING) {
1296 xu->var->pcsr1 &= ~PCSR1_STATE;
1297 xu->var->pcsr1 |= STATE_READY;
1298 xu->var->pcsr0 |= PCSR0_DNI;
1299 } else
1300 xu->var->pcsr0 |= PCSR0_PCEI;
1301 break;
1302
1303 case CMD_BOOT: /* BOOT */
1304 /* not implemented */
1305 msg = "%s: BOOT command not implemented!\n";
1306 printf (msg, xu->dev->name);
1307 if (sim_log) fprintf(sim_log, msg, xu->dev->name);
1308
1309 xu->var->pcsr0 |= PCSR0_PCEI;
1310 break;
1311
1312 case CMD_NOOP: /* NO-OP */
1313 /* NOOP does NOT set DNI */
1314 break;
1315
1316 case CMD_RSV06: /* RESERVED */
1317 case CMD_RSV07: /* RESERVED */
1318 case CMD_RSV11: /* RESERVED */
1319 case CMD_RSV12: /* RESERVED */
1320 case CMD_RSV13: /* RESERVED */
1321 case CMD_RSV14: /* RESERVED */
1322 case CMD_RSV15: /* RESERVED */
1323 /* all reserved commands act as a no-op but set DNI */
1324 xu->var->pcsr0 |= PCSR0_DNI;
1325 break;
1326 } /* switch */
1327
1328 /* set interrupt if needed */
1329 xu_setclrint(xu, 0);
1330 }
1331
1332 t_stat xu_rd(int32 *data, int32 PA, int32 access)
1333 {
1334 CTLR* xu = xu_pa2ctlr(PA);
1335 int reg = (PA >> 1) & 03;
1336
1337 switch (reg) {
1338 case 00:
1339 *data = xu->var->pcsr0;
1340 break;
1341 case 01:
1342 *data = xu->var->pcsr1;
1343 break;
1344 case 02:
1345 *data = xu->var->pcsr2;
1346 break;
1347 case 03:
1348 *data = xu->var->pcsr3;
1349 break;
1350 }
1351 sim_debug(DBG_TRC, xu->dev, "xu_rd(), PCSR%d, data=%04x\n", reg, *data);
1352 if (PA & 1)
1353 sim_debug(DBG_WRN, xu->dev, "xu_rd(), Unexpected Odd address access of PCSR%d\n", reg);
1354 return SCPE_OK;
1355 }
1356
1357 t_stat xu_wr(int32 data, int32 PA, int32 access)
1358 {
1359 CTLR* xu = xu_pa2ctlr(PA);
1360 int reg = (PA >> 1) & 03;
1361 char desc[10];
1362
1363 switch (access) {
1364 case WRITE :
1365 strcpy(desc, "Word");
1366 break;
1367 case WRITEB:
1368 if (PA & 1) {
1369 strcpy(desc, "ByteHi");
1370 } else {
1371 strcpy(desc, "ByteLo");
1372 }
1373 break;
1374 default :
1375 strcpy(desc, "Unknown");
1376 break;
1377 }
1378 sim_debug(DBG_TRC, xu->dev, "xu_wr(), PCSR%d, data=%08x, PA=%08x, access=%d[%s]\n", reg, data, PA, access, desc);
1379 switch (reg) {
1380 case 00:
1381 /* Clear write-one-to-clear interrupt bits */
1382 if (access == WRITEB) {
1383 data &= 0377;
1384 if (PA & 1) {
1385 /* Handle WriteOneToClear trick. */
1386 xu->var->pcsr0 &= ~((data << 8) & 0177400);
1387
1388 /* set/reset interrupt */
1389 xu_setclrint(xu, 0);
1390
1391 /* Bail out early to avoid PCMD crap. */
1392 return SCPE_OK;
1393 }
1394 } else { /* access == WRITE [Word] */
1395 uint16 mask = data & 0xFF00; /* only interested in high byte */
1396 xu->var->pcsr0 &= ~mask; /* clear write-one-to-clear bits */
1397 }
1398 /* RESET function requested? */
1399 if (data & PCSR0_RSET) {
1400 xu_sw_reset(xu);
1401 xu_setclrint(xu, 0);
1402 return SCPE_OK; /* nothing else to do on reset */
1403 }
1404 /* Handle the INTE interlock; if INTE changes state, no commands can occur */
1405 if ((xu->var->pcsr0 ^ data) & PCSR0_INTE) {
1406 xu->var->pcsr0 ^= PCSR0_INTE;
1407 xu->var->pcsr0 |= PCSR0_DNI;
1408 if (xu->var->pcsr0 & PCSR0_INTE) {
1409 sim_debug(DBG_TRC, xu->dev, "xu_wr(), Interrupts Enabled\n");
1410 } else {
1411 sim_debug(DBG_TRC, xu->dev, "xu_wr(), Interrupts Disabled\n");
1412 }
1413 } else {
1414 /* Normal write, no interlock. */
1415 xu->var->pcsr0 &= ~PCSR0_PCMD;
1416 xu->var->pcsr0 |= (data & PCSR0_PCMD);
1417 xu_port_command(xu);
1418 }
1419 /* We might have changed the interrupt sys. */
1420 xu_setclrint(xu, 0);
1421 break;
1422
1423 case 01:
1424 sim_debug(DBG_WRN, xu->dev, "xu_wr(), invalid write access on PCSR1!\n");
1425 break;
1426
1427 case 02:
1428 xu->var->pcsr2 = data & 0177776; /* store word, but not MBZ LSB */
1429 break;
1430
1431 case 03:
1432 xu->var->pcsr3 = data & 0000003; /* store significant bits */
1433 break;
1434 }
1435 return SCPE_OK;
1436 }
1437
1438
1439 /* attach device: */
1440 t_stat xu_attach(UNIT* uptr, char* cptr)
1441 {
1442 t_stat status;
1443 char* tptr;
1444 CTLR* xu = xu_unit2ctlr(uptr);
1445
1446 sim_debug(DBG_TRC, xu->dev, "xu_attach(cptr=%s)\n", cptr);
1447 tptr = (char *) malloc(strlen(cptr) + 1);
1448 if (tptr == NULL) return SCPE_MEM;
1449 strcpy(tptr, cptr);
1450
1451 xu->var->etherface = (ETH_DEV *) malloc(sizeof(ETH_DEV));
1452 if (!xu->var->etherface) return SCPE_MEM;
1453
1454 status = eth_open(xu->var->etherface, cptr, xu->dev, DBG_ETH);
1455 if (status != SCPE_OK) {
1456 free(tptr);
1457 free(xu->var->etherface);
1458 xu->var->etherface = 0;
1459 return status;
1460 }
1461 uptr->filename = tptr;
1462 uptr->flags |= UNIT_ATT;
1463 eth_setcrc(xu->var->etherface, 1); /* enable CRC */
1464
1465 /* reset the device with the new attach info */
1466 xu_reset(xu->dev);
1467
1468 return SCPE_OK;
1469 }
1470
1471 /* detach device: */
1472
1473 t_stat xu_detach(UNIT* uptr)
1474 {
1475 t_stat status;
1476 CTLR* xu = xu_unit2ctlr(uptr);
1477 sim_debug(DBG_TRC, xu->dev, "xu_detach()\n");
1478
1479 if (uptr->flags & UNIT_ATT) {
1480 status = eth_close (xu->var->etherface);
1481 free(xu->var->etherface);
1482 xu->var->etherface = 0;
1483 free(uptr->filename);
1484 uptr->filename = NULL;
1485 uptr->flags &= ~UNIT_ATT;
1486 }
1487 return SCPE_OK;
1488 }
1489
1490 void xu_setint(CTLR* xu)
1491 {
1492 if (xu->var->pcsr0 & PCSR0_INTE) {
1493 xu->var->irq = 1;
1494 SET_INT(XU);
1495 }
1496 return;
1497 }
1498
1499 void xu_clrint(CTLR* xu)
1500 {
1501 int i;
1502 xu->var->irq = 0; /* set controller irq off */
1503 /* clear master interrupt? */
1504 for (i=0; i<XU_MAX_CONTROLLERS; i++) /* check all controllers.. */
1505 if (xu_ctrl[i].var->irq) { /* if any irqs enabled */
1506 SET_INT(XU); /* set master interrupt on */
1507 return;
1508 }
1509 CLR_INT(XU); /* clear master interrupt */
1510 return;
1511 }
1512
1513 int32 xu_int (void)
1514 {
1515 int i;
1516 for (i=0; i<XU_MAX_CONTROLLERS; i++) {
1517 CTLR* xu = &xu_ctrl[i];
1518 if (xu->var->irq) { /* if interrupt pending */
1519 xu_clrint(xu); /* clear interrupt */
1520 return xu->dib->vec; /* return vector */
1521 }
1522 }
1523 return 0; /* no interrupt request active */
1524 }
1525
1526 /*==============================================================================
1527 / debugging routines
1528 /=============================================================================*/
1529
1530 void xu_dump_rxring (CTLR* xu)
1531 {
1532 int i;
1533 int rrlen = xu->var->rrlen;
1534 printf ("receive ring[%s]: base address: %08x headers: %d, header size: %d, current: %d\n", xu->dev->name, xu->var->rdrb, xu->var->rrlen, xu->var->relen, xu->var->rxnext);
1535 for (i=0; i<rrlen; i++) {
1536 uint16 rxhdr[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF};
1537 uint32 ba = xu->var->rdrb + (xu->var->relen * 2) * i;
1538 t_stat rstatus = Map_ReadW (ba, 8, rxhdr); /* get rxring entry[i] */
1539 int own = (rxhdr[2] & RXR_OWN) >> 15;
1540 int len = rxhdr[0];
1541 uint32 addr = rxhdr[1] + ((rxhdr[2] & 3) << 16);
1542 printf (" header[%d]: own:%d, len:%d, address:%08x data:{%04x,%04x,%04x,%04x}\n", i, own, len, addr, rxhdr[0], rxhdr[1], rxhdr[2], rxhdr[3]);
1543 }
1544 }
1545
1546 void xu_dump_txring (CTLR* xu)
1547 {
1548 int i;
1549 int trlen = xu->var->trlen;
1550 printf ("transmit ring[%s]: base address: %08x headers: %d, header size: %d, current: %d\n", xu->dev->name, xu->var->tdrb, xu->var->trlen, xu->var->telen, xu->var->txnext);
1551 for (i=0; i<trlen; i++) {
1552 uint16 txhdr[4];
1553 uint32 ba = xu->var->tdrb + (xu->var->telen * 2) * i;
1554 t_stat tstatus = Map_ReadW (ba, 8, txhdr); /* get rxring entry[i] */
1555 int own = (txhdr[2] & RXR_OWN) >> 15;
1556 int len = txhdr[0];
1557 uint32 addr = txhdr[1] + ((txhdr[2] & 3) << 16);
1558 printf (" header[%d]: own:%d, len:%d, address:%08x data:{%04x,%04x,%04x,%04x}\n", i, own, len, addr, txhdr[0], txhdr[1], txhdr[2], txhdr[3]);
1559 }
1560 }