1 /* pdp11_xu.c: DEUNA/DELUA ethernet controller simulator
2 ------------------------------------------------------------------------------
4 Copyright (c) 2003-2007, David T. Hittner
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:
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
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.
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.
27 ------------------------------------------------------------------------------
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
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
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.
55 ------------------------------------------------------------------------------
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
83 ------------------------------------------------------------------------------
88 extern int32 tmxr_poll
, tmr_poll
, clk_tps
, cpu_astop
;
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
);
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
);
116 DIB xua_dib
= { IOBA_XU
, IOLN_XU
, &xu_rd
, &xu_wr
,
117 1, IVCL (XU
), VEC_XU
, {&xu_int
} };
120 { UDATA (&xu_svc
, UNIT_IDLE
|UNIT_ATTABLE
|UNIT_DISABLE
, 0) } /* receive timer */
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 */
131 #if defined (VM_PDP11)
132 { MTAB_XTD
|MTAB_VDV
, 004, "ADDRESS", "ADDRESS",
133 &set_addr
, &show_addr
, NULL
},
135 { MTAB_XTD
|MTAB_VDV
, 004, "ADDRESS", NULL
,
136 NULL
, &show_addr
, NULL
},
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
, ð_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
},
154 DEBTAB xu_debug
[] = {
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
,
174 /* XUB does not exist in the PDP10 simulation */
175 #if defined(IOBA_XUB)
177 DIB xub_dib
= { IOBA_XUB
, IOLN_XUB
, &xu_rd
, &xu_wr
,
178 1, IVCL (XU
), 0, { &xu_int
} };
181 { UDATA (&xu_svc
, UNIT_IDLE
|UNIT_ATTABLE
|UNIT_DISABLE
, 0) } /* receive timer */
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 */
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
,
203 #define XU_MAX_CONTROLLERS 2
205 {&xu_dev
, xua_unit
, &xua_dib
, &xua
} /* XUA controller */
206 ,{&xub_dev
, xub_unit
, &xub_dib
, &xub
} /* XUB controller */
209 #define XU_MAX_CONTROLLERS 1
211 {&xu_dev
, xua_unit
, &xua_dib
, &xua
} /* XUA controller */
213 #endif /* IOBA_XUB */
215 /*============================================================================*/
217 /* Multicontroller support */
219 CTLR
* xu_unit2ctlr(UNIT
* uptr
)
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
)
231 CTLR
* xu_dev2ctlr(DEVICE
* dptr
)
234 for (i
=0; i
<XU_MAX_CONTROLLERS
; i
++)
235 if (xu_ctrl
[i
].dev
== dptr
)
241 CTLR
* xu_pa2ctlr(uint32 PA
)
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
)))
251 /*============================================================================*/
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
)
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
)
265 t_stat
xu_showmac (FILE* st
, UNIT
* uptr
, int32 val
, void* desc
)
267 CTLR
* xu
= xu_unit2ctlr(uptr
);
270 eth_mac_fmt((ETH_MAC
*)xu
->var
->mac
, buffer
);
271 fprintf(st
, "MAC=%s", buffer
);
275 t_stat
xu_setmac (UNIT
* uptr
, int32 val
, char* cptr
, void* desc
)
278 CTLR
* xu
= xu_unit2ctlr(uptr
);
280 if (!cptr
) return SCPE_IERR
;
281 if (uptr
->flags
& UNIT_ATT
) return SCPE_ALATT
;
282 status
= eth_mac_scan(&xu
->var
->mac
, cptr
);
286 t_stat
xu_set_stats (UNIT
* uptr
, int32 val
, char* cptr
, void* desc
)
288 CTLR
* xu
= xu_unit2ctlr(uptr
);
290 /* set stats to zero, regardless of passed parameter */
291 memset(&xu
->var
->stats
, 0, sizeof(struct xu_stats
));
295 t_stat
xu_show_stats (FILE* st
, UNIT
* uptr
, int32 val
, void* desc
)
297 char* fmt
= " %-24s%d\n";
298 CTLR
* xu
= xu_unit2ctlr(uptr
);
299 struct xu_stats
* stats
= &xu
->var
->stats
;
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
);
314 t_stat
xu_show_type (FILE* st
, UNIT
* uptr
, int32 val
, void* desc
)
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;
325 t_stat
xu_set_type (UNIT
* uptr
, int32 val
, char* cptr
, void* desc
)
327 CTLR
* xu
= xu_unit2ctlr(uptr
);
328 if (!cptr
) return SCPE_IERR
;
329 if (uptr
->flags
& UNIT_ATT
) return SCPE_ALATT
;
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
;
339 /*============================================================================*/
341 void upd_stat16(uint16
* stat
, uint16 add
)
344 /* did stat roll over? latches at maximum */
349 void upd_stat32(uint32
* stat
, uint32 add
)
352 /* did stat roll over? latches at maximum */
357 void bit_stat16(uint16
* stat
, uint16 bits
)
362 t_stat
xu_process_local (CTLR
* xu
, ETH_PACK
* pack
)
364 return SCPE_NOFNC
; /* not implemented yet */
367 void xu_read_callback(CTLR
* xu
, int status
)
369 /* process any packets locally that can be */
370 status
= xu_process_local (xu
, &xu
->var
->read_buffer
);
372 /* add packet to read queue */
373 if (status
!= SCPE_OK
)
374 ethq_insert(&xu
->var
->ReadQ
, 2, &xu
->var
->read_buffer
, 0);
377 void xua_read_callback(int status
)
379 xu_read_callback(&xu_ctrl
[0], status
);
382 void xub_read_callback(int status
)
384 xu_read_callback(&xu_ctrl
[1], status
);
387 t_stat
xu_system_id (CTLR
* xu
, const ETH_MAC dest
, uint16 receipt_id
)
389 static uint16 receipt
= 0;
391 uint8
* const msg
= &system_id
.msg
[0];
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 */
405 msg
[18] = receipt_id
& 0xFF; /* receipt number */
406 msg
[19] = (receipt_id
>> 8) & 0xFF; /* receipt number */
408 msg
[18] = receipt
& 0xFF; /* receipt number */
409 msg
[19] = (receipt
++ >> 8) & 0xFF; /* receipt number */
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 */
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 */
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 */
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) */
440 msg
[43] = 11; /* value (11=DELUA) */
442 /* write system id */
444 status
= eth_write(xu
->var
->etherface
, &system_id
, NULL
);
449 t_stat
xu_svc(UNIT
* uptr
)
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
;
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
);
461 /* Now read and queue packets that have arrived */
462 /* This is repeated as long as they are available and we have room */
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
);
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
);
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 */
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);
487 /* resubmit service timer if controller not halted */
488 switch (xu
->var
->pcsr1
& PCSR1_STATE
) {
491 sim_activate(&xu
->unit
[0], tmxr_poll
);
498 void xu_write_callback (CTLR
* xu
, int status
)
500 xu
->var
->write_buffer
.status
= status
;
503 void xua_write_callback (int status
)
505 xu_write_callback(&xu_ctrl
[0], status
);
508 void xub_write_callback (int status
)
510 xu_write_callback(&xu_ctrl
[1], status
);
513 void xu_setclrint(CTLR
* xu
, int32 bits
)
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 */
519 xu
->var
->pcsr0
&= ~PCSR0_INTR
; /* ... or off */
520 xu_clrint(xu
); /* and clear interrupt if needed*/
524 t_stat
xu_sw_reset (CTLR
* xu
)
528 sim_debug(DBG_TRC
, xu
->dev
, "xu_sw_reset()\n");
530 /* Clear the registers. */
531 xu
->var
->pcsr0
= PCSR0_DNI
| PCSR0_INTR
;
532 xu
->var
->pcsr1
= STATE_READY
;
533 switch (xu
->var
->type
) {
535 xu
->var
->pcsr1
|= TYPE_DELUA
;
538 xu
->var
->pcsr1
|= TYPE_DEUNA
;
539 if (!xu
->var
->etherface
) /* if not attached, set transceiver powerfail */
540 xu
->var
->pcsr1
|= PCSR1_XPWR
;
546 /* Clear the parameters. */
551 /* clear read queue */
552 ethq_clear(&xu
->var
->ReadQ
);
554 /* clear setup info */
555 memset(&xu
->var
->setup
, 0, sizeof(struct xu_setup
));
557 /* clear network statistics */
558 memset(&xu
->var
->stats
, 0, sizeof(struct xu_stats
));
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
);
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
));
573 /* clear load_server address */
574 memset(xu
->var
->load_server
, 0, sizeof(ETH_MAC
));
580 t_stat
xu_reset(DEVICE
* dptr
)
583 CTLR
* xu
= xu_dev2ctlr(dptr
);
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
)
591 /* software reset controller */
598 /* Perform one of the defined ancillary functions. */
599 int32
xu_command(CTLR
* xu
)
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
[] = {
612 "Start Microaddress",
613 "Read Default Physical Address",
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",
622 "Read/Clear Counters",
623 "Read Mode Register",
624 "Write Mode Register",
627 "Dump Internal Memory",
628 "Load Internal Memory",
631 "Read Load Server Address",
632 "Write Load Server Address"
635 /* Grab the PCB from the host. */
636 rstatus
= Map_ReadW(xu
->var
->pcbb
, 8, xu
->var
->pcb
);
638 return PCSR0_PCEI
+ 1;
640 /* High 8 bits are defined as MBZ. */
641 if (xu
->var
->pcb
[0] & 0177400)
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
);
652 case FC_RDPA
: /* read default physical address */
653 wstatus
= Map_WriteB(xu
->var
->pcbb
+ 2, 6, xu
->var
->mac
);
655 return PCSR0_PCEI
+ 1;
658 case FC_RPA
: /* read current physical address */
659 wstatus
= Map_WriteB(xu
->var
->pcbb
+ 2, 6, (uint8
*)&xu
->var
->setup
.macs
[0]);
661 return PCSR0_PCEI
+ 1;
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)
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]);
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
);
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
++) {
685 xu
->var
->setup
.macs
[i
][j
] = 0;
687 /* get multicast list from host */
688 rstatus
= Map_ReadB(udbb
, mtlen
* 6, (uint8
*) &xu
->var
->setup
.macs
[1]);
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
);
695 xu
->var
->pcsr0
|= PCSR0_PCEI
;
699 case FC_RRF
: /* read ring format */
700 if ((xu
->var
->pcb
[1] & 1) || (xu
->var
->pcb
[2] & 0374))
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
;
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
);
716 case FC_WRF
: /* write ring format */
717 if ((xu
->var
->pcb
[1] & 1) || (xu
->var
->pcb
[2] & 0374))
719 if ((xu
->var
->pcsr1
& PCSR1_STATE
) == STATE_RUNNING
)
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
);
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)) {
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];
742 // xu_dump_rxring(xu);
743 // xu_dump_txring(xu);
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
));
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 */
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
);
792 xu
->var
->pcsr0
|= PCSR0_PCEI
;
795 /* if clear function, clear network stats */
796 if (fnc
== FC_RDCLCTR
)
797 memset(stats
, 0, sizeof(struct xu_stats
));
800 case FC_RMODE
: /* read mode register */
801 value
= xu
->var
->mode
;
802 wstatus
= Map_WriteW(xu
->var
->pcbb
+2, 2, &value
);
804 return PCSR0_PCEI
+ 1;
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
);
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;
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
);
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
);
828 wstatus2
= Map_WriteW(xu
->var
->pcbb
+4, 2, &value
);
830 wstatus3
= Map_WriteW(xu
->var
->pcbb
+6, 2, &value
);
831 if (wstatus
+ wstatus2
+ wstatus3
)
832 return PCSR0_PCEI
+ 1;
834 if (fnc
== FC_RCSTAT
)
835 xu
->var
->stat
&= 0377; /* clear high byte */
838 case FC_RSID
: /* read system id parameters */
839 /* prepare udb for transfer */
840 memset(xu
->var
->udb
, 0, sizeof(xu
->var
->udb
));
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 */
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
);
866 xu
->var
->pcsr0
|= PCSR0_PCEI
;
869 case FC_WSID
: /* write system id parameters */
871 udbb
= xu
->var
->pcb
[1] + ((xu
->var
->pcb
[2] & 3) << 16);
873 pltlen
= xu
->var
->pcb
[3];
875 /* transfer udb from host */
876 rstatus
= Map_ReadW(udbb
, pltlen
* 2, xu
->var
->udb
);
878 return PCSR0_PCEI
+ 1;
880 /* decode and store system ID fields , if we ever need to.
881 for right now, just return "success" */
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
);
890 /* is set, use load_server */
891 wstatus
= Map_WriteB(xu
->var
->pcbb
+ 2, 6, xu
->var
->load_server
);
894 return PCSR0_PCEI
+ 1;
898 case FC_WLSA
: /* write load server address */
899 rstatus
= Map_ReadB(xu
->var
->pcbb
+ 2, 6, xu
->var
->load_server
);
901 return PCSR0_PCEI
+ 1;
904 default: /* Unknown (unimplemented) command. */
905 printf("%s: unknown ancilliary command 0%o requested !\n", xu
->dev
->name
, fnc
);
914 /* Transfer received packets into receive ring. */
915 void xu_process_receive(CTLR
* xu
)
919 t_stat rstatus
, wstatus
;
921 int state
= xu
->var
->pcsr1
& PCSR1_STATE
;
922 int no_buffers
= xu
->var
->pcsr0
& PCSR0_RCBI
;
924 sim_debug(DBG_TRC
, xu
->dev
, "xu_process_receive(), buffers: %d\n", xu
->var
->rrlen
);
926 /* xu_dump_rxring(xu); /* debug receive ring */
928 /* process only when in the running state, and host buffers are available */
929 if ((state
!= STATE_RUNNING
) || no_buffers
)
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;
938 /* while there are still packets left to process in the queue */
939 while (xu
->var
->ReadQ
.count
> 0) {
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
);
945 /* tell host bus read failed */
946 xu
->var
->stat
|= STAT_ERRS
| STAT_MERR
| STAT_TMOT
| STAT_RRNG
;
947 xu
->var
->pcsr0
|= PCSR0_SERI
;
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 */
958 /* set buffer length and address */
959 slen
= xu
->var
->rxhdr
[0];
960 segb
= xu
->var
->rxhdr
[1] + ((xu
->var
->rxhdr
[2] & 3) << 16);
962 /* get first packet from receive queue */
964 item
= &xu
->var
->ReadQ
.item
[xu
->var
->ReadQ
.head
];
966 * 2.11BSD does not seem to like small packets.
967 * For example.. an incoming ARP packet is:
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...
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
;
989 /* is this the start of frame? */
990 if (item
->packet
.used
== 0) {
991 xu
->var
->rxhdr
[2] |= RXR_STF
;
995 /* figure out chained packet size */
996 wlen
= item
->packet
.crc_len
- item
->packet
.used
;
1000 /* transfer chained packet to host buffer */
1001 wstatus
= Map_WriteB (segb
, wlen
, &item
->packet
.msg
[off
]);
1003 /* error during write */
1004 xu
->var
->stat
|= STAT_ERRS
| STAT_MERR
| STAT_TMOT
| STAT_RRNG
;
1005 xu
->var
->pcsr0
|= PCSR0_SERI
;
1009 /* update chained counts */
1010 item
->packet
.used
+= wlen
;
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
;
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
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
1034 * The VMS XEDRIVER indicates that CRC is transferred as
1035 * part of the packet, and is included in the MLEN count. -- DTH
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
;
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);
1050 /* remove processed packet from the receive queue */
1051 ethq_remove (&xu
->var
->ReadQ
);
1054 /* tell host we received a packet */
1055 xu
->var
->pcsr0
|= PCSR0_RXI
;
1056 } /* if end-of-frame */
1058 /* give buffer back to host */
1059 xu
->var
->rxhdr
[2] &= ~RXR_OWN
; /* clear ownership flag */
1061 /* update the ring entry in host memory. */
1062 wstatus
= Map_WriteW (ba
, 8, xu
->var
->rxhdr
);
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);
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;
1079 /* if we failed to finish receiving the frame, flush the packet */
1081 ethq_remove(&xu
->var
->ReadQ
);
1082 upd_stat16(&xu
->var
->stats
.rlossl
, 1);
1085 /* set or clear interrupt, depending on what happened */
1086 xu_setclrint(xu
, 0);
1087 // xu_dump_rxring(xu); /* debug receive ring */
1091 void xu_process_transmit(CTLR
* xu
)
1094 int slen
, wlen
, i
, off
, giant
, runt
;
1095 t_stat rstatus
, wstatus
;
1097 sim_debug(DBG_TRC
, xu
->dev
, "xu_process_transmit()\n");
1098 /* xu_dump_txring(xu); /* debug receive ring */
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
);
1106 /* tell host bus read failed */
1107 xu
->var
->stat
|= STAT_ERRS
| STAT_MERR
| STAT_TMOT
| STAT_TRNG
;
1108 xu
->var
->pcsr0
|= PCSR0_SERI
;
1112 /* if buffer not owned by controller, exit [at end of ring] */
1113 if (!(xu
->var
->txhdr
[2] & TXR_OWN
))
1116 /* set buffer length and address */
1117 slen
= xu
->var
->txhdr
[0];
1118 segb
= xu
->var
->txhdr
[1] + ((xu
->var
->txhdr
[2] & 3) << 16);
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;
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
;
1133 rstatus
= Map_ReadB(segb
, wlen
, &xu
->var
->write_buffer
.msg
[off
]);
1135 /* tell host bus read failed */
1136 xu
->var
->stat
|= STAT_ERRS
| STAT_MERR
| STAT_TMOT
| STAT_TRNG
;
1137 xu
->var
->pcsr0
|= PCSR0_SERI
;
1142 xu
->var
->write_buffer
.len
+= wlen
;
1144 /* transmit packet when end-of-frame is reached */
1145 if (xu
->var
->txhdr
[2] & TXR_ENF
) {
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 */
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);
1159 /* transmit packet synchronously - write callback sets status */
1160 wstatus
= eth_write(xu
->var
->etherface
, &xu
->var
->write_buffer
, xu
->var
->wcallback
);
1162 xu
->var
->pcsr0
|= PCSR0_PCEI
;
1165 /* update transmit status in transmit buffer */
1166 if (xu
->var
->write_buffer
.status
!= 0) {
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
;
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
;
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
;
1185 /* tell host we transmitted a packet */
1186 xu
->var
->pcsr0
|= PCSR0_TXI
;
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);
1196 bit_stat16(&xu
->var
->stats
.txerf
, 0x10);
1198 } /* if end-of-frame */
1201 /* give buffer ownership back to host */
1202 xu
->var
->txhdr
[2] &= ~TXR_OWN
;
1204 /* update transmit buffer */
1205 wstatus
= Map_WriteW (ba
, 8, xu
->var
->txhdr
);
1207 /* tell host bus write failed */
1208 xu
->var
->pcsr0
|= PCSR0_PCEI
;
1210 upd_stat16(&xu
->var
->stats
.ftransa
, 1);
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;
1222 void xu_port_command (CTLR
* xu
)
1225 int command
= xu
->var
->pcsr0
& PCSR0_PCMD
;
1226 int state
= xu
->var
->pcsr1
& PCSR1_STATE
;
1228 static char* commands
[] = {
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
;
1255 case CMD_GETCMD
: /* GET COMMAND */
1256 bits
= xu_command(xu
);
1257 xu
->var
->pcsr0
|= PCSR0_DNI
;
1260 case CMD_GETPCBB
: /* GET PCB-BASE */
1261 xu
->var
->pcbb
= (xu
->var
->pcsr3
<< 16) | xu
->var
->pcsr2
;
1262 xu
->var
->pcsr0
|= PCSR0_DNI
;
1265 case CMD_SELFTEST
: /* SELFTEST */
1267 xu
->var
->pcsr0
|= PCSR0_DNI
;
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
;
1276 /* reset ring pointers */
1277 xu
->var
->rxnext
= 0;
1278 xu
->var
->txnext
= 0;
1281 xu
->var
->pcsr0
|= PCSR0_PCEI
;
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
;
1291 xu
->var
->pcsr0
|= PCSR0_PCEI
;
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
;
1300 xu
->var
->pcsr0
|= PCSR0_PCEI
;
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
);
1309 xu
->var
->pcsr0
|= PCSR0_PCEI
;
1312 case CMD_NOOP
: /* NO-OP */
1313 /* NOOP does NOT set DNI */
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
;
1328 /* set interrupt if needed */
1329 xu_setclrint(xu
, 0);
1332 t_stat
xu_rd(int32
*data
, int32 PA
, int32 access
)
1334 CTLR
* xu
= xu_pa2ctlr(PA
);
1335 int reg
= (PA
>> 1) & 03;
1339 *data
= xu
->var
->pcsr0
;
1342 *data
= xu
->var
->pcsr1
;
1345 *data
= xu
->var
->pcsr2
;
1348 *data
= xu
->var
->pcsr3
;
1351 sim_debug(DBG_TRC
, xu
->dev
, "xu_rd(), PCSR%d, data=%04x\n", reg
, *data
);
1353 sim_debug(DBG_WRN
, xu
->dev
, "xu_rd(), Unexpected Odd address access of PCSR%d\n", reg
);
1357 t_stat
xu_wr(int32 data
, int32 PA
, int32 access
)
1359 CTLR
* xu
= xu_pa2ctlr(PA
);
1360 int reg
= (PA
>> 1) & 03;
1365 strcpy(desc
, "Word");
1369 strcpy(desc
, "ByteHi");
1371 strcpy(desc
, "ByteLo");
1375 strcpy(desc
, "Unknown");
1378 sim_debug(DBG_TRC
, xu
->dev
, "xu_wr(), PCSR%d, data=%08x, PA=%08x, access=%d[%s]\n", reg
, data
, PA
, access
, desc
);
1381 /* Clear write-one-to-clear interrupt bits */
1382 if (access
== WRITEB
) {
1385 /* Handle WriteOneToClear trick. */
1386 xu
->var
->pcsr0
&= ~((data
<< 8) & 0177400);
1388 /* set/reset interrupt */
1389 xu_setclrint(xu
, 0);
1391 /* Bail out early to avoid PCMD crap. */
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 */
1398 /* RESET function requested? */
1399 if (data
& PCSR0_RSET
) {
1401 xu_setclrint(xu
, 0);
1402 return SCPE_OK
; /* nothing else to do on reset */
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");
1411 sim_debug(DBG_TRC
, xu
->dev
, "xu_wr(), Interrupts Disabled\n");
1414 /* Normal write, no interlock. */
1415 xu
->var
->pcsr0
&= ~PCSR0_PCMD
;
1416 xu
->var
->pcsr0
|= (data
& PCSR0_PCMD
);
1417 xu_port_command(xu
);
1419 /* We might have changed the interrupt sys. */
1420 xu_setclrint(xu
, 0);
1424 sim_debug(DBG_WRN
, xu
->dev
, "xu_wr(), invalid write access on PCSR1!\n");
1428 xu
->var
->pcsr2
= data
& 0177776; /* store word, but not MBZ LSB */
1432 xu
->var
->pcsr3
= data
& 0000003; /* store significant bits */
1439 /* attach device: */
1440 t_stat
xu_attach(UNIT
* uptr
, char* cptr
)
1444 CTLR
* xu
= xu_unit2ctlr(uptr
);
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
;
1451 xu
->var
->etherface
= (ETH_DEV
*) malloc(sizeof(ETH_DEV
));
1452 if (!xu
->var
->etherface
) return SCPE_MEM
;
1454 status
= eth_open(xu
->var
->etherface
, cptr
, xu
->dev
, DBG_ETH
);
1455 if (status
!= SCPE_OK
) {
1457 free(xu
->var
->etherface
);
1458 xu
->var
->etherface
= 0;
1461 uptr
->filename
= tptr
;
1462 uptr
->flags
|= UNIT_ATT
;
1463 eth_setcrc(xu
->var
->etherface
, 1); /* enable CRC */
1465 /* reset the device with the new attach info */
1471 /* detach device: */
1473 t_stat
xu_detach(UNIT
* uptr
)
1476 CTLR
* xu
= xu_unit2ctlr(uptr
);
1477 sim_debug(DBG_TRC
, xu
->dev
, "xu_detach()\n");
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
;
1490 void xu_setint(CTLR
* xu
)
1492 if (xu
->var
->pcsr0
& PCSR0_INTE
) {
1499 void xu_clrint(CTLR
* xu
)
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 */
1509 CLR_INT(XU
); /* clear master interrupt */
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 */
1523 return 0; /* no interrupt request active */
1526 /*==============================================================================
1527 / debugging routines
1528 /=============================================================================*/
1530 void xu_dump_rxring (CTLR
* xu
)
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;
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]);
1546 void xu_dump_txring (CTLR
* xu
)
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
++) {
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;
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]);