First Commit of my working state
[simh.git] / PDP11 / pdp11_xq.c
CommitLineData
196ba1fc
PH
1/* pdp11_xq.c: DEQNA/DELQA ethernet controller simulator\r
2 ------------------------------------------------------------------------------\r
3\r
4 Copyright (c) 2002-2007, David T. Hittner\r
5\r
6 Permission is hereby granted, free of charge, to any person obtaining a\r
7 copy of this software and associated documentation files (the "Software"),\r
8 to deal in the Software without restriction, including without limitation\r
9 the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
10 and/or sell copies of the Software, and to permit persons to whom the\r
11 Software is furnished to do so, subject to the following conditions:\r
12\r
13 The above copyright notice and this permission notice shall be included in\r
14 all copies or substantial portions of the Software.\r
15\r
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r
19 THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
20 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
21 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
22\r
23 Except as contained in this notice, the name of the author shall not be\r
24 used in advertising or otherwise to promote the sale, use or other dealings\r
25 in this Software without prior written authorization from the author.\r
26\r
27 ------------------------------------------------------------------------------\r
28\r
29 This DEQNA/DELQA simulation is based on:\r
30 Digital DELQA Users Guide, Part# EK-DELQA-UG-002\r
31 Digital DEQNA Users Guide, Part# EK-DEQNA-UG-001\r
32 These manuals can be found online at:\r
33 http://www.spies.com/~aek/pdf/dec/qbus\r
34\r
35 Certain adaptations have been made because this is an emulation:\r
36 Ethernet transceiver power flag CSR<12> is ON when attached.\r
37 External Loopback does not go out to the physical adapter, it is\r
38 implemented more like an extended Internal Loopback\r
39 Time Domain Reflectometry (TDR) numbers are faked\r
40 The 10-second approx. hardware/software reset delay does not exist\r
41 Some physical ethernet receive events like Runts, Overruns, etc. are\r
42 never reported back, since the packet-level driver never sees them\r
43\r
44 Certain advantages are derived from this emulation:\r
45 If the real ethernet controller is faster than 10Mbit/sec, the speed is\r
46 seen by the simulated cpu since there are no minimum response times.\r
47\r
48 Known Bugs or Unsupported features, in priority order:\r
49 1) PDP11 bootstrap\r
50 2) MOP functionality not implemented\r
51 3) Local packet processing not implemented\r
52\r
53 Regression Tests:\r
54 VAX: 1. Console SHOW DEVICE\r
55 2. VMS v7.2 boots/initializes/shows device\r
56 3. VMS DECNET - SET HOST and COPY tests\r
57 4. VMS MultiNet - SET HOST/TELNET and FTP tests\r
58 5. VMS LAT - SET HOST/LAT tests\r
59 6. VMS Cluster - SHOW CLUSTER, SHOW DEVICE, and cluster COPY tests\r
60 7. Console boot into VMSCluster (>>>B XQAO)\r
61\r
62 PDP11: 1. RT-11 v5.3 - FTPSB copy test\r
63 2. RSTS/E v10.1 - detects/enables device\r
64\r
65 ------------------------------------------------------------------------------\r
66\r
67 Modification history:\r
68\r
69 18-Jun-07 RMS Added UNIT_IDLE flag\r
70 29-Oct-06 RMS Synced poll and clock\r
71 27-Jan-06 RMS Fixed unaligned accesses in XQB (found by Doug Carman)\r
72 07-Jan-06 RMS Fixed unaligned access bugs (found by Doug Carman)\r
73 07-Sep-05 DTH Removed unused variable\r
74 16-Aug-05 RMS Fixed C++ declaration and cast problems\r
75 01-Dec-04 DTH Added runtime attach prompt\r
76 27-Feb-04 DTH Removed struct timeb deuggers\r
77 31-Jan-04 DTH Replaced #ifdef debuggers with inline debugging\r
78 19-Jan-04 DTH Combined service timers into one for efficiency\r
79 16-Jan-04 DTH Added more info to SHOW MOD commands, added SET/SHOW XQ DEBUG\r
80 13-Jan-04 DTH Corrected interrupt code with help from Tom Evans\r
81 06-Jan-04 DTH Added protection against changing mac and type if attached\r
82 05-Jan-04 DTH Moved most of xq_setmac to sim_ether\r
83 26-Dec-03 DTH Moved ethernet show and queue functions to sim_ether\r
84 03-Dec-03 DTH Added minimum name length to show xq eth\r
85 25-Nov-03 DTH Reworked interrupts to fix broken XQB implementation\r
86 19-Nov-03 MP Rearranged timer reset sequencing to allow for a device to be\r
87 disabled after it had been enabled.\r
88 17-Nov-03 DTH Standardized #include of timeb.h\r
89 28-Sep-03 MP - Fixed bug in xq_process_setup which would leave the\r
90 device in promiscuous or all multicast mode once it\r
91 ever had been there.\r
92 - Fixed output format in show_xq_sanity to end in "\n"\r
93 - Added display of All Multicase and promiscuous to\r
94 xq_show_filters\r
95 - The stuck in All Multicast or Promiscuous issue is \r
96 worse than previously thought. See comments in \r
97 xq_process_setup. \r
98 - Change xq_setmac to also allow ":" as a address \r
99 separator character, since sim_ether's eth_mac_fmt\r
100 formats them with this separator character.\r
101 - Changed xq_sw_reset to behave more like the set of\r
102 actions described in Table 3-6 of the DELQA manua.\r
103 The manual mentions "N/A" which I'm interpreting to\r
104 mean "Not Affected".\r
105 05-Jun-03 DTH Added receive packet splitting\r
106 03-Jun-03 DTH Added SHOW XQ FILTERS\r
107 02-Jun-03 DTH Added SET/SHOW XQ STATS (packet statistics), runt & giant processing\r
108 28-May-03 DTH Modified message queue for dynamic size to shrink executable\r
109 28-May-03 MP Fixed bug in xq_setmac\r
110 06-May-03 DTH Changed 32-bit t_addr to uint32 for v3.0\r
111 Removed SET ADDRESS functionality\r
112 05-May-03 DTH Added second controller\r
113 26-Mar-03 DTH Added PDP11 bootrom loader\r
114 Adjusted xq_ex and xq_dev to allow pdp11 to look at bootrom\r
115 Patched bootrom to allow "pass" of diagnostics on RSTS/E\r
116 06-Mar-03 DTH Corrected interrupts on IE state transition (code by Tom Evans)\r
117 Added interrupt clear on soft reset (first noted by Bob Supnik)\r
118 Removed interrupt when setting XL or RL (multiple people)\r
119 16-Jan-03 DTH Merged Mark Pizzolato's enhancements with main source\r
120 Corrected PDP11 XQ_DEBUG compilation\r
121 15-Jan-03 MP Fixed the number of units in the xq device structure.\r
122 13-Jan-03 MP Reworked the timer management logic which initiated\r
123 the system id broadcast messages. The original\r
124 implementation triggered this on the CSR transition\r
125 of Receiver Enabled. This was an issue since the\r
126 it seems that at least VMS's XQ driver makes this\r
127 transition often and the resulting overhead reduces\r
128 the simulated CPU instruction execution throughput by\r
129 about 40%. I start the system id timer on device\r
130 reset and it fires once a second so that it can\r
131 leverage the reasonably recalibrated tmr_poll value.\r
132 13-Jan-03 MP Changed the scheduling of xq_svc to leverage the\r
133 dynamically computed clock values to achieve an\r
134 approximate interval of 100 per second. This is\r
135 more than sufficient for normal system behaviour\r
136 expecially since we service receives with every\r
137 transmit. The previous fixed value of 2500\r
138 attempted to get 200/sec but it was a guess that\r
139 didn't adapt. On faster host systems (possibly\r
140 most of them) the 2500 number spends too much time\r
141 polling.\r
142 10-Jan-03 DTH Removed XQ_DEBUG dependency from Borland #pragmas\r
143 Added SET XQ BOOTROM command for PDP11s\r
144 07-Jan-03 DTH Added pointer to online manuals\r
145 02-Jan-03 DTH Added local packet processing\r
146 30-Dec-02 DTH Added automatic system id broadcast\r
147 27-Dec-02 DTH Merged Mark Pizzolato's enhancements with main source\r
148 20-Dec-02 MP Fix bug that caused VMS system crashes when attempting cluster\r
149 operations. Added additional conditionally compiled debug\r
150 info needed to track down the issue.\r
151 17-Dec-02 MP Added SIMH "registers" describing the Ethernet state\r
152 so this information can be recorded in a "saved" snapshot.\r
153 05-Dec-02 MP Adjusted the rtime value from 100 to 2500 which increased the\r
154 available CPU cycles for Instruction execution by almost 100%.\r
155 This made sense after the below enhancements which, in general\r
156 caused the draining of the received data stream much more\r
157 agressively with less overhead.\r
158 05-Dec-02 MP Added a call to xq_svc after all successful calls to eth_write\r
159 to allow receive processing to happen before the next event\r
160 service time.\r
161 05-Dec-02 MP Restructured the flow of processing in xq_svc so that eth_read\r
162 is called repeatedly until either a packet isn't found or\r
163 there is no room for another one in the queue. Once that has\r
164 been done, xq_process_rdbl is called to pass the queued packets\r
165 into the simulated system as space is available there.\r
166 xq_process_rdbl is also called at the beginning of xq_svc to\r
167 drain the queue into the simulated system, making more room\r
168 available in the queue. No processing is done at all in\r
169 xq_svc if the receiver is disabled.\r
170 04-Dec-02 MP Changed interface and usage to xq_insert_queue to pass\r
171 the packet to be inserted by reference. This avoids 3K bytes\r
172 of buffer copy operations for each packet received. Now only\r
173 copy actual received packet data.\r
174 31-Oct-02 DTH Cleaned up pointer warnings (found by Federico Schwindt)\r
175 Corrected unattached and no network behavior\r
176 Added message when SHOW XQ ETH finds no devices\r
177 23-Oct-02 DTH Beta 5 released\r
178 22-Oct-02 DTH Added all_multicast and promiscuous support\r
179 21-Oct-02 DTH Added write buffer max size check (code by Jason Thorpe)\r
180 Corrected copyright again\r
181 Implemented NXM testing and recovery\r
182 16-Oct-02 DTH Beta 4 released\r
183 Added and debugged Sanity Timer code\r
184 Corrected copyright\r
185 15-Oct-02 DTH Rollback to known good Beta3 and roll forward; TCP broken\r
186 12-Oct-02 DTH Fixed VAX network bootstrap; setup packets must return TDR > 0\r
187 11-Oct-02 DTH Added SET/SHOW XQ TYPE and SET/SHOW XQ SANITY commands\r
188 10-Oct-02 DTH Beta 3 released; Integrated with 2.10-0b1\r
189 Fixed off-by-1 bug on xq->setup.macs[7..13]\r
190 Added xq_make_checksum\r
191 Added rejection of multicast addresses in SET XQ MAC\r
192 08-Oct-02 DTH Beta 2 released; Integrated with 2.10-0p4\r
193 Added variable vector (fixes PDP11) and copyrights\r
194 03-Oct-02 DTH Beta version of xq/sim_ether released for SIMH 2.09-11\r
195 24-Sep-02 DTH Moved more code to Sim_Ether module, added SHOW ETH command\r
196 23-Sep-02 DTH Added SET/SHOW MAC command\r
197 22-Sep-02 DTH Multinet TCP/IP loaded, tests OK via SET HOST/TELNET\r
198 20-Sep-02 DTH Cleaned up code fragments, fixed non-DECNET MAC use\r
199 19-Sep-02 DTH DECNET finally stays up; successful SET HOST to another node\r
200 15-Sep-02 DTH Added ethernet packet read/write\r
201 13-Sep-02 DTH DECNET starts, but circuit keeps going up & down\r
202 26-Aug-02 DTH DECNET loaded, returns device timeout\r
203 22-Aug-02 DTH VMS 7.2 recognizes device as XQA0\r
204 18-Aug-02 DTH VAX sees device as XQA0; shows hardcoded MAC correctly\r
205 15-Aug-02 DTH Started XQ simulation\r
206\r
207 ------------------------------------------------------------------------------\r
208*/\r
209\r
210#include <assert.h>\r
211#include "pdp11_xq.h"\r
212#include "pdp11_xq_bootrom.h"\r
213\r
214extern int32 tmxr_poll;\r
215extern FILE* sim_deb;\r
216extern char* read_line (char *ptr, int32 size, FILE *stream);\r
217\r
218/* forward declarations */\r
219t_stat xq_rd(int32* data, int32 PA, int32 access);\r
220t_stat xq_wr(int32 data, int32 PA, int32 access);\r
221t_stat xq_svc(UNIT * uptr);\r
222t_stat xq_reset (DEVICE * dptr);\r
223t_stat xq_attach (UNIT * uptr, char * cptr);\r
224t_stat xq_detach (UNIT * uptr);\r
225t_stat xq_showmac (FILE* st, UNIT* uptr, int32 val, void* desc);\r
226t_stat xq_setmac (UNIT* uptr, int32 val, char* cptr, void* desc);\r
227t_stat xq_show_filters (FILE* st, UNIT* uptr, int32 val, void* desc);\r
228t_stat xq_show_stats (FILE* st, UNIT* uptr, int32 val, void* desc);\r
229t_stat xq_set_stats (UNIT* uptr, int32 val, char* cptr, void* desc);\r
230t_stat xq_show_type (FILE* st, UNIT* uptr, int32 val, void* desc);\r
231t_stat xq_set_type (UNIT* uptr, int32 val, char* cptr, void* desc);\r
232t_stat xq_show_sanity (FILE* st, UNIT* uptr, int32 val, void* desc);\r
233t_stat xq_set_sanity (UNIT* uptr, int32 val, char* cptr, void* desc);\r
234t_stat xq_show_poll (FILE* st, UNIT* uptr, int32 val, void* desc);\r
235t_stat xq_set_poll (UNIT* uptr, int32 val, char* cptr, void* desc);\r
236t_stat xq_process_xbdl(CTLR* xq);\r
237t_stat xq_dispatch_xbdl(CTLR* xq);\r
238void xq_start_receiver(void);\r
239void xq_sw_reset(CTLR* xq);\r
240t_stat xq_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);\r
241t_stat xq_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);\r
242void xq_reset_santmr(CTLR* xq);\r
243t_stat xq_boot_host(CTLR* xq);\r
244t_stat xq_system_id(CTLR* xq, const ETH_MAC dst, uint16 receipt_id);\r
245void xqa_read_callback(int status);\r
246void xqb_read_callback(int status);\r
247void xqa_write_callback(int status);\r
248void xqb_write_callback(int status);\r
249void xq_setint (CTLR* xq);\r
250void xq_clrint (CTLR* xq);\r
251int32 xq_int (void);\r
252void xq_csr_set_clr(CTLR* xq, uint16 set_bits, uint16 clear_bits);\r
253\r
254struct xq_device xqa = {\r
255 xqa_read_callback, /* read callback routine */\r
256 xqa_write_callback, /* write callback routine */\r
257 {0x08, 0x00, 0x2B, 0xAA, 0xBB, 0xCC}, /* mac */\r
258 XQ_T_DELQA, /* type */\r
259 XQ_SERVICE_INTERVAL, /* poll */\r
260 {0} /* sanity */\r
261 };\r
262\r
263struct xq_device xqb = {\r
264 xqb_read_callback, /* read callback routine */\r
265 xqb_write_callback, /* write callback routine */\r
266 {0x08, 0x00, 0x2B, 0xBB, 0xCC, 0xDD}, /* mac */\r
267 XQ_T_DELQA, /* type */\r
268 XQ_SERVICE_INTERVAL, /* poll */\r
269 {0} /* sanity */\r
270 };\r
271\r
272/* SIMH device structures */\r
273DIB xqa_dib = { IOBA_XQ, IOLN_XQ, &xq_rd, &xq_wr,\r
274 1, IVCL (XQ), 0, { &xq_int } };\r
275\r
276UNIT xqa_unit[] = {\r
277 { UDATA (&xq_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE, 2047) }, /* receive timer */\r
278};\r
279\r
280REG xqa_reg[] = {\r
281 { GRDATA ( SA0, xqa.addr[0], XQ_RDX, 8, 0), REG_RO|REG_FIT},\r
282 { GRDATA ( SA1, xqa.addr[1], XQ_RDX, 8, 0), REG_RO|REG_FIT},\r
283 { GRDATA ( SA2, xqa.addr[2], XQ_RDX, 8, 0), REG_RO|REG_FIT},\r
284 { GRDATA ( SA3, xqa.addr[3], XQ_RDX, 8, 0), REG_RO|REG_FIT},\r
285 { GRDATA ( SA4, xqa.addr[4], XQ_RDX, 8, 0), REG_RO|REG_FIT},\r
286 { GRDATA ( SA5, xqa.addr[5], XQ_RDX, 8, 0), REG_RO|REG_FIT},\r
287 { GRDATA ( RBDL, xqa.rbdl[0], XQ_RDX, 16, 0), REG_FIT },\r
288 { GRDATA ( RBDH, xqa.rbdl[1], XQ_RDX, 16, 0), REG_FIT },\r
289 { GRDATA ( XBDL, xqa.xbdl[0], XQ_RDX, 16, 0), REG_FIT },\r
290 { GRDATA ( XBDH, xqa.xbdl[1], XQ_RDX, 16, 0), REG_FIT },\r
291 { GRDATA ( VAR, xqa.var, XQ_RDX, 16, 0), REG_FIT },\r
292 { GRDATA ( CSR, xqa.csr, XQ_RDX, 16, 0), REG_FIT },\r
293 { FLDATA ( INT, xqa.irq, 0) },\r
294 { GRDATA ( SETUP_PRM, xqa.setup.promiscuous, XQ_RDX, 32, 0), REG_HRO},\r
295 { GRDATA ( SETUP_MLT, xqa.setup.multicast, XQ_RDX, 32, 0), REG_HRO},\r
296 { GRDATA ( SETUP_L1, xqa.setup.l1, XQ_RDX, 32, 0), REG_HRO},\r
297 { GRDATA ( SETUP_L2, xqa.setup.l2, XQ_RDX, 32, 0), REG_HRO},\r
298 { GRDATA ( SETUP_L3, xqa.setup.l3, XQ_RDX, 32, 0), REG_HRO},\r
299 { GRDATA ( SETUP_SAN, xqa.setup.sanity_timer, XQ_RDX, 32, 0), REG_HRO},\r
300 { BRDATA ( SETUP_MACS, &xqa.setup.macs, XQ_RDX, 8, sizeof(xqa.setup.macs)), REG_HRO},\r
301 { NULL },\r
302};\r
303\r
304DIB xqb_dib = { IOBA_XQB, IOLN_XQB, &xq_rd, &xq_wr,\r
305 1, IVCL (XQ), 0, { &xq_int } };\r
306\r
307UNIT xqb_unit[] = {\r
308 { UDATA (&xq_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE, 2047) }, /* receive timer */\r
309};\r
310\r
311REG xqb_reg[] = {\r
312 { GRDATA ( SA0, xqb.addr[0], XQ_RDX, 8, 0), REG_RO|REG_FIT},\r
313 { GRDATA ( SA1, xqb.addr[1], XQ_RDX, 8, 0), REG_RO|REG_FIT},\r
314 { GRDATA ( SA2, xqb.addr[2], XQ_RDX, 8, 0), REG_RO|REG_FIT},\r
315 { GRDATA ( SA3, xqb.addr[3], XQ_RDX, 8, 0), REG_RO|REG_FIT},\r
316 { GRDATA ( SA4, xqb.addr[4], XQ_RDX, 8, 0), REG_RO|REG_FIT},\r
317 { GRDATA ( SA5, xqb.addr[5], XQ_RDX, 8, 0), REG_RO|REG_FIT},\r
318 { GRDATA ( RBDL, xqb.rbdl[0], XQ_RDX, 16, 0), REG_FIT },\r
319 { GRDATA ( RBDH, xqb.rbdl[1], XQ_RDX, 16, 0), REG_FIT },\r
320 { GRDATA ( XBDL, xqb.xbdl[0], XQ_RDX, 16, 0), REG_FIT },\r
321 { GRDATA ( XBDH, xqb.xbdl[1], XQ_RDX, 16, 0), REG_FIT },\r
322 { GRDATA ( VAR, xqb.var, XQ_RDX, 16, 0), REG_FIT },\r
323 { GRDATA ( CSR, xqb.csr, XQ_RDX, 16, 0), REG_FIT },\r
324 { FLDATA ( INT, xqb.irq, 0) },\r
325 { GRDATA ( SETUP_PRM, xqb.setup.promiscuous, XQ_RDX, 32, 0), REG_HRO},\r
326 { GRDATA ( SETUP_MLT, xqb.setup.multicast, XQ_RDX, 32, 0), REG_HRO},\r
327 { GRDATA ( SETUP_L1, xqb.setup.l1, XQ_RDX, 32, 0), REG_HRO},\r
328 { GRDATA ( SETUP_L2, xqb.setup.l2, XQ_RDX, 32, 0), REG_HRO},\r
329 { GRDATA ( SETUP_L3, xqb.setup.l3, XQ_RDX, 32, 0), REG_HRO},\r
330 { GRDATA ( SETUP_SAN, xqb.setup.sanity_timer, XQ_RDX, 32, 0), REG_HRO},\r
331 { BRDATA ( SETUP_MACS, &xqb.setup.macs, XQ_RDX, 8, sizeof(xqb.setup.macs)), REG_HRO},\r
332 { NULL },\r
333};\r
334\r
335MTAB xq_mod[] = {\r
336 { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", NULL,\r
337 NULL, &show_addr, NULL },\r
338 { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL,\r
339 NULL, &show_vec, NULL },\r
340 { MTAB_XTD | MTAB_VDV, 0, "MAC", "MAC=xx:xx:xx:xx:xx:xx",\r
341 &xq_setmac, &xq_showmac, NULL },\r
342 { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "ETH", "ETH",\r
343 NULL, &eth_show, NULL },\r
344 { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "FILTERS", "FILTERS",\r
345 NULL, &xq_show_filters, NULL },\r
346 { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATS", "STATS",\r
347 &xq_set_stats, &xq_show_stats, NULL },\r
348 { MTAB_XTD | MTAB_VDV, 0, "TYPE", "TYPE={DEQNA|DELQA}",\r
349 &xq_set_type, &xq_show_type, NULL },\r
350 { MTAB_XTD | MTAB_VDV, 0, "POLL", "POLL={DEFAULT|4..2500]",\r
351 &xq_set_poll, &xq_show_poll, NULL },\r
352 { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "SANITY", "SANITY={ON|OFF}",\r
353 &xq_set_sanity, &xq_show_sanity, NULL },\r
354 { 0 },\r
355};\r
356\r
357DEBTAB xq_debug[] = {\r
358 {"TRACE", DBG_TRC},\r
359 {"CSR", DBG_CSR},\r
360 {"VAR", DBG_VAR},\r
361 {"WARN", DBG_WRN},\r
362 {"SETUP", DBG_SET},\r
363 {"SANITY", DBG_SAN},\r
364 {"REG", DBG_REG},\r
365 {"PACKET", DBG_PCK},\r
366 {"ETH", DBG_ETH},\r
367 {0}\r
368};\r
369\r
370DEVICE xq_dev = {\r
371 "XQ", xqa_unit, xqa_reg, xq_mod,\r
372 1, XQ_RDX, 11, 1, XQ_RDX, 16,\r
373 &xq_ex, &xq_dep, &xq_reset,\r
374 NULL, &xq_attach, &xq_detach,\r
375 &xqa_dib, DEV_DISABLE | DEV_QBUS | DEV_DEBUG,\r
376 0, xq_debug\r
377};\r
378\r
379DEVICE xqb_dev = {\r
380 "XQB", xqb_unit, xqb_reg, xq_mod,\r
381 1, XQ_RDX, 11, 1, XQ_RDX, 16,\r
382 &xq_ex, &xq_dep, &xq_reset,\r
383 NULL, &xq_attach, &xq_detach,\r
384 &xqb_dib, DEV_DISABLE | DEV_DIS | DEV_QBUS | DEV_DEBUG,\r
385 0, xq_debug\r
386};\r
387\r
388CTLR xq_ctrl[] = {\r
389 {&xq_dev, xqa_unit, &xqa_dib, &xqa}, /* XQA controller */\r
390 {&xqb_dev, xqb_unit, &xqb_dib, &xqb} /* XQB controller */\r
391};\r
392\r
393const char* const xq_recv_regnames[] = {\r
394 "MAC0", "MAC1", "MAC2", "MAC3", "MAC4", "MAC5", "VAR", "CSR"\r
395};\r
396\r
397const char* const xq_xmit_regnames[] = {\r
398 "", "", "RBDL-Lo", "RBDL-Hi", "XBDL-Lo", "XBDL-Hi", "VAR", "CSR"\r
399};\r
400\r
401const char* const xq_csr_bits[] = {\r
402 "RE", "SR", "NI", "BD", "XL", "RL", "IE", "XI",\r
403 "IL", "EL", "SE", "RR", "OK", "CA", "PE", "RI"\r
404};\r
405\r
406const char* const xq_var_bits[] = {\r
407 "ID", "RR", "V0", "V1", "V2", "V3", "V4", "V5",\r
408 "V6", "V7", "S1", "S2", "S3", "RS", "OS", "MS"\r
409};\r
410\r
411/* internal debugging routines */\r
412void xq_debug_setup(CTLR* xq);\r
413\r
414/*============================================================================*/\r
415\r
416/* Multicontroller support */\r
417\r
418CTLR* xq_unit2ctlr(UNIT* uptr)\r
419{\r
420 unsigned int i,j;\r
421 for (i=0; i<XQ_MAX_CONTROLLERS; i++)\r
422 for (j=0; j<xq_ctrl[i].dev->numunits; j++)\r
423 if (&xq_ctrl[i].unit[j] == uptr)\r
424 return &xq_ctrl[i];\r
425 /* not found */\r
426 return 0;\r
427}\r
428\r
429CTLR* xq_dev2ctlr(DEVICE* dptr)\r
430{\r
431 int i;\r
432 for (i=0; i<XQ_MAX_CONTROLLERS; i++)\r
433 if (xq_ctrl[i].dev == dptr)\r
434 return &xq_ctrl[i];\r
435 /* not found */\r
436 return 0;\r
437}\r
438\r
439CTLR* xq_pa2ctlr(uint32 PA)\r
440{\r
441 int i;\r
442 for (i=0; i<XQ_MAX_CONTROLLERS; i++)\r
443 if ((PA >= xq_ctrl[i].dib->ba) && (PA < (xq_ctrl[i].dib->ba + xq_ctrl[i].dib->lnt)))\r
444 return &xq_ctrl[i];\r
445 /* not found */\r
446 return 0;\r
447}\r
448\r
449/*============================================================================*/\r
450\r
451/* stop simh from reading non-existant unit data stream */\r
452t_stat xq_ex (t_value* vptr, t_addr addr, UNIT* uptr, int32 sw)\r
453{\r
454 /* on PDP-11, allow EX command to look at bootrom */\r
455#ifdef VM_PDP11\r
456 if (addr <= sizeof(xq_bootrom)/2)\r
457 *vptr = xq_bootrom[addr];\r
458 else\r
459 *vptr = 0;\r
460 return SCPE_OK;\r
461#else\r
462 return SCPE_NOFNC;\r
463#endif\r
464}\r
465\r
466/* stop simh from writing non-existant unit data stream */\r
467t_stat xq_dep (t_value val, t_addr addr, UNIT* uptr, int32 sw)\r
468{\r
469 return SCPE_NOFNC;\r
470}\r
471\r
472t_stat xq_showmac (FILE* st, UNIT* uptr, int32 val, void* desc)\r
473{\r
474 CTLR* xq = xq_unit2ctlr(uptr);\r
475 char buffer[20];\r
476\r
477 eth_mac_fmt((ETH_MAC*)xq->var->mac, buffer);\r
478 fprintf(st, "MAC=%s", buffer);\r
479 return SCPE_OK;\r
480}\r
481\r
482void xq_make_checksum(CTLR* xq)\r
483{\r
484 /* checksum calculation routine detailed in vaxboot.zip/xqbtdrivr.mar */\r
485 uint32 checksum = 0;\r
486 const uint32 wmask = 0xFFFF;\r
487 int i;\r
488\r
489 for (i = 0; i < sizeof(ETH_MAC); i += 2) {\r
490 checksum <<= 1;\r
491 if (checksum > wmask)\r
492 checksum -= wmask;\r
493 checksum += (xq->var->mac[i] << 8) | xq->var->mac[i+1];\r
494 if (checksum > wmask)\r
495 checksum -= wmask;\r
496 }\r
497 if (checksum == wmask)\r
498 checksum = 0;\r
499\r
500 /* set checksum bytes */\r
501 xq->var->mac_checksum[0] = checksum & 0xFF;\r
502 xq->var->mac_checksum[1] = checksum >> 8;\r
503}\r
504\r
505t_stat xq_setmac (UNIT* uptr, int32 val, char* cptr, void* desc)\r
506{\r
507 t_stat status;\r
508 CTLR* xq = xq_unit2ctlr(uptr);\r
509\r
510 if (!cptr) return SCPE_IERR;\r
511 if (uptr->flags & UNIT_ATT) return SCPE_ALATT;\r
512 status = eth_mac_scan(&xq->var->mac, cptr);\r
513 if (status != SCPE_OK)\r
514 return status;\r
515\r
516 /* calculate mac checksum */\r
517 xq_make_checksum(xq);\r
518 return SCPE_OK;\r
519}\r
520\r
521t_stat xq_set_stats (UNIT* uptr, int32 val, char* cptr, void* desc)\r
522{\r
523 /* this sets all ints in the stats structure to the integer passed */\r
524 CTLR* xq = xq_unit2ctlr(uptr);\r
525\r
526 if (cptr) {\r
527 /* set individual stats to passed parameter value */\r
528 int init = atoi(cptr);\r
529 int* stat_array = (int*) &xq->var->stats;\r
530 int elements = sizeof(struct xq_stats)/sizeof(int);\r
531 int i;\r
532 for (i=0; i<elements; i++)\r
533 stat_array[i] = init;\r
534 } else {\r
535 /* set stats to zero */\r
536 memset(&xq->var->stats, 0, sizeof(struct xq_stats));\r
537 }\r
538 return SCPE_OK;\r
539}\r
540\r
541t_stat xq_show_stats (FILE* st, UNIT* uptr, int32 val, void* desc)\r
542{\r
543 char* fmt = " %-15s%d\n";\r
544 CTLR* xq = xq_unit2ctlr(uptr);\r
545\r
546 fprintf(st, "Ethernet statistics:\n");\r
547 fprintf(st, fmt, "Recv:", xq->var->stats.recv);\r
548 fprintf(st, fmt, "Filtered:", xq->var->stats.filter);\r
549 fprintf(st, fmt, "Xmit:", xq->var->stats.xmit);\r
550 fprintf(st, fmt, "Xmit Fail:", xq->var->stats.fail);\r
551 fprintf(st, fmt, "Runts:", xq->var->stats.runt);\r
552 fprintf(st, fmt, "Oversize:", xq->var->stats.giant);\r
553 fprintf(st, fmt, "Setup:", xq->var->stats.setup);\r
554 fprintf(st, fmt, "Loopback:", xq->var->stats.loop);\r
555 fprintf(st, fmt, "ReadQ high:", xq->var->ReadQ.high);\r
556 return SCPE_OK;\r
557}\r
558\r
559t_stat xq_show_filters (FILE* st, UNIT* uptr, int32 val, void* desc)\r
560{\r
561 CTLR* xq = xq_unit2ctlr(uptr);\r
562 char buffer[20];\r
563 int i;\r
564\r
565 fprintf(st, "Filters:\n");\r
566 for (i=0; i<XQ_FILTER_MAX; i++) {\r
567 eth_mac_fmt((ETH_MAC*)xq->var->setup.macs[i], buffer);\r
568 fprintf(st, " [%2d]: %s\n", i, buffer);\r
569 };\r
570 if (xq->var->setup.multicast)\r
571 fprintf(st, "All Multicast Receive Mode\n");\r
572 if (xq->var->setup.promiscuous)\r
573 fprintf(st, "Promiscuous Receive Mode\n");\r
574 return SCPE_OK;\r
575}\r
576\r
577t_stat xq_show_type (FILE* st, UNIT* uptr, int32 val, void* desc)\r
578{\r
579 CTLR* xq = xq_unit2ctlr(uptr);\r
580 fprintf(st, "type=");\r
581 switch (xq->var->type) {\r
582 case XQ_T_DEQNA: fprintf(st, "DEQNA"); break;\r
583 case XQ_T_DELQA: fprintf(st, "DELQA"); break;\r
584 }\r
585 return SCPE_OK;\r
586}\r
587\r
588t_stat xq_set_type (UNIT* uptr, int32 val, char* cptr, void* desc)\r
589{\r
590 CTLR* xq = xq_unit2ctlr(uptr);\r
591 if (!cptr) return SCPE_IERR;\r
592 if (uptr->flags & UNIT_ATT) return SCPE_ALATT;\r
593\r
594 /* this assumes that the parameter has already been upcased */\r
595 if (!strcmp(cptr, "DEQNA")) xq->var->type = XQ_T_DEQNA;\r
596 else if (!strcmp(cptr, "DELQA")) xq->var->type = XQ_T_DELQA;\r
597 else return SCPE_ARG;\r
598\r
599 return SCPE_OK;\r
600}\r
601\r
602t_stat xq_show_poll (FILE* st, UNIT* uptr, int32 val, void* desc)\r
603{\r
604 CTLR* xq = xq_unit2ctlr(uptr);\r
605 fprintf(st, "poll=%d", xq->var->poll);\r
606 return SCPE_OK;\r
607}\r
608\r
609t_stat xq_set_poll (UNIT* uptr, int32 val, char* cptr, void* desc)\r
610{\r
611 CTLR* xq = xq_unit2ctlr(uptr);\r
612 if (!cptr) return SCPE_IERR;\r
613 if (uptr->flags & UNIT_ATT) return SCPE_ALATT;\r
614\r
615 /* this assumes that the parameter has already been upcased */\r
616 if (!strcmp(cptr, "DEFAULT"))\r
617 xq->var->poll = XQ_SERVICE_INTERVAL;\r
618 else {\r
619 int newpoll = 0;\r
620 sscanf(cptr, "%d", &newpoll);\r
621 if ((newpoll >= 4) && (newpoll <= 2500))\r
622 xq->var->poll = newpoll;\r
623 else\r
624 return SCPE_ARG;\r
625 }\r
626\r
627 return SCPE_OK;\r
628}\r
629\r
630t_stat xq_show_sanity (FILE* st, UNIT* uptr, int32 val, void* desc)\r
631{\r
632 CTLR* xq = xq_unit2ctlr(uptr);\r
633\r
634 fprintf(st, "sanity=");\r
635 switch (xq->var->sanity.enabled) {\r
636 case 2: fprintf(st, "ON\n"); break;\r
637 default: fprintf(st, "OFF\n"); break;\r
638 }\r
639 return SCPE_OK;\r
640}\r
641\r
642t_stat xq_set_sanity (UNIT* uptr, int32 val, char* cptr, void* desc)\r
643{\r
644 CTLR* xq = xq_unit2ctlr(uptr);\r
645 if (!cptr) return SCPE_IERR;\r
646 if (uptr->flags & UNIT_ATT) return SCPE_ALATT;\r
647\r
648 /* this assumes that the parameter has already been upcased */\r
649 if (!strcmp(cptr, "ON")) xq->var->sanity.enabled = 2;\r
650 else if (!strcmp(cptr, "OFF")) xq->var->sanity.enabled = 0;\r
651 else return SCPE_ARG;\r
652\r
653 return SCPE_OK;\r
654}\r
655\r
656/*============================================================================*/\r
657\r
658t_stat xq_nxm_error(CTLR* xq)\r
659{\r
660 const uint16 set_bits = XQ_CSR_NI | XQ_CSR_XI | XQ_CSR_XL | XQ_CSR_RL;\r
661 sim_debug(DBG_WRN, xq->dev, "Non Existent Memory Error!\n");\r
662\r
663 /* set NXM and associated bits in CSR */\r
664 xq_csr_set_clr(xq, set_bits , 0);\r
665 return SCPE_OK;\r
666}\r
667\r
668/*\r
669** write callback\r
670*/\r
671void xq_write_callback (CTLR* xq, int status)\r
672{\r
673 t_stat rstatus;\r
674 int32 wstatus;\r
675 const uint16 TDR = 100 + xq->var->write_buffer.len * 8; /* arbitrary value */\r
676 uint16 write_success[2] = {0};\r
677 uint16 write_failure[2] = {XQ_DSC_C};\r
678 write_success[1] = TDR & 0x03FF; /* Does TDR get set on successful packets ?? */\r
679 write_failure[1] = TDR & 0x03FF; /* TSW2<09:00> */\r
680 \r
681 xq->var->stats.xmit += 1;\r
682 /* update write status words */\r
683 if (status == 0) { /* success */\r
684 wstatus = Map_WriteW(xq->var->xbdl_ba + 8, 4, write_success);\r
685 } else { /* failure */\r
686 sim_debug(DBG_WRN, xq->dev, "Packet Write Error!\n");\r
687 xq->var->stats.fail += 1;\r
688 wstatus = Map_WriteW(xq->var->xbdl_ba + 8, 4, write_failure);\r
689 }\r
690 if (wstatus) {\r
691 xq_nxm_error(xq);\r
692 return;\r
693 }\r
694\r
695 /* update csr */\r
696 xq_csr_set_clr(xq, XQ_CSR_XI, 0);\r
697\r
698 /* reset sanity timer */\r
699 xq_reset_santmr(xq);\r
700\r
701 /* clear write buffer */\r
702 xq->var->write_buffer.len = 0;\r
703\r
704 /* next descriptor (implicit) */\r
705 xq->var->xbdl_ba += 12;\r
706\r
707 /* finish processing xbdl */\r
708 rstatus = xq_process_xbdl(xq);\r
709}\r
710\r
711void xqa_write_callback (int status)\r
712{\r
713 xq_write_callback(&xq_ctrl[0], status);\r
714}\r
715\r
716void xqb_write_callback (int status)\r
717{\r
718 xq_write_callback(&xq_ctrl[1], status);\r
719}\r
720\r
721/* read registers: */\r
722t_stat xq_rd(int32* data, int32 PA, int32 access)\r
723{\r
724 CTLR* xq = xq_pa2ctlr(PA);\r
725 int index = (PA >> 1) & 07; /* word index */\r
726\r
727 sim_debug(DBG_REG, xq->dev, "xq_rd(PA=0x%08X [%s], access=%d)\n", PA, xq_recv_regnames[index], access);\r
728 switch (index) {\r
729 case 0:\r
730 case 1:\r
731 /* return checksum in external loopback mode */\r
732 if (xq->var->csr & XQ_CSR_EL)\r
733 *data = 0xFF00 | xq->var->mac_checksum[index];\r
734 else\r
735 *data = 0xFF00 | xq->var->mac[index];\r
736 break;\r
737 case 2:\r
738 case 3:\r
739 case 4:\r
740 case 5:\r
741 *data = 0xFF00 | xq->var->mac[index];\r
742 break;\r
743 case 6:\r
744 sim_debug_u16(DBG_VAR, xq->dev, xq_var_bits, xq->var->var, xq->var->var, 0);\r
745 sim_debug (DBG_VAR, xq->dev, ", vec = 0%o\n", (xq->var->var & XQ_VEC_IV));\r
746 *data = xq->var->var;\r
747 break;\r
748 case 7:\r
749 sim_debug_u16(DBG_CSR, xq->dev, xq_csr_bits, xq->var->csr, xq->var->csr, 1);\r
750 *data = xq->var->csr;\r
751 break;\r
752 }\r
753 return SCPE_OK;\r
754}\r
755\r
756\r
757/* dispatch ethernet read request\r
758 procedure documented in sec. 3.2.2 */\r
759\r
760t_stat xq_process_rbdl(CTLR* xq)\r
761{\r
762 int32 rstatus, wstatus;\r
763 uint16 b_length, w_length, rbl;\r
764 uint32 address;\r
765 ETH_ITEM* item;\r
766 uint8* rbuf;\r
767\r
768 sim_debug(DBG_TRC, xq->dev, "xq_process_rdbl\n");\r
769\r
770 /* process buffer descriptors */\r
771 while(1) {\r
772\r
773 /* get receive bdl from memory */\r
774 xq->var->rbdl_buf[0] = 0xFFFF;\r
775 wstatus = Map_WriteW(xq->var->rbdl_ba, 2, &xq->var->rbdl_buf[0]);\r
776 rstatus = Map_ReadW (xq->var->rbdl_ba + 2, 6, &xq->var->rbdl_buf[1]);\r
777 if (rstatus || wstatus) return xq_nxm_error(xq);\r
778\r
779 /* invalid buffer? */\r
780 if (~xq->var->rbdl_buf[1] & XQ_DSC_V) {\r
781 xq_csr_set_clr(xq, XQ_CSR_RL, 0);\r
782 return SCPE_OK;\r
783 }\r
784\r
785 /* explicit chain buffer? */\r
786 if (xq->var->rbdl_buf[1] & XQ_DSC_C) {\r
787 xq->var->rbdl_ba = ((xq->var->rbdl_buf[1] & 0x3F) << 16) | xq->var->rbdl_buf[2];\r
788 continue;\r
789 }\r
790\r
791 /* stop processing if nothing in read queue */\r
792 if (!xq->var->ReadQ.count) break;\r
793\r
794 /* get status words */\r
795 rstatus = Map_ReadW(xq->var->rbdl_ba + 8, 4, &xq->var->rbdl_buf[4]);\r
796 if (rstatus) return xq_nxm_error(xq);\r
797\r
798 /* get host memory address */\r
799 address = ((xq->var->rbdl_buf[1] & 0x3F) << 16) | xq->var->rbdl_buf[2];\r
800\r
801 /* decode buffer length - two's complement (in words) */\r
802 w_length = ~xq->var->rbdl_buf[3] + 1;\r
803 b_length = w_length * 2;\r
804 if (xq->var->rbdl_buf[1] & XQ_DSC_H) b_length -= 1;\r
805 if (xq->var->rbdl_buf[1] & XQ_DSC_L) b_length -= 1;\r
806\r
807 item = &xq->var->ReadQ.item[xq->var->ReadQ.head];\r
808 rbl = item->packet.len;\r
809 rbuf = item->packet.msg;\r
810\r
811 /* see if packet must be size-adjusted or is splitting */\r
812 if (item->packet.used) {\r
813 int used = item->packet.used;\r
814 rbl -= used;\r
815 rbuf = &item->packet.msg[used];\r
816 } else {\r
817 /* adjust runt packets */\r
818 if (rbl < ETH_MIN_PACKET) {\r
819 xq->var->stats.runt += 1;\r
820 sim_debug(DBG_WRN, xq->dev, "Runt detected, size = %d\n", rbl);\r
821 /* pad runts with zeros up to minimum size - this allows "legal" (size - 60)\r
822 processing of those weird short ARP packets that seem to occur occasionally */\r
823 memset(&item->packet.msg[rbl], 0, ETH_MIN_PACKET-rbl);\r
824 rbl = ETH_MIN_PACKET;\r
825 };\r
826\r
827 /* adjust oversized packets */\r
828 if (rbl > ETH_MAX_PACKET) {\r
829 xq->var->stats.giant += 1;\r
830 sim_debug(DBG_WRN, xq->dev, "Giant detected, size=%d\n", rbl);\r
831 /* trim giants down to maximum size - no documentation on how to handle the data loss */\r
832 item->packet.len = ETH_MAX_PACKET;\r
833 rbl = ETH_MAX_PACKET;\r
834 };\r
835 };\r
836\r
837 /* make sure entire packet fits in buffer - if not, will need to split into multiple buffers */\r
838 if (rbl > b_length)\r
839 rbl = b_length;\r
840 item->packet.used += rbl;\r
841 \r
842 /* send data to host */\r
843 wstatus = Map_WriteB(address, rbl, rbuf);\r
844 if (wstatus) return xq_nxm_error(xq);\r
845\r
846 /* set receive size into RBL - RBL<10:8> maps into Status1<10:8>,\r
847 RBL<7:0> maps into Status2<7:0>, and Status2<15:8> (copy) */\r
848\r
849 xq->var->rbdl_buf[4] = 0;\r
850 switch (item->type) {\r
851 case 0: /* setup packet */\r
852 xq->var->stats.setup += 1;\r
853 xq->var->rbdl_buf[4] = 0x2700; /* set esetup and RBL 10:8 */\r
854 break;\r
855 case 1: /* loopback packet */\r
856 xq->var->stats.loop += 1;\r
857 xq->var->rbdl_buf[4] = 0x2000; /* loopback flag */\r
858 xq->var->rbdl_buf[4] |= (rbl & 0x0700); /* high bits of rbl */\r
859 break;\r
860 case 2: /* normal packet */\r
861 rbl -= 60; /* keeps max packet size in 11 bits */\r
862 xq->var->rbdl_buf[4] = (rbl & 0x0700); /* high bits of rbl */\r
863 break;\r
864 }\r
865 if (item->packet.used < item->packet.len)\r
866 xq->var->rbdl_buf[4] |= 0xC000; /* not last segment */\r
867 xq->var->rbdl_buf[5] = ((rbl & 0x00FF) << 8) | (rbl & 0x00FF);\r
868 if (xq->var->ReadQ.loss) {\r
869 sim_debug(DBG_WRN, xq->dev, "ReadQ overflow!\n");\r
870 xq->var->rbdl_buf[4] |= 0x0001; /* set overflow bit */\r
871 xq->var->ReadQ.loss = 0; /* reset loss counter */\r
872 }\r
873\r
874 /* update read status words*/\r
875 wstatus = Map_WriteW(xq->var->rbdl_ba + 8, 4, &xq->var->rbdl_buf[4]);\r
876 if (wstatus) return xq_nxm_error(xq);\r
877\r
878 /* remove packet from queue */\r
879 if (item->packet.used >= item->packet.len)\r
880 ethq_remove(&xq->var->ReadQ);\r
881\r
882 /* mark transmission complete */\r
883 xq_csr_set_clr(xq, XQ_CSR_RI, 0);\r
884\r
885 /* set to next bdl (implicit chain) */\r
886 xq->var->rbdl_ba += 12;\r
887\r
888 } /* while */\r
889\r
890 return SCPE_OK;\r
891}\r
892\r
893t_stat xq_process_mop(CTLR* xq)\r
894{\r
895 uint32 address;\r
896 uint16 size;\r
897 int32 wstatus;\r
898 struct xq_meb* meb = (struct xq_meb*) &xq->var->write_buffer.msg[0200];\r
899 const struct xq_meb* limit = (struct xq_meb*) &xq->var->write_buffer.msg[0400];\r
900\r
901 sim_debug(DBG_TRC, xq->dev, "xq_process_mop()\n");\r
902\r
903 if (xq->var->type == XQ_T_DEQNA) /* DEQNA's don't MOP */\r
904 return SCPE_NOFNC;\r
905\r
906 while ((meb->type != 0) && (meb < limit)) {\r
907 address = (meb->add_hi << 16) || (meb->add_mi << 8) || meb->add_lo;\r
908 size = (meb->siz_hi << 8) || meb->siz_lo;\r
909\r
910 /* MOP stuff here - NOT YET FULLY IMPLEMENTED */\r
911 sim_debug (DBG_WRN, xq->dev, "Processing MEB type: %d\n", meb->type);\r
912 switch (meb->type) {\r
913 case 0: /* MOP Termination */\r
914 break;\r
915 case 1: /* MOP Read Ethernet Address */\r
916 wstatus = Map_WriteB(address, sizeof(ETH_MAC), (uint8*) &xq->var->setup.macs[0]);\r
917 if (wstatus) return xq_nxm_error(xq);\r
918 break;\r
919 case 2: /* MOP Reset System ID */\r
920 break;\r
921 case 3: /* MOP Read Last MOP Boot */\r
922 break;\r
923 case 4: /* MOP Read Boot Password */\r
924 break;\r
925 case 5: /* MOP Write Boot Password */\r
926 break;\r
927 case 6: /* MOP Read System ID */\r
928 break;\r
929 case 7: /* MOP Write System ID */\r
930 break;\r
931 case 8: /* MOP Read Counters */\r
932 break;\r
933 case 9: /* Mop Read/Clear Counters */\r
934 break;\r
935 } /* switch */\r
936\r
937 /* process next meb */\r
938 meb += sizeof(struct xq_meb);\r
939\r
940 } /* while */\r
941 return SCPE_OK;\r
942}\r
943\r
944t_stat xq_process_setup(CTLR* xq)\r
945{\r
946 int i,j;\r
947 int count = 0;\r
948 float secs;\r
949 t_stat status;\r
950 ETH_MAC zeros = {0, 0, 0, 0, 0, 0};\r
951 ETH_MAC filters[XQ_FILTER_MAX + 1];\r
952\r
953 sim_debug(DBG_TRC, xq->dev, "xq_process_setup()\n");\r
954\r
955 /* extract filter addresses from setup packet */\r
956 memset(xq->var->setup.macs, '\0', sizeof(xq->var->setup.macs));\r
957 for (i = 0; i < 7; i++)\r
958 for (j = 0; j < 6; j++) {\r
959 xq->var->setup.macs[i] [j] = xq->var->write_buffer.msg[(i + 01) + (j * 8)];\r
960 if (xq->var->write_buffer.len > 112)\r
961 xq->var->setup.macs[i+7][j] = xq->var->write_buffer.msg[(i + 0101) + (j * 8)];\r
962 }\r
963\r
964 /*\r
965 Under VMS the setup packet that is passed to turn promiscuous \r
966 off after it has been on doesn't seem to follow the rules documented \r
967 in both the DEQNA and DELQA manuals.\r
968 These rules seem to say that setup packets less than 128 should only \r
969 modify the address filter set and probably not the All-Multicast and \r
970 Promiscuous modes, however, VMS V5-5 and V7.3 seem to send a 127 byte \r
971 packet to turn this functionality off. I'm not sure how real hardware \r
972 behaves in this case, since the only consequence is extra interrupt \r
973 load. To realize and retain the benefits of the newly added BPF \r
974 functionality in sim_ether, I've modified the logic implemented here\r
975 to disable Promiscuous mode when a "small" setup packet is processed.\r
976 I'm deliberately not modifying the All-Multicast mode the same way\r
977 since I don't have an observable case of its behavior. These two \r
978 different modes come from very different usage situations:\r
979 1) Promiscuous mode is usually entered for relatively short periods \r
980 of time due to the needs of a specific application program which\r
981 is doing some sort of management/monitoring function (i.e. tcpdump)\r
982 2) All-Multicast mode is only entered by the OS Kernel Port Driver\r
983 when it happens to have clients (usually network stacks or service \r
984 programs) which as a group need to listen to more multicast ethernet\r
985 addresses than the 12 (or so) which the hardware supports directly.\r
986 so, I believe that the All-Multicast mode, is first rarely used, and if \r
987 it ever is used, once set, it will probably be set either forever or for \r
988 long periods of time, and the additional interrupt processing load to\r
989 deal with the distinctly lower multicast traffic set is clearly lower than\r
990 that of the promiscuous mode.\r
991 */\r
992 xq->var->setup.promiscuous = 0;\r
993 /* process high byte count */\r
994 if (xq->var->write_buffer.len > 128) {\r
995 uint16 len = xq->var->write_buffer.len;\r
996 uint16 led, san;\r
997\r
998 xq->var->setup.multicast = (0 != (len & XQ_SETUP_MC));\r
999 xq->var->setup.promiscuous = (0 != (len & XQ_SETUP_PM));\r
1000 if (led = (len & XQ_SETUP_LD) >> 2) {\r
1001 switch (led) {\r
1002 case 1: xq->var->setup.l1 = 0; break;\r
1003 case 2: xq->var->setup.l2 = 0; break;\r
1004 case 3: xq->var->setup.l3 = 0; break;\r
1005 } /* switch */\r
1006 } /* if led */\r
1007\r
1008 /* set sanity timer timeout */\r
1009 san = (len & XQ_SETUP_ST) >> 4;\r
1010 switch(san) {\r
1011 case 0: secs = 0.25; break; /* 1/4 second */\r
1012 case 1: secs = 1; break; /* 1 second */\r
1013 case 2: secs = 4; break; /* 4 seconds */\r
1014 case 3: secs = 16; break; /* 16 seconds */\r
1015 case 4: secs = 1 * 60; break; /* 1 minute */\r
1016 case 5: secs = 4 * 60; break; /* 4 minutes */\r
1017 case 6: secs = 16 * 60; break; /* 16 minutes */\r
1018 case 7: secs = 64 * 60; break; /* 64 minutes */\r
1019 }\r
1020 xq->var->sanity.quarter_secs = (int) (secs * 4);\r
1021 xq->var->sanity.max = (int) (secs * xq->var->poll);\r
1022 }\r
1023\r
1024 /* finalize sanity timer state */\r
1025 xq->var->sanity.timer = xq->var->sanity.max;\r
1026 if (xq->var->sanity.enabled != 2) {\r
1027 if (xq->var->csr & XQ_CSR_SE)\r
1028 xq->var->sanity.enabled = 1;\r
1029 else\r
1030 xq->var->sanity.enabled = 0;\r
1031 }\r
1032\r
1033 /* set ethernet filter */\r
1034 /* memcpy (filters[count++], xq->mac, sizeof(ETH_MAC)); */\r
1035 for (i = 0; i < XQ_FILTER_MAX; i++)\r
1036 if (memcmp(zeros, &xq->var->setup.macs[i], sizeof(ETH_MAC)))\r
1037 memcpy (filters[count++], xq->var->setup.macs[i], sizeof(ETH_MAC));\r
1038 status = eth_filter (xq->var->etherface, count, filters, xq->var->setup.multicast, xq->var->setup.promiscuous);\r
1039\r
1040 /* process MOP information */\r
1041 if (xq->var->write_buffer.msg[0])\r
1042 status = xq_process_mop(xq);\r
1043\r
1044 /* mark setup block valid */\r
1045 xq->var->setup.valid = 1;\r
1046\r
1047 if (sim_deb && (xq->dev->dctrl & DBG_SET))\r
1048 xq_debug_setup(xq);\r
1049 return SCPE_OK;\r
1050}\r
1051\r
1052/*\r
1053 Dispatch Write Operation\r
1054\r
1055 The DELQA manual does not explicitly state whether or not multiple packets\r
1056 can be written in one transmit operation, so a maximum of 1 packet is assumed.\r
1057\r
1058*/\r
1059t_stat xq_process_xbdl(CTLR* xq)\r
1060{\r
1061 const uint16 implicit_chain_status[2] = {XQ_DSC_V | XQ_DSC_C, 1};\r
1062 const uint16 write_success[2] = {0, 1 /*Non-Zero TDR*/};\r
1063 uint16 b_length, w_length;\r
1064 int32 rstatus, wstatus;\r
1065 uint32 address;\r
1066 t_stat status;\r
1067\r
1068 sim_debug(DBG_TRC, xq->dev, "xq_process_xbdl()\n");\r
1069\r
1070 /* clear write buffer */\r
1071 xq->var->write_buffer.len = 0;\r
1072\r
1073 /* process buffer descriptors until not valid */\r
1074 while (1) {\r
1075\r
1076 /* Get transmit bdl from memory */\r
1077 rstatus = Map_ReadW (xq->var->xbdl_ba, 12, &xq->var->xbdl_buf[0]);\r
1078 xq->var->xbdl_buf[0] = 0xFFFF;\r
1079 wstatus = Map_WriteW(xq->var->xbdl_ba, 2, &xq->var->xbdl_buf[0]);\r
1080 if (rstatus || wstatus) return xq_nxm_error(xq);\r
1081\r
1082 /* invalid buffer? */\r
1083 if (~xq->var->xbdl_buf[1] & XQ_DSC_V) {\r
1084 xq_csr_set_clr(xq, XQ_CSR_XL, 0);\r
1085 sim_debug(DBG_WRN, xq->dev, "XBDL List empty\n");\r
1086 return SCPE_OK;\r
1087 }\r
1088\r
1089 /* compute host memory address */\r
1090 address = ((xq->var->xbdl_buf[1] & 0x3F) << 16) | xq->var->xbdl_buf[2];\r
1091\r
1092 /* decode buffer length - two's complement (in words) */\r
1093 w_length = ~xq->var->xbdl_buf[3] + 1;\r
1094 b_length = w_length * 2;\r
1095 if (xq->var->xbdl_buf[1] & XQ_DSC_H) b_length -= 1;\r
1096 if (xq->var->xbdl_buf[1] & XQ_DSC_L) b_length -= 1;\r
1097\r
1098 /* explicit chain buffer? */\r
1099 if (xq->var->xbdl_buf[1] & XQ_DSC_C) {\r
1100 xq->var->xbdl_ba = address;\r
1101 sim_debug(DBG_WRN, xq->dev, "XBDL chained buffer encountered: %d\n", b_length);\r
1102 continue;\r
1103 }\r
1104\r
1105 /* add to transmit buffer, making sure it's not too big */\r
1106 if ((xq->var->write_buffer.len + b_length) > sizeof(xq->var->write_buffer.msg))\r
1107 b_length = sizeof(xq->var->write_buffer.msg) - xq->var->write_buffer.len;\r
1108 rstatus = Map_ReadB(address, b_length, &xq->var->write_buffer.msg[xq->var->write_buffer.len]);\r
1109 if (rstatus) return xq_nxm_error(xq);\r
1110 xq->var->write_buffer.len += b_length;\r
1111\r
1112 /* end of message? */\r
1113 if (xq->var->xbdl_buf[1] & XQ_DSC_E) {\r
1114 if (((~xq->var->csr & XQ_CSR_RE) && ((~xq->var->csr & XQ_CSR_IL) || (xq->var->csr & XQ_CSR_EL))) || /* loopback */\r
1115 (xq->var->xbdl_buf[1] & XQ_DSC_S)) { /* or setup packet (forces loopback regardless of state) */\r
1116 if (xq->var->xbdl_buf[1] & XQ_DSC_S) { /* setup packet */\r
1117 status = xq_process_setup(xq);\r
1118\r
1119 /* put packet in read buffer */\r
1120 ethq_insert (&xq->var->ReadQ, 0, &xq->var->write_buffer, status);\r
1121 } else { /* loopback */\r
1122 /* put packet in read buffer */\r
1123 ethq_insert (&xq->var->ReadQ, 1, &xq->var->write_buffer, 0);\r
1124 }\r
1125\r
1126 /* update write status */\r
1127 wstatus = Map_WriteW(xq->var->xbdl_ba + 8, 4, (uint16*) write_success);\r
1128 if (wstatus) return xq_nxm_error(xq);\r
1129\r
1130 /* clear write buffer */\r
1131 xq->var->write_buffer.len = 0;\r
1132\r
1133 /* reset sanity timer */\r
1134 xq_reset_santmr(xq);\r
1135\r
1136 /* mark transmission complete */\r
1137 xq_csr_set_clr(xq, XQ_CSR_XI, 0);\r
1138\r
1139 /* now trigger "read" of setup or loopback packet */\r
1140 if (~xq->var->csr & XQ_CSR_RL)\r
1141 status = xq_process_rbdl(xq);\r
1142\r
1143 } else { /* not loopback */\r
1144\r
1145 status = eth_write(xq->var->etherface, &xq->var->write_buffer, xq->var->wcallback);\r
1146 if (status != SCPE_OK) /* not implemented or unattached */\r
1147 xq_write_callback(xq, 1); /* fake failure */\r
1148#if 0\r
1149 else\r
1150 xq_svc(&xq->unit[0]); /* service any received data */\r
1151#endif\r
1152 sim_debug(DBG_WRN, xq->dev, "XBDL completed processing write\n");\r
1153 return SCPE_OK;\r
1154\r
1155 } /* loopback/non-loopback */\r
1156 } else { /* not at end-of-message */\r
1157\r
1158 sim_debug(DBG_WRN, xq->dev, "XBDL processing implicit chain buffer segment\n");\r
1159 /* update bdl status words */\r
1160 wstatus = Map_WriteW(xq->var->xbdl_ba + 8, 4, (uint16*) implicit_chain_status);\r
1161 if(wstatus) return xq_nxm_error(xq);\r
1162 }\r
1163\r
1164 /* set to next bdl (implicit chain) */\r
1165 xq->var->xbdl_ba += 12;\r
1166\r
1167 } /* while */\r
1168}\r
1169\r
1170t_stat xq_dispatch_rbdl(CTLR* xq)\r
1171{\r
1172 int i;\r
1173 int32 rstatus, wstatus;\r
1174 t_stat status;\r
1175\r
1176 sim_debug(DBG_TRC, xq->dev, "xq_dispatch_rbdl()\n");\r
1177\r
1178 /* mark receive bdl valid */\r
1179 xq_csr_set_clr(xq, 0, XQ_CSR_RL);\r
1180\r
1181 /* init receive bdl buffer */\r
1182 for (i=0; i<6; i++)\r
1183 xq->var->rbdl_buf[i] = 0;\r
1184\r
1185 /* get address of first receive buffer */\r
1186 xq->var->rbdl_ba = ((xq->var->rbdl[1] & 0x3F) << 16) | (xq->var->rbdl[0] & ~01);\r
1187\r
1188 /* get first receive buffer */\r
1189 xq->var->rbdl_buf[0] = 0xFFFF;\r
1190 wstatus = Map_WriteW(xq->var->rbdl_ba, 2, &xq->var->rbdl_buf[0]);\r
1191 rstatus = Map_ReadW (xq->var->rbdl_ba + 2, 6, &xq->var->rbdl_buf[1]);\r
1192 if (rstatus || wstatus) return xq_nxm_error(xq);\r
1193\r
1194 /* is buffer valid? */\r
1195 if (~xq->var->rbdl_buf[1] & XQ_DSC_V) {\r
1196 xq_csr_set_clr(xq, XQ_CSR_RL, 0);\r
1197 return SCPE_OK;\r
1198 }\r
1199\r
1200 /* process any waiting packets in receive queue */\r
1201 if (xq->var->ReadQ.count)\r
1202 status = xq_process_rbdl(xq);\r
1203\r
1204 return SCPE_OK;\r
1205}\r
1206\r
1207t_stat xq_dispatch_xbdl(CTLR* xq)\r
1208{\r
1209 int i;\r
1210 t_stat status;\r
1211\r
1212 sim_debug(DBG_TRC, xq->dev, "xq_dispatch_xbdl()\n");\r
1213\r
1214 /* mark transmit bdl valid */\r
1215 xq_csr_set_clr(xq, 0, XQ_CSR_XL);\r
1216\r
1217 /* initialize transmit bdl buffers */\r
1218 for (i=0; i<6; i++)\r
1219 xq->var->xbdl_buf[i] = 0;\r
1220\r
1221 /* clear transmit buffer */\r
1222 xq->var->write_buffer.len = 0;\r
1223\r
1224 /* get base address of first transmit descriptor */\r
1225 xq->var->xbdl_ba = ((xq->var->xbdl[1] & 0x3F) << 16) | (xq->var->xbdl[0] & ~01);\r
1226\r
1227 /* process xbdl */\r
1228 status = xq_process_xbdl(xq);\r
1229\r
1230 return status;\r
1231}\r
1232\r
1233t_stat xq_process_loopback(CTLR* xq, ETH_PACK* pack)\r
1234{\r
1235 ETH_PACK reply;\r
1236 ETH_MAC physical_address;\r
1237 t_stat status;\r
1238 int offset = pack->msg[14] | (pack->msg[15] << 8);\r
1239 int function = pack->msg[offset] | (pack->msg[offset+1] << 8);\r
1240\r
1241 sim_debug(DBG_TRC, xq->dev, "xq_process_loopback()\n");\r
1242\r
1243 if (function != 2 /*forward*/)\r
1244 return SCPE_NOFNC;\r
1245\r
1246 /* create reply packet */\r
1247 memcpy (&reply, pack, sizeof(ETH_PACK));\r
1248 memcpy (physical_address, xq->var->setup.valid ? xq->var->setup.macs[0] : xq->var->mac, sizeof(ETH_MAC));\r
1249 memcpy (&reply.msg[0], &reply.msg[offset+2], sizeof(ETH_MAC));\r
1250 memcpy (&reply.msg[6], physical_address, sizeof(ETH_MAC));\r
1251 memcpy (&reply.msg[offset+2], physical_address, sizeof(ETH_MAC));\r
1252 reply.msg[offset] = 0x01;\r
1253 offset += 8;\r
1254 reply.msg[14] = offset & 0xFF;\r
1255 reply.msg[15] = (offset >> 8) & 0xFF;\r
1256\r
1257 /* send reply packet */\r
1258 status = eth_write(xq->var->etherface, &reply, NULL);\r
1259\r
1260 return status;\r
1261}\r
1262\r
1263t_stat xq_process_remote_console (CTLR* xq, ETH_PACK* pack)\r
1264{\r
1265 t_stat status;\r
1266 ETH_MAC source;\r
1267 uint16 receipt;\r
1268 int code = pack->msg[16];\r
1269\r
1270 sim_debug(DBG_TRC, xq->dev, "xq_process_remote_console()\n");\r
1271\r
1272 switch (code) {\r
1273 case 0x05: /* request id */\r
1274 receipt = pack->msg[18] | (pack->msg[19] << 8);\r
1275 memcpy(source, &pack->msg[6], sizeof(ETH_MAC));\r
1276\r
1277 /* send system id to requestor */\r
1278 status = xq_system_id (xq, source, receipt);\r
1279 return status;\r
1280 break;\r
1281 case 0x06: /* boot */\r
1282 /*\r
1283 NOTE: the verification field should be checked here against the\r
1284 verification value established in the setup packet. If they match the\r
1285 reboot should occur, otherwise nothing happens, and the packet\r
1286 is passed on to the host.\r
1287\r
1288 Verification is not implemented, since the setup packet processing code\r
1289 isn't complete yet.\r
1290\r
1291 Various values are also passed: processor, control, and software id.\r
1292 These control the various boot parameters, however SIMH does not\r
1293 have a mechanism to pass these to the host, so just reboot.\r
1294 */\r
1295\r
1296 status = xq_boot_host(xq);\r
1297 return status;\r
1298 break;\r
1299 } /* switch */\r
1300\r
1301 return SCPE_NOFNC;\r
1302}\r
1303\r
1304t_stat xq_process_local (CTLR* xq, ETH_PACK* pack)\r
1305{\r
1306 /* returns SCPE_OK if local processing occurred,\r
1307 otherwise returns SCPE_NOFNC or some other code */\r
1308 int protocol;\r
1309\r
1310 sim_debug(DBG_TRC, xq->dev, "xq_process_local()\n");\r
1311 /* DEQNA's have no local processing capability */\r
1312 if (xq->var->type == XQ_T_DEQNA)\r
1313 return SCPE_NOFNC;\r
1314\r
1315 protocol = pack->msg[12] | (pack->msg[13] << 8);\r
1316 switch (protocol) {\r
1317 case 0x0090: /* ethernet loopback */\r
1318 return xq_process_loopback(xq, pack);\r
1319 break;\r
1320 case 0x0260: /* MOP remote console */\r
1321 return xq_process_remote_console(xq, pack);\r
1322 break;\r
1323 }\r
1324 return SCPE_NOFNC;\r
1325}\r
1326\r
1327void xq_read_callback(CTLR* xq, int status)\r
1328{\r
1329 xq->var->stats.recv += 1;\r
1330 if (xq->var->csr & XQ_CSR_RE) { /* receiver enabled */\r
1331\r
1332 /* process any packets locally that can be */\r
1333 t_stat status = xq_process_local (xq, &xq->var->read_buffer);\r
1334\r
1335 /* add packet to read queue */\r
1336 if (status != SCPE_OK)\r
1337 ethq_insert(&xq->var->ReadQ, 2, &xq->var->read_buffer, status);\r
1338 } else {\r
1339 sim_debug(DBG_WRN, xq->dev, "packet received with receiver disabled\n");\r
1340 }\r
1341}\r
1342\r
1343void xqa_read_callback(int status)\r
1344{\r
1345 xq_read_callback(&xq_ctrl[0], status);\r
1346}\r
1347\r
1348void xqb_read_callback(int status)\r
1349{\r
1350 xq_read_callback(&xq_ctrl[1], status);\r
1351}\r
1352\r
1353void xq_sw_reset(CTLR* xq)\r
1354{\r
1355 const uint16 set_bits = XQ_CSR_XL | XQ_CSR_RL;\r
1356 int i;\r
1357\r
1358 sim_debug(DBG_TRC, xq->dev, "xq_sw_reset()\n");\r
1359\r
1360 /* reset csr bits */\r
1361 xq_csr_set_clr(xq, set_bits, (uint16) ~set_bits);\r
1362\r
1363 if (xq->var->etherface)\r
1364 xq_csr_set_clr(xq, XQ_CSR_OK, 0);\r
1365\r
1366 /* clear interrupt unconditionally */\r
1367 xq_clrint(xq);\r
1368\r
1369 /* flush read queue */\r
1370 ethq_clear(&xq->var->ReadQ);\r
1371\r
1372 /* clear setup info */\r
1373 xq->var->setup.multicast = 0;\r
1374 xq->var->setup.promiscuous = 0;\r
1375 if (xq->var->etherface) {\r
1376 int count = 0;\r
1377 ETH_MAC zeros = {0, 0, 0, 0, 0, 0};\r
1378 ETH_MAC filters[XQ_FILTER_MAX + 1];\r
1379\r
1380 /* set ethernet filter */\r
1381 /* memcpy (filters[count++], xq->mac, sizeof(ETH_MAC)); */\r
1382 for (i = 0; i < XQ_FILTER_MAX; i++)\r
1383 if (memcmp(zeros, &xq->var->setup.macs[i], sizeof(ETH_MAC)))\r
1384 memcpy (filters[count++], xq->var->setup.macs[i], sizeof(ETH_MAC));\r
1385 eth_filter (xq->var->etherface, count, filters, xq->var->setup.multicast, xq->var->setup.promiscuous);\r
1386 }\r
1387}\r
1388\r
1389/* write registers: */\r
1390\r
1391t_stat xq_wr_var(CTLR* xq, int32 data)\r
1392{\r
1393 uint16 save_var = xq->var->var;\r
1394 sim_debug(DBG_REG, xq->dev, "xq_wr_var(data= 0x%08X\n", data);\r
1395 \r
1396 switch (xq->var->type) {\r
1397 case XQ_T_DEQNA:\r
1398 xq->var->var = (data & XQ_VEC_IV);\r
1399 break;\r
1400 case XQ_T_DELQA:\r
1401 xq->var->var = (xq->var->var & XQ_VEC_RO) | (data & XQ_VEC_RW);\r
1402\r
1403 /* if switching to DEQNA-LOCK mode clear VAR<14:10> */\r
1404 if (~xq->var->var & XQ_VEC_MS)\r
1405 xq->var->var &= ~(XQ_VEC_OS | XQ_VEC_RS | XQ_VEC_ST);\r
1406 break;\r
1407 }\r
1408\r
1409 /* set vector of SIMH device */\r
1410 if (data & XQ_VEC_IV)\r
1411 xq->dib->vec = (data & XQ_VEC_IV) + VEC_Q;\r
1412 else\r
1413 xq->dib->vec = 0;\r
1414\r
1415 sim_debug_u16(DBG_VAR, xq->dev, xq_var_bits, save_var, xq->var->var, 1);\r
1416\r
1417 return SCPE_OK;\r
1418}\r
1419\r
1420#ifdef VM_PDP11\r
1421t_stat xq_process_bootrom (CTLR* xq)\r
1422{\r
1423 /*\r
1424 NOTE: BOOT ROMs are a PDP-11ism, since they contain PDP-11 binary code.\r
1425 the host is responsible for creating two *2KB* receive buffers.\r
1426\r
1427 RSTS/E v10.1 source (INIONE.MAR/XHLOOK:) indicates that both the DEQNA and\r
1428 DELQA will set receive status word 1 bits 15 & 14 on both packets. It also\r
1429 states that a hardware bug in the DEQNA will set receive status word 1 bit 15\r
1430 (only) in the *third* receive buffer (oops!).\r
1431\r
1432 RSTS/E v10.1 will run the Citizenship test from the bootrom after loading it.\r
1433 Documentation on the Boot ROM can be found in INIQNA.MAR.\r
1434 */\r
1435\r
1436 int32 rstatus, wstatus;\r
1437 uint16 b_length, w_length;\r
1438 uint32 address;\r
1439 uint8* bootrom = (uint8*) xq_bootrom;\r
1440 int i, checksum;\r
1441\r
1442 sim_debug(DBG_TRC, xq->dev, "xq_process_bootrom()\n");\r
1443\r
1444 /*\r
1445 RSTS/E v10.1 invokes the Citizenship tests in the Bootrom. For some\r
1446 reason, the current state of the XQ emulator cannot pass these. So,\r
1447 to get moving on RSTE/E support, we will replace the following line in\r
1448 INIQNA.MAR/CITQNA::\r
1449 70$: MOV (R2),R0 ;get the status word\r
1450 with\r
1451 70$: CLR R0 ;force success\r
1452 to cause the Citizenship test to return success to RSTS/E.\r
1453\r
1454 At some point, the real problem (failure to pass citizenship diagnostics)\r
1455 does need to be corrected to find incompatibilities in the emulation, and to\r
1456 ultimately allow it to pass Digital hardware diagnostic tests.\r
1457 */\r
1458 for (i=0; i<sizeof(xq_bootrom)/2; i++)\r
1459 if (xq_bootrom[i] == 011200) { /* MOV (R2),R0 */\r
1460 xq_bootrom[i] = 005000; /* CLR R0 */\r
1461 break;\r
1462 }\r
1463\r
1464 /* recalculate checksum, which is a simple byte sum */\r
1465 for (i=0, checksum=0; i<sizeof(xq_bootrom)-2; i++)\r
1466 checksum += bootrom[i];\r
1467\r
1468 /* set new checksum */\r
1469 xq_bootrom[sizeof(xq_bootrom)/2-1] = checksum;\r
1470\r
1471 /* --------------------------- bootrom part 1 -----------------------------*/\r
1472\r
1473 /* get receive bdl from memory */\r
1474 xq->var->rbdl_buf[0] = 0xFFFF;\r
1475 wstatus = Map_WriteW(xq->var->rbdl_ba, 2, &xq->var->rbdl_buf[0]);\r
1476 rstatus = Map_ReadW (xq->var->rbdl_ba + 2, 6, &xq->var->rbdl_buf[1]);\r
1477 if (rstatus || wstatus) return xq_nxm_error(xq);\r
1478\r
1479 /* invalid buffer? */\r
1480 if (~xq->var->rbdl_buf[1] & XQ_DSC_V) {\r
1481 xq_csr_set_clr(xq, XQ_CSR_RL, 0);\r
1482 return SCPE_OK;\r
1483 }\r
1484\r
1485 /* get status words */\r
1486 rstatus = Map_ReadW(xq->var->rbdl_ba + 8, 4, &xq->var->rbdl_buf[4]);\r
1487 if (rstatus) return xq_nxm_error(xq);\r
1488\r
1489 /* get host memory address */\r
1490 address = ((xq->var->rbdl_buf[1] & 0x3F) << 16) | xq->var->rbdl_buf[2];\r
1491\r
1492 /* decode buffer length - two's complement (in words) */\r
1493 w_length = ~xq->var->rbdl_buf[3] + 1;\r
1494 b_length = w_length * 2;\r
1495 if (xq->var->rbdl_buf[1] & XQ_DSC_H) b_length -= 1;\r
1496 if (xq->var->rbdl_buf[1] & XQ_DSC_L) b_length -= 1;\r
1497\r
1498 /* make sure entire packet fits in buffer */\r
1499 assert(b_length >= sizeof(xq_bootrom)/2);\r
1500\r
1501 /* send data to host */\r
1502 wstatus = Map_WriteB(address, sizeof(xq_bootrom)/2, bootrom);\r
1503 if (wstatus) return xq_nxm_error(xq);\r
1504\r
1505 /* update read status words */\r
1506 xq->var->rbdl_buf[4] = XQ_DSC_V | XQ_DSC_C; /* valid, chain */\r
1507 xq->var->rbdl_buf[5] = 0;\r
1508\r
1509 /* update read status words*/\r
1510 wstatus = Map_WriteW(xq->var->rbdl_ba + 8, 4, &xq->var->rbdl_buf[4]);\r
1511 if (wstatus) return xq_nxm_error(xq);\r
1512\r
1513 /* set to next bdl (implicit chain) */\r
1514 xq->var->rbdl_ba += 12;\r
1515\r
1516 /* --------------------------- bootrom part 2 -----------------------------*/\r
1517\r
1518 /* get receive bdl from memory */\r
1519 xq->var->rbdl_buf[0] = 0xFFFF;\r
1520 wstatus = Map_WriteW(xq->var->rbdl_ba, 2, &xq->var->rbdl_buf[0]);\r
1521 rstatus = Map_ReadW (xq->var->rbdl_ba + 2, 6, &xq->var->rbdl_buf[1]);\r
1522 if (rstatus || wstatus) return xq_nxm_error(xq);\r
1523\r
1524 /* invalid buffer? */\r
1525 if (~xq->var->rbdl_buf[1] & XQ_DSC_V) {\r
1526 xq_csr_set_clr(xq, XQ_CSR_RL, 0);\r
1527 return SCPE_OK;\r
1528 }\r
1529\r
1530 /* get status words */\r
1531 rstatus = Map_ReadW(xq->var->rbdl_ba + 8, 4, &xq->var->rbdl_buf[4]);\r
1532 if (rstatus) return xq_nxm_error(xq);\r
1533\r
1534 /* get host memory address */\r
1535 address = ((xq->var->rbdl_buf[1] & 0x3F) << 16) | xq->var->rbdl_buf[2];\r
1536\r
1537 /* decode buffer length - two's complement (in words) */\r
1538 w_length = ~xq->var->rbdl_buf[3] + 1;\r
1539 b_length = w_length * 2;\r
1540 if (xq->var->rbdl_buf[1] & XQ_DSC_H) b_length -= 1;\r
1541 if (xq->var->rbdl_buf[1] & XQ_DSC_L) b_length -= 1;\r
1542\r
1543 /* make sure entire packet fits in buffer */\r
1544 assert(b_length >= sizeof(xq_bootrom)/2);\r
1545\r
1546 /* send data to host */\r
1547 wstatus = Map_WriteB(address, sizeof(xq_bootrom)/2, &bootrom[2048]);\r
1548 if (wstatus) return xq_nxm_error(xq);\r
1549\r
1550 /* update read status words */\r
1551 xq->var->rbdl_buf[4] = XQ_DSC_V | XQ_DSC_C; /* valid, chain */\r
1552 xq->var->rbdl_buf[5] = 0;\r
1553\r
1554 /* update read status words*/\r
1555 wstatus = Map_WriteW(xq->var->rbdl_ba + 8, 4, &xq->var->rbdl_buf[4]);\r
1556 if (wstatus) return xq_nxm_error(xq);\r
1557\r
1558 /* set to next bdl (implicit chain) */\r
1559 xq->var->rbdl_ba += 12;\r
1560\r
1561 /* --------------------------- bootrom part 3 -----------------------------*/\r
1562\r
1563 switch (xq->var->type) {\r
1564 case XQ_T_DEQNA:\r
1565\r
1566 /* get receive bdl from memory */\r
1567 xq->var->rbdl_buf[0] = 0xFFFF;\r
1568 wstatus = Map_WriteW(xq->var->rbdl_ba, 2, &xq->var->rbdl_buf[0]);\r
1569 rstatus = Map_ReadW (xq->var->rbdl_ba + 2, 6, &xq->var->rbdl_buf[1]);\r
1570 if (rstatus || wstatus) return xq_nxm_error(xq);\r
1571\r
1572 /* invalid buffer? */\r
1573 if (~xq->var->rbdl_buf[1] & XQ_DSC_V) {\r
1574 xq_csr_set_clr(xq, XQ_CSR_RL, 0);\r
1575 return SCPE_OK;\r
1576 }\r
1577\r
1578 /* get status words */\r
1579 rstatus = Map_ReadW(xq->var->rbdl_ba + 8, 4, &xq->var->rbdl_buf[4]);\r
1580 if (rstatus) return xq_nxm_error(xq);\r
1581\r
1582 /* update read status words */\r
1583 xq->var->rbdl_buf[4] = XQ_DSC_V; /* valid */\r
1584 xq->var->rbdl_buf[5] = 0;\r
1585\r
1586 /* update read status words*/\r
1587 wstatus = Map_WriteW(xq->var->rbdl_ba + 8, 4, &xq->var->rbdl_buf[4]);\r
1588 if (wstatus) return xq_nxm_error(xq);\r
1589\r
1590 /* set to next bdl (implicit chain) */\r
1591 xq->var->rbdl_ba += 12;\r
1592 break;\r
1593 } /* switch */\r
1594\r
1595 /* --------------------------- Done, finish up -----------------------------*/\r
1596\r
1597 /* mark transmission complete */\r
1598 xq_csr_set_clr(xq, XQ_CSR_RI, 0);\r
1599\r
1600 /* reset sanity timer */\r
1601 xq_reset_santmr(xq);\r
1602\r
1603 return SCPE_OK;\r
1604}\r
1605#endif /* ifdef VM_PDP11 */\r
1606\r
1607t_stat xq_wr_csr(CTLR* xq, int32 data)\r
1608{\r
1609 uint16 set_bits = data & XQ_CSR_RW; /* set RW set bits */\r
1610 uint16 clr_bits = ((data ^ XQ_CSR_RW) & XQ_CSR_RW) /* clear RW cleared bits */\r
1611 | (data & XQ_CSR_W1) /* write 1 to clear bits */\r
1612 | ((data & XQ_CSR_XI) ? XQ_CSR_NI : 0); /* clearing XI clears NI */\r
1613\r
1614 sim_debug(DBG_REG, xq->dev, "xq_wr_csr(data=0x%08X)\n", data);\r
1615\r
1616 /* reset controller when SR transitions to cleared */\r
1617 if (xq->var->csr & XQ_CSR_SR & ~data) {\r
1618 xq_sw_reset(xq);\r
1619 return SCPE_OK;\r
1620 }\r
1621\r
1622#if 0 /* controller should ALWAYS have an active timer if enabled (for HW sanity) */\r
1623 /* start/stop receive timer when RE transitions */\r
1624 if ((xq->var->csr ^ data) & XQ_CSR_RE) {\r
1625 if (data & XQ_CSR_RE)\r
1626 sim_activate(&xq->unit[0], clock_cosched (tmxr_poll));\r
1627 else\r
1628 sim_cancel(&xq->unit[0]);\r
1629 }\r
1630#endif\r
1631\r
1632 /* update CSR bits */\r
1633 xq_csr_set_clr (xq, set_bits, clr_bits);\r
1634\r
1635#ifdef VM_PDP11\r
1636 /* request boot/diagnostic rom? [PDP-11 only] */\r
1637 if ((xq->var->csr & XQ_CSR_BP) == XQ_CSR_BP) /* all bits must be on */\r
1638 xq_process_bootrom(xq);\r
1639#endif\r
1640\r
1641 return SCPE_OK;\r
1642}\r
1643\r
1644t_stat xq_wr(int32 data, int32 PA, int32 access)\r
1645{\r
1646 t_stat status;\r
1647 CTLR* xq = xq_pa2ctlr(PA);\r
1648 int index = (PA >> 1) & 07; /* word index */\r
1649\r
1650 sim_debug(DBG_REG, xq->dev, "xq_wr(data=0x%08X, PA=0x%08X[%s], access=%d)\n", data, PA, xq_xmit_regnames[index], access);\r
1651\r
1652 switch (index) {\r
1653 case 0: /* these should not be written */\r
1654 case 1:\r
1655 break;\r
1656 case 2: /* receive bdl low bits */\r
1657 xq->var->rbdl[0] = data;\r
1658 break;\r
1659 case 3: /* receive bdl high bits */\r
1660 xq->var->rbdl[1] = data;\r
1661 status = xq_dispatch_rbdl(xq); /* start receive operation */\r
1662 break;\r
1663 case 4: /* transmit bdl low bits */\r
1664 xq->var->xbdl[0] = data;\r
1665 break;\r
1666 case 5: /* transmit bdl high bits */\r
1667 xq->var->xbdl[1] = data;\r
1668 status = xq_dispatch_xbdl(xq); /* start transmit operation */\r
1669 break;\r
1670 case 6: /* vector address register */\r
1671 status = xq_wr_var(xq, data);\r
1672 break;\r
1673 case 7: /* control and status register */\r
1674 status = xq_wr_csr(xq, data);\r
1675 break;\r
1676 }\r
1677 return SCPE_OK;\r
1678}\r
1679\r
1680\r
1681/* reset device */\r
1682t_stat xq_reset(DEVICE* dptr)\r
1683{\r
1684 t_stat status;\r
1685 CTLR* xq = xq_dev2ctlr(dptr);\r
1686 const uint16 set_bits = XQ_CSR_RL | XQ_CSR_XL;\r
1687\r
1688 sim_debug(DBG_TRC, xq->dev, "xq_reset()\n");\r
1689\r
1690 /* calculate MAC checksum */\r
1691 xq_make_checksum(xq);\r
1692\r
1693 /* init vector address register */\r
1694 switch (xq->var->type) {\r
1695 case XQ_T_DEQNA:\r
1696 xq->var->var = 0;\r
1697 break;\r
1698 case XQ_T_DELQA:\r
1699 xq->var->var = XQ_VEC_MS | XQ_VEC_OS;\r
1700 break;\r
1701 }\r
1702 xq->dib->vec = 0;\r
1703\r
1704 /* init control status register */\r
1705 xq_csr_set_clr(xq, set_bits, (uint16) ~set_bits);\r
1706\r
1707 /* clear interrupts unconditionally */\r
1708 xq_clrint(xq);\r
1709\r
1710 /* init read queue (first time only) */\r
1711 status = ethq_init(&xq->var->ReadQ, XQ_QUE_MAX);\r
1712 if (status != SCPE_OK)\r
1713 return status;\r
1714\r
1715 /* clear read queue */\r
1716 ethq_clear(&xq->var->ReadQ);\r
1717\r
1718 /* reset ethernet interface */\r
1719 if (xq->var->etherface) {\r
1720 status = eth_filter (xq->var->etherface, 1, &xq->var->mac, 0, 0);\r
1721 xq_csr_set_clr(xq, XQ_CSR_OK, 0);\r
1722\r
1723 /* start service timer */\r
1724 sim_activate_abs(&xq->unit[0], tmxr_poll);\r
1725 }\r
1726\r
1727 /* set hardware sanity controls */\r
1728 if (xq->var->sanity.enabled) {\r
1729 xq->var->sanity.quarter_secs = XQ_HW_SANITY_SECS * 4/*qsec*/;\r
1730 xq->var->sanity.max = XQ_HW_SANITY_SECS * xq->var->poll;\r
1731 }\r
1732 return SCPE_OK;\r
1733}\r
1734\r
1735void xq_reset_santmr(CTLR* xq)\r
1736{\r
1737 sim_debug(DBG_TRC, xq->dev, "xq_reset_santmr()\n");\r
1738 if (xq->var->sanity.enabled) {\r
1739 sim_debug(DBG_SAN, xq->dev, "SANITY TIMER RESETTING, qsecs: %d\n", xq->var->sanity.quarter_secs);\r
1740\r
1741 /* reset sanity countdown timer to max count */\r
1742 xq->var->sanity.timer = xq->var->sanity.max;\r
1743 }\r
1744}\r
1745\r
1746t_stat xq_boot_host(CTLR* xq)\r
1747{\r
1748 sim_debug(DBG_TRC, xq->dev, "xq_boot_host()\n");\r
1749 /*\r
1750 The manual says the hardware should force the Qbus BDCOK low for\r
1751 3.6 microseconds, which will cause the host to reboot.\r
1752\r
1753 Since the SIMH Qbus emulator does not have this functionality, we call\r
1754 a special STOP_ code, and let the CPU stop dispatch routine decide\r
1755 what the appropriate cpu-specific behavior should be.\r
1756 */\r
1757 return STOP_SANITY;\r
1758}\r
1759\r
1760t_stat xq_system_id (CTLR* xq, const ETH_MAC dest, uint16 receipt_id)\r
1761{\r
1762 static uint16 receipt = 0;\r
1763 ETH_PACK system_id;\r
1764 uint8* const msg = &system_id.msg[0];\r
1765 t_stat status;\r
1766\r
1767 sim_debug(DBG_TRC, xq->dev, "xq_system_id()\n");\r
1768 if (xq->var->type != XQ_T_DELQA) /* DELQA-only function */\r
1769 return SCPE_NOFNC; \r
1770\r
1771 memset (&system_id, 0, sizeof(system_id));\r
1772 memcpy (&msg[0], dest, sizeof(ETH_MAC));\r
1773 memcpy (&msg[6], xq->var->setup.valid ? xq->var->setup.macs[0] : xq->var->mac, sizeof(ETH_MAC));\r
1774 msg[12] = 0x60; /* type */\r
1775 msg[13] = 0x02; /* type */\r
1776 msg[14] = 0x1C; /* character count */\r
1777 msg[15] = 0x00; /* character count */\r
1778 msg[16] = 0x07; /* code */\r
1779 msg[17] = 0x00; /* zero pad */\r
1780 if (receipt_id) {\r
1781 msg[18] = receipt_id & 0xFF; /* receipt number */\r
1782 msg[19] = (receipt_id >> 8) & 0xFF; /* receipt number */\r
1783 } else {\r
1784 msg[18] = receipt & 0xFF; /* receipt number */\r
1785 msg[19] = (receipt++ >> 8) & 0xFF; /* receipt number */\r
1786 }\r
1787\r
1788 /* MOP VERSION */\r
1789 msg[20] = 0x01; /* type */\r
1790 msg[21] = 0x00; /* type */\r
1791 msg[22] = 0x03; /* length */\r
1792 msg[23] = 0x03; /* version */\r
1793 msg[24] = 0x01; /* eco */\r
1794 msg[25] = 0x00; /* user eco */\r
1795\r
1796 /* FUNCTION */\r
1797 msg[26] = 0x02; /* type */\r
1798 msg[27] = 0x00; /* type */\r
1799 msg[28] = 0x02; /* length */\r
1800 msg[29] = 0x00; /* value 1 ??? */\r
1801 msg[30] = 0x00; /* value 2 */\r
1802\r
1803 /* HARDWARE ADDRESS */\r
1804 msg[31] = 0x07; /* type */\r
1805 msg[32] = 0x00; /* type */\r
1806 msg[33] = 0x06; /* length */\r
1807 memcpy (&msg[34], xq->var->mac, sizeof(ETH_MAC)); /* ROM address */\r
1808\r
1809 /* DEVICE TYPE */\r
1810 msg[40] = 37; /* type */\r
1811 msg[41] = 0x00; /* type */\r
1812 msg[42] = 0x01; /* length */\r
1813 msg[43] = 0x11; /* value (0x11=DELQA) */\r
1814\r
1815 /* write system id */\r
1816 system_id.len = 60;\r
1817 status = eth_write(xq->var->etherface, &system_id, NULL);\r
1818\r
1819 return status;\r
1820}\r
1821\r
1822/*\r
1823** service routine - used for ethernet reading loop\r
1824*/\r
1825t_stat xq_svc(UNIT* uptr)\r
1826{\r
1827 CTLR* xq = xq_unit2ctlr(uptr);\r
1828\r
1829 /* if the receiver is enabled */\r
1830 if (xq->var->csr & XQ_CSR_RE) {\r
1831 t_stat status;\r
1832 int queue_size;\r
1833\r
1834 /* First pump any queued packets into the system */\r
1835 if ((xq->var->ReadQ.count > 0) && (~xq->var->csr & XQ_CSR_RL))\r
1836 status = xq_process_rbdl(xq);\r
1837\r
1838 /* Now read and queue packets that have arrived */\r
1839 /* This is repeated as long as they are available and we have room */\r
1840 do\r
1841 {\r
1842 queue_size = xq->var->ReadQ.count;\r
1843 /* read a packet from the ethernet - processing is via the callback */\r
1844 status = eth_read (xq->var->etherface, &xq->var->read_buffer, xq->var->rcallback);\r
1845 } while (queue_size != xq->var->ReadQ.count);\r
1846\r
1847 /* Now pump any still queued packets into the system */\r
1848 if ((xq->var->ReadQ.count > 0) && (~xq->var->csr & XQ_CSR_RL))\r
1849 status = xq_process_rbdl(xq);\r
1850 }\r
1851\r
1852 /* has sanity timer expired? if so, reboot */\r
1853 if (xq->var->sanity.enabled)\r
1854 if (--xq->var->sanity.timer <= 0)\r
1855 xq_boot_host(xq);\r
1856\r
1857 /* has system id timer expired? if so, do system id */\r
1858 if (--xq->var->idtmr <= 0) {\r
1859 const ETH_MAC mop_multicast = {0xAB, 0x00, 0x00, 0x02, 0x00, 0x00};\r
1860 xq_system_id(xq, mop_multicast, 0);\r
1861\r
1862 /* reset system ID counter for next event */\r
1863 xq->var->idtmr = XQ_SYSTEM_ID_SECS * xq->var->poll;\r
1864 }\r
1865\r
1866 /* resubmit service timer */\r
1867 sim_activate(&xq->unit[0], tmxr_poll);\r
1868\r
1869 return SCPE_OK;\r
1870}\r
1871\r
1872\r
1873/* attach device: */\r
1874t_stat xq_attach(UNIT* uptr, char* cptr)\r
1875{\r
1876 t_stat status;\r
1877 char* tptr;\r
1878 CTLR* xq = xq_unit2ctlr(uptr);\r
1879 char buffer[80]; /* buffer for runtime input */\r
1880\r
1881 sim_debug(DBG_TRC, xq->dev, "xq_attach(cptr=%s)\n", cptr);\r
1882\r
1883 /* runtime selection of ethernet port? */\r
1884 if (*cptr == '?') { /* I/O style derived from main() */\r
1885 memset (buffer, 0, sizeof(buffer)); /* clear read buffer */\r
1886 eth_show (stdout, uptr, 0, NULL); /* show ETH devices */\r
1887 printf ("Select device (ethX or <device_name>)? "); /* prompt for device */\r
1888 cptr = read_line (buffer, sizeof(buffer), stdin); /* read command line */\r
1889 if (cptr == NULL) return SCPE_ARG; /* ignore EOF */\r
1890 if (*cptr == 0) return SCPE_ARG; /* ignore blank */\r
1891 } /* resume attaching */\r
1892\r
1893 tptr = (char *) malloc(strlen(cptr) + 1);\r
1894 if (tptr == NULL) return SCPE_MEM;\r
1895 strcpy(tptr, cptr);\r
1896\r
1897 xq->var->etherface = (ETH_DEV *) malloc(sizeof(ETH_DEV));\r
1898 if (!xq->var->etherface) return SCPE_MEM;\r
1899\r
1900 status = eth_open(xq->var->etherface, cptr, xq->dev, DBG_ETH);\r
1901 if (status != SCPE_OK) {\r
1902 free(tptr);\r
1903 free(xq->var->etherface);\r
1904 xq->var->etherface = 0;\r
1905 return status;\r
1906 }\r
1907 uptr->filename = tptr;\r
1908 uptr->flags |= UNIT_ATT;\r
1909\r
1910 /* turn on transceiver power indicator */\r
1911 xq_csr_set_clr(xq, XQ_CSR_OK, 0);\r
1912\r
1913 /* reset the device with the new attach info */\r
1914 xq_reset(xq->dev);\r
1915\r
1916 return SCPE_OK;\r
1917}\r
1918\r
1919/* detach device: */\r
1920\r
1921t_stat xq_detach(UNIT* uptr)\r
1922{\r
1923 CTLR* xq = xq_unit2ctlr(uptr);\r
1924 sim_debug(DBG_TRC, xq->dev, "xq_detach()\n");\r
1925\r
1926 if (uptr->flags & UNIT_ATT) {\r
1927 eth_close (xq->var->etherface);\r
1928 free(xq->var->etherface);\r
1929 xq->var->etherface = 0;\r
1930 free(uptr->filename);\r
1931 uptr->filename = NULL;\r
1932 uptr->flags &= ~UNIT_ATT;\r
1933 /* cancel service timer */\r
1934 sim_cancel(&xq->unit[0]);\r
1935 }\r
1936\r
1937 /* turn off transceiver power indicator */\r
1938 xq_csr_set_clr(xq, 0, XQ_CSR_OK);\r
1939\r
1940 return SCPE_OK;\r
1941}\r
1942\r
1943void xq_setint(CTLR* xq)\r
1944{\r
1945 xq->var->irq = 1;\r
1946 SET_INT(XQ);\r
1947 return;\r
1948}\r
1949\r
1950void xq_clrint(CTLR* xq)\r
1951{\r
1952 int i;\r
1953 xq->var->irq = 0; /* set controller irq off */\r
1954 /* clear master interrupt? */\r
1955 for (i=0; i<XQ_MAX_CONTROLLERS; i++) /* check all controllers.. */\r
1956 if (xq_ctrl[i].var->irq) { /* if any irqs enabled */\r
1957 SET_INT(XQ); /* set master interrupt on */\r
1958 return;\r
1959 }\r
1960 CLR_INT(XQ); /* clear master interrupt */\r
1961 return;\r
1962}\r
1963\r
1964int32 xq_int (void)\r
1965{\r
1966 int i;\r
1967 for (i=0; i<XQ_MAX_CONTROLLERS; i++) {\r
1968 CTLR* xq = &xq_ctrl[i];\r
1969 if (xq->var->irq) { /* if interrupt pending */\r
1970 xq_clrint(xq); /* clear interrupt */\r
1971 return xq->dib->vec; /* return vector */\r
1972 }\r
1973 }\r
1974 return 0; /* no interrupt request active */\r
1975}\r
1976\r
1977void xq_csr_set_clr (CTLR* xq, uint16 set_bits, uint16 clear_bits)\r
1978{\r
1979 uint16 saved_csr = xq->var->csr;\r
1980\r
1981 /* set the bits in the csr */\r
1982 xq->var->csr = (xq->var->csr | set_bits) & ~clear_bits;\r
1983\r
1984 sim_debug_u16(DBG_CSR, xq->dev, xq_csr_bits, saved_csr, xq->var->csr, 1);\r
1985\r
1986 /* check and correct the state of controller interrupt */\r
1987\r
1988 /* if IE is transitioning, process it */\r
1989 if ((saved_csr ^ xq->var->csr) & XQ_CSR_IE) {\r
1990\r
1991 /* if IE transitioning low and interrupt set, clear interrupt */\r
1992 if ((clear_bits & XQ_CSR_IE) && xq->var->irq)\r
1993 xq_clrint(xq);\r
1994\r
1995 /* if IE transitioning high, and XI or RI is high,\r
1996 set interrupt if interrupt is off */\r
1997 if ((set_bits & XQ_CSR_IE) && (xq->var->csr & XQ_CSR_XIRI) && !xq->var->irq)\r
1998 xq_setint(xq);\r
1999\r
2000 } else { /* IE is not transitioning */\r
2001\r
2002 /* if interrupts are enabled */\r
2003 if (xq->var->csr & XQ_CSR_IE) {\r
2004\r
2005 /* if XI or RI transitioning high and interrupt off, set interrupt */\r
2006 if (((saved_csr ^ xq->var->csr) & (set_bits & XQ_CSR_XIRI)) && !xq->var->irq) {\r
2007 xq_setint(xq);\r
2008\r
2009 } else {\r
2010\r
2011 /* if XI or RI transitioning low, and both XI and RI are now low,\r
2012 clear interrupt if interrupt is on */\r
2013 if (((saved_csr ^ xq->var->csr) & (clear_bits & XQ_CSR_XIRI))\r
2014 && !(xq->var->csr & XQ_CSR_XIRI)\r
2015 && xq->var->irq)\r
2016 xq_clrint(xq);\r
2017 }\r
2018\r
2019 } /* IE enabled */\r
2020\r
2021 } /* IE transitioning */\r
2022}\r
2023\r
2024/*==============================================================================\r
2025/ debugging routines\r
2026/=============================================================================*/\r
2027\r
2028\r
2029void xq_debug_setup(CTLR* xq)\r
2030{\r
2031 int i;\r
2032 char buffer[20];\r
2033 if (xq->var->write_buffer.msg[0])\r
2034 printf ("%s: setup> MOP info present!\n", xq->dev->name);\r
2035\r
2036 for (i = 0; i < XQ_FILTER_MAX; i++) {\r
2037 eth_mac_fmt(&xq->var->setup.macs[i], buffer);\r
2038 printf ("%s: setup> set addr[%d]: %s\n", xq->dev->name, i, buffer);\r
2039 }\r
2040\r
2041 if (xq->var->write_buffer.len > 128) {\r
2042 char buffer[20] = {0};\r
2043 uint16 len = xq->var->write_buffer.len;\r
2044 if (len & XQ_SETUP_MC) strcat(buffer, "MC ");\r
2045 if (len & XQ_SETUP_PM) strcat(buffer, "PM ");\r
2046 if (len & XQ_SETUP_LD) strcat(buffer, "LD ");\r
2047 if (len & XQ_SETUP_ST) strcat(buffer, "ST ");\r
2048 printf ("%s: setup> Length [%d =0x%X, LD:%d, ST:%d] info: %s\n",\r
2049 xq->dev->name, len, len, (len & XQ_SETUP_LD) >> 2, (len & XQ_SETUP_ST) >> 4, buffer);\r
2050 }\r
2051}\r