First Commit of my working state
[simh.git] / VAX / vax_io.c
CommitLineData
196ba1fc
PH
1/* vax_io.c: VAX 3900 Qbus IO simulator\r
2\r
3 Copyright (c) 1998-2008, Robert M Supnik\r
4\r
5 Permission is hereby granted, free of charge, to any person obtaining a\r
6 copy of this software and associated documentation files (the "Software"),\r
7 to deal in the Software without restriction, including without limitation\r
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
9 and/or sell copies of the Software, and to permit persons to whom the\r
10 Software is furnished to do so, subject to the following conditions:\r
11\r
12 The above copyright notice and this permission notice shall be included in\r
13 all copies or substantial portions of the Software.\r
14\r
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21\r
22 Except as contained in this notice, the name of Robert M Supnik shall not be\r
23 used in advertising or otherwise to promote the sale, use or other dealings\r
24 in this Software without prior written authorization from Robert M Supnik.\r
25\r
26 qba Qbus adapter\r
27\r
28 28-May-08 RMS Inlined physical memory routines\r
29 25-Jan-08 RMS Fixed declarations (from Mark Pizzolato)\r
30 03-Dec-05 RMS Added SHOW QBA VIRT and ex/dep via map\r
31 05-Oct-05 RMS Fixed bug in autoconfiguration (missing XU)\r
32 25-Jul-05 RMS Revised autoconfiguration algorithm and interface\r
33 30-Sep-04 RMS Revised Qbus interface\r
34 Moved mem_err, crd_err interrupts here from vax_cpu.c\r
35 09-Sep-04 RMS Integrated powerup into RESET (with -p)\r
36 05-Sep-04 RMS Added CRD interrupt handling\r
37 28-May-04 RMS Revised I/O dispatching (from John Dundas)\r
38 21-Mar-04 RMS Added RXV21 support\r
39 21-Dec-03 RMS Fixed bug in autoconfigure vector assignment; added controls\r
40 21-Nov-03 RMS Added check for interrupt slot conflict (found by Dave Hittner)\r
41 29-Oct-03 RMS Fixed WriteX declaration (found by Mark Pizzolato)\r
42 19-Apr-03 RMS Added optimized byte and word DMA routines\r
43 12-Mar-03 RMS Added logical name support\r
44 22-Dec-02 RMS Added console halt support\r
45 12-Oct-02 RMS Added autoconfigure support\r
46 Added SHOW IO space routine\r
47 29-Sep-02 RMS Added dynamic table support\r
48 07-Sep-02 RMS Added TMSCP and variable vector support\r
49*/\r
50\r
51#include "vax_defs.h"\r
52\r
53/* CQBIC system configuration register */\r
54\r
55#define CQSCR_POK 0x00008000 /* power ok RO1 */\r
56#define CQSCR_BHL 0x00004000 /* BHALT enb */\r
57#define CQSCR_AUX 0x00000400 /* aux mode RONI */\r
58#define CQSCR_DBO 0x0000000C /* offset NI */\r
59#define CQSCR_RW (CQSCR_BHL | CQSCR_DBO)\r
60#define CQSCR_MASK (CQSCR_RW | CQSCR_POK | CQSCR_AUX)\r
61\r
62/* CQBIC DMA system error register - W1C */\r
63\r
64#define CQDSER_BHL 0x00008000 /* BHALT NI */\r
65#define CQDSER_DCN 0x00004000 /* DC ~OK NI */\r
66#define CQDSER_MNX 0x00000080 /* master NXM */\r
67#define CQDSER_MPE 0x00000020 /* master par NI */\r
68#define CQDSER_SME 0x00000010 /* slv mem err NI */\r
69#define CQDSER_LST 0x00000008 /* lost err */\r
70#define CQDSER_TMO 0x00000004 /* no grant NI */\r
71#define CQDSER_SNX 0x00000001 /* slave NXM */\r
72#define CQDSER_ERR (CQDSER_MNX | CQDSER_MPE | CQDSER_TMO | CQDSER_SNX)\r
73#define CQDSER_MASK 0x0000C0BD\r
74\r
75/* CQBIC master error address register */\r
76\r
77#define CQMEAR_MASK 0x00001FFF /* Qbus page */\r
78\r
79/* CQBIC slave error address register */\r
80\r
81#define CQSEAR_MASK 0x000FFFFF /* mem page */\r
82\r
83/* CQBIC map base register */\r
84\r
85#define CQMBR_MASK 0x1FFF8000 /* 32KB aligned */\r
86\r
87/* CQBIC IPC register */\r
88\r
89#define CQIPC_QME 0x00008000 /* Qbus read NXM W1C */\r
90#define CQIPC_INV 0x00004000 /* CAM inval NIWO */\r
91#define CQIPC_AHLT 0x00000100 /* aux halt NI */\r
92#define CQIPC_DBIE 0x00000040 /* dbell int enb NI */\r
93#define CQIPC_LME 0x00000020 /* local mem enb */\r
94#define CQIPC_DB 0x00000001 /* doorbell req NI */\r
95#define CQIPC_W1C CQIPC_QME\r
96#define CQIPC_RW (CQIPC_AHLT | CQIPC_DBIE | CQIPC_LME | CQIPC_DB)\r
97#define CQIPC_MASK (CQIPC_RW | CQIPC_QME )\r
98\r
99/* CQBIC map entry */\r
100\r
101#define CQMAP_VLD 0x80000000 /* valid */\r
102#define CQMAP_PAG 0x000FFFFF /* mem page */\r
103\r
104int32 int_req[IPL_HLVL] = { 0 }; /* intr, IPL 14-17 */\r
105int32 cq_scr = 0; /* SCR */\r
106int32 cq_dser = 0; /* DSER */\r
107int32 cq_mear = 0; /* MEAR */\r
108int32 cq_sear = 0; /* SEAR */\r
109int32 cq_mbr = 0; /* MBR */\r
110int32 cq_ipc = 0; /* IPC */\r
111int32 autcon_enb = 1; /* autoconfig enable */\r
112\r
113extern uint32 *M;\r
114extern UNIT cpu_unit;\r
115extern int32 PSL, SISR, trpirq, mem_err, crd_err, hlt_pin;\r
116extern int32 p1;\r
117extern int32 ssc_bto;\r
118extern jmp_buf save_env;\r
119extern int32 sim_switches;\r
120extern DEVICE *sim_devices[];\r
121extern FILE *sim_log;\r
122\r
123t_stat dbl_rd (int32 *data, int32 addr, int32 access);\r
124t_stat dbl_wr (int32 data, int32 addr, int32 access);\r
125int32 eval_int (void);\r
126void cq_merr (int32 pa);\r
127void cq_serr (int32 pa);\r
128t_stat qba_reset (DEVICE *dptr);\r
129t_stat qba_ex (t_value *vptr, t_addr exta, UNIT *uptr, int32 sw);\r
130t_stat qba_dep (t_value val, t_addr exta, UNIT *uptr, int32 sw);\r
131t_bool qba_map_addr (uint32 qa, uint32 *ma);\r
132t_bool qba_map_addr_c (uint32 qa, uint32 *ma);\r
133t_stat set_autocon (UNIT *uptr, int32 val, char *cptr, void *desc);\r
134t_stat show_autocon (FILE *st, UNIT *uptr, int32 val, void *desc);\r
135t_stat show_iospace (FILE *st, UNIT *uptr, int32 val, void *desc);\r
136t_stat qba_show_virt (FILE *of, UNIT *uptr, int32 val, void *desc);\r
137\r
138/* Qbus adapter data structures\r
139\r
140 qba_dev QBA device descriptor\r
141 qba_unit QBA units\r
142 qba_reg QBA register list\r
143*/\r
144\r
145DIB qba_dib = { IOBA_DBL, IOLN_DBL, &dbl_rd, &dbl_wr, 0 };\r
146\r
147UNIT qba_unit = { UDATA (NULL, 0, 0) };\r
148\r
149REG qba_reg[] = {\r
150 { HRDATA (SCR, cq_scr, 16) },\r
151 { HRDATA (DSER, cq_dser, 8) },\r
152 { HRDATA (MEAR, cq_mear, 13) },\r
153 { HRDATA (SEAR, cq_sear, 20) },\r
154 { HRDATA (MBR, cq_mbr, 29) },\r
155 { HRDATA (IPC, cq_ipc, 16) },\r
156 { HRDATA (IPL17, int_req[3], 32), REG_RO },\r
157 { HRDATA (IPL16, int_req[2], 32), REG_RO },\r
158 { HRDATA (IPL15, int_req[1], 32), REG_RO },\r
159 { HRDATA (IPL14, int_req[0], 32), REG_RO },\r
160 { FLDATA (AUTOCON, autcon_enb, 0), REG_HRO },\r
161 { NULL }\r
162 };\r
163\r
164MTAB qba_mod[] = {\r
165 { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "IOSPACE", NULL,\r
166 NULL, &show_iospace },\r
167 { MTAB_XTD|MTAB_VDV, 1, "AUTOCONFIG", "AUTOCONFIG",\r
168 &set_autocon, &show_autocon },\r
169 { MTAB_XTD|MTAB_VDV, 0, NULL, "NOAUTOCONFIG",\r
170 &set_autocon, NULL },\r
171 { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "VIRTUAL", NULL,\r
172 NULL, &qba_show_virt },\r
173 { 0 }\r
174 };\r
175\r
176DEVICE qba_dev = {\r
177 "QBA", &qba_unit, qba_reg, qba_mod,\r
178 1, 16, CQMAWIDTH, 2, 16, 16,\r
179 &qba_ex, &qba_dep, &qba_reset,\r
180 NULL, NULL, NULL,\r
181 &qba_dib, DEV_QBUS\r
182 };\r
183\r
184/* IO page dispatches */\r
185\r
186static t_stat (*iodispR[IOPAGESIZE >> 1])(int32 *dat, int32 ad, int32 md);\r
187static t_stat (*iodispW[IOPAGESIZE >> 1])(int32 dat, int32 ad, int32 md);\r
188static DIB *iodibp[IOPAGESIZE >> 1];\r
189\r
190/* Interrupt request to interrupt action map */\r
191\r
192int32 (*int_ack[IPL_HLVL][32])(); /* int ack routines */\r
193\r
194/* Interrupt request to vector map */\r
195\r
196int32 int_vec[IPL_HLVL][32]; /* int req to vector */\r
197\r
198/* The KA65x handles errors in I/O space as follows\r
199\r
200 - read: set DSER<7>, latch addr in MEAR, machine check\r
201 - write: set DSER<7>, latch addr in MEAR, MEMERR interrupt\r
202*/\r
203\r
204int32 ReadQb (uint32 pa)\r
205{\r
206int32 idx, val;\r
207\r
208idx = (pa & IOPAGEMASK) >> 1;\r
209if (iodispR[idx]) {\r
210 iodispR[idx] (&val, pa, READ);\r
211 return val;\r
212 }\r
213cq_merr (pa);\r
214MACH_CHECK (MCHK_READ);\r
215return 0;\r
216}\r
217\r
218void WriteQb (uint32 pa, int32 val, int32 mode)\r
219{\r
220int32 idx;\r
221\r
222idx = (pa & IOPAGEMASK) >> 1;\r
223if (iodispW[idx]) {\r
224 iodispW[idx] (val, pa, mode);\r
225 return;\r
226 }\r
227cq_merr (pa);\r
228mem_err = 1;\r
229return;\r
230}\r
231\r
232/* ReadIO - read I/O space\r
233\r
234 Inputs:\r
235 pa = physical address\r
236 lnt = length (BWLQ)\r
237 Output:\r
238 longword of data\r
239*/\r
240\r
241int32 ReadIO (uint32 pa, int32 lnt)\r
242{\r
243int32 iod;\r
244\r
245iod = ReadQb (pa); /* wd from Qbus */\r
246if (lnt < L_LONG) iod = iod << ((pa & 2)? 16: 0); /* bw? position */\r
247else iod = (ReadQb (pa + 2) << 16) | iod; /* lw, get 2nd wd */\r
248SET_IRQL;\r
249return iod;\r
250}\r
251\r
252/* WriteIO - write I/O space\r
253\r
254 Inputs:\r
255 pa = physical address\r
256 val = data to write, right justified in 32b longword\r
257 lnt = length (BWLQ)\r
258 Outputs:\r
259 none\r
260*/\r
261\r
262void WriteIO (uint32 pa, int32 val, int32 lnt)\r
263{\r
264if (lnt == L_BYTE) WriteQb (pa, val, WRITEB);\r
265else if (lnt == L_WORD) WriteQb (pa, val, WRITE);\r
266else {\r
267 WriteQb (pa, val & 0xFFFF, WRITE);\r
268 WriteQb (pa + 2, (val >> 16) & 0xFFFF, WRITE);\r
269 }\r
270SET_IRQL;\r
271return;\r
272}\r
273\r
274/* Find highest priority outstanding interrupt */\r
275\r
276int32 eval_int (void)\r
277{\r
278int32 ipl = PSL_GETIPL (PSL);\r
279int32 i, t;\r
280\r
281static const int32 sw_int_mask[IPL_SMAX] = {\r
282 0xFFFE, 0xFFFC, 0xFFF8, 0xFFF0, /* 0 - 3 */\r
283 0xFFE0, 0xFFC0, 0xFF80, 0xFF00, /* 4 - 7 */\r
284 0xFE00, 0xFC00, 0xF800, 0xF000, /* 8 - B */\r
285 0xE000, 0xC000, 0x8000 /* C - E */\r
286 };\r
287\r
288if (hlt_pin) return IPL_HLTPIN; /* hlt pin int */\r
289if ((ipl < IPL_MEMERR) && mem_err) return IPL_MEMERR; /* mem err int */\r
290if ((ipl < IPL_CRDERR) && crd_err) return IPL_CRDERR; /* crd err int */\r
291for (i = IPL_HMAX; i >= IPL_HMIN; i--) { /* chk hwre int */\r
292 if (i <= ipl) return 0; /* at ipl? no int */\r
293 if (int_req[i - IPL_HMIN]) return i; /* req != 0? int */\r
294 }\r
295if (ipl >= IPL_SMAX) return 0; /* ipl >= sw max? */\r
296if ((t = SISR & sw_int_mask[ipl]) == 0) return 0; /* eligible req */\r
297for (i = IPL_SMAX; i > ipl; i--) { /* check swre int */\r
298 if ((t >> i) & 1) return i; /* req != 0? int */\r
299 }\r
300return 0;\r
301}\r
302\r
303/* Return vector for highest priority hardware interrupt at IPL lvl */\r
304\r
305int32 get_vector (int32 lvl)\r
306{\r
307int32 i;\r
308int32 l = lvl - IPL_HMIN;\r
309\r
310if (lvl == IPL_MEMERR) { /* mem error? */\r
311 mem_err = 0;\r
312 return SCB_MEMERR;\r
313 }\r
314if (lvl == IPL_CRDERR) { /* CRD error? */\r
315 crd_err = 0;\r
316 return SCB_CRDERR;\r
317 }\r
318if (lvl > IPL_HMAX) { /* error req lvl? */\r
319 ABORT (STOP_UIPL); /* unknown intr */\r
320 }\r
321for (i = 0; int_req[l] && (i < 32); i++) {\r
322 if ((int_req[l] >> i) & 1) {\r
323 int_req[l] = int_req[l] & ~(1u << i);\r
324 if (int_ack[l][i]) return int_ack[l][i]();\r
325 return int_vec[l][i];\r
326 }\r
327 }\r
328return 0;\r
329}\r
330\r
331/* CQBIC registers\r
332\r
333 SCR system configuration register\r
334 DSER DMA system error register (W1C)\r
335 MEAR master error address register (RO)\r
336 SEAR slave error address register (RO)\r
337 MBR map base register\r
338 IPC inter-processor communication register\r
339*/\r
340\r
341int32 cqbic_rd (int32 pa)\r
342{\r
343int32 rg = (pa - CQBICBASE) >> 2;\r
344\r
345switch (rg) {\r
346\r
347 case 0: /* SCR */\r
348 return (cq_scr | CQSCR_POK) & CQSCR_MASK;\r
349\r
350 case 1: /* DSER */\r
351 return cq_dser & CQDSER_MASK;\r
352\r
353 case 2: /* MEAR */\r
354 return cq_mear & CQMEAR_MASK;\r
355\r
356 case 3: /* SEAR */\r
357 return cq_sear & CQSEAR_MASK;\r
358\r
359 case 4: /* MBR */\r
360 return cq_mbr & CQMBR_MASK;\r
361 }\r
362\r
363return 0;\r
364}\r
365\r
366void cqbic_wr (int32 pa, int32 val, int32 lnt)\r
367{\r
368int32 nval, rg = (pa - CQBICBASE) >> 2;\r
369\r
370if (lnt < L_LONG) {\r
371 int32 sc = (pa & 3) << 3;\r
372 int32 mask = (lnt == L_WORD)? 0xFFFF: 0xFF;\r
373 int32 t = cqbic_rd (pa);\r
374 nval = ((val & mask) << sc) | (t & ~(mask << sc));\r
375 val = val << sc;\r
376 }\r
377else nval = val;\r
378switch (rg) {\r
379\r
380 case 0: /* SCR */\r
381 cq_scr = ((cq_scr & ~CQSCR_RW) | (nval & CQSCR_RW)) & CQSCR_MASK;\r
382 break;\r
383\r
384 case 1: /* DSER */\r
385 cq_dser = (cq_dser & ~val) & CQDSER_MASK;\r
386 if (val & CQDSER_SME) cq_ipc = cq_ipc & ~CQIPC_QME;\r
387 break;\r
388\r
389 case 2: case 3:\r
390 cq_merr (pa); /* MEAR, SEAR */\r
391 MACH_CHECK (MCHK_WRITE);\r
392 break;\r
393\r
394 case 4: /* MBR */\r
395 cq_mbr = nval & CQMBR_MASK;\r
396 break;\r
397 }\r
398return;\r
399}\r
400\r
401/* IPC can be read as local register or as Qbus I/O\r
402 Because of the W1C */\r
403\r
404int32 cqipc_rd (int32 pa)\r
405{\r
406return cq_ipc & CQIPC_MASK; /* IPC */\r
407}\r
408\r
409void cqipc_wr (int32 pa, int32 val, int32 lnt)\r
410{\r
411int32 nval = val;\r
412\r
413if (lnt < L_LONG) {\r
414 int32 sc = (pa & 3) << 3;\r
415 nval = val << sc;\r
416 }\r
417\r
418cq_ipc = cq_ipc & ~(nval & CQIPC_W1C); /* W1C */\r
419if ((pa & 3) == 0) /* low byte only */\r
420 cq_ipc = ((cq_ipc & ~CQIPC_RW) | (val & CQIPC_RW)) & CQIPC_MASK;\r
421return;\r
422}\r
423\r
424/* I/O page routines */\r
425\r
426t_stat dbl_rd (int32 *data, int32 addr, int32 access)\r
427{\r
428*data = cq_ipc & CQIPC_MASK;\r
429return SCPE_OK;\r
430}\r
431\r
432t_stat dbl_wr (int32 data, int32 addr, int32 access)\r
433{\r
434cqipc_wr (addr, data, (access == WRITEB)? L_BYTE: L_WORD);\r
435return SCPE_OK;\r
436}\r
437\r
438/* CQBIC map read and write (reflects to main memory)\r
439\r
440 Read error: set DSER<0>, latch slave address, machine check\r
441 Write error: set DSER<0>, latch slave address, memory error interrupt\r
442*/\r
443\r
444int32 cqmap_rd (int32 pa)\r
445{\r
446int32 ma = (pa & CQMAPAMASK) + cq_mbr; /* mem addr */\r
447\r
448if (ADDR_IS_MEM (ma)) return M[ma >> 2];\r
449cq_serr (ma); /* set err */\r
450MACH_CHECK (MCHK_READ); /* mcheck */\r
451return 0;\r
452}\r
453\r
454void cqmap_wr (int32 pa, int32 val, int32 lnt)\r
455{\r
456int32 ma = (pa & CQMAPAMASK) + cq_mbr; /* mem addr */\r
457\r
458if (ADDR_IS_MEM (ma)) {\r
459 if (lnt < L_LONG) {\r
460 int32 sc = (pa & 3) << 3;\r
461 int32 mask = (lnt == L_WORD)? 0xFFFF: 0xFF;\r
462 int32 t = M[ma >> 2];\r
463 val = ((val & mask) << sc) | (t & ~(mask << sc));\r
464 }\r
465 M[ma >> 2] = val;\r
466 }\r
467else {\r
468 cq_serr (ma); /* error */\r
469 mem_err = 1;\r
470 }\r
471return;\r
472}\r
473\r
474/* CQBIC Qbus memory read and write (reflects to main memory)\r
475\r
476 May give master or slave error, depending on where the failure occurs\r
477*/\r
478\r
479int32 cqmem_rd (int32 pa)\r
480{\r
481int32 qa = pa & CQMAMASK; /* Qbus addr */\r
482uint32 ma;\r
483\r
484if (qba_map_addr (qa, &ma)) return M[ma >> 2]; /* map addr */\r
485MACH_CHECK (MCHK_READ); /* err? mcheck */\r
486return 0;\r
487}\r
488\r
489void cqmem_wr (int32 pa, int32 val, int32 lnt)\r
490{\r
491int32 qa = pa & CQMAMASK; /* Qbus addr */\r
492uint32 ma;\r
493\r
494if (qba_map_addr (qa, &ma)) { /* map addr */\r
495 if (lnt < L_LONG) {\r
496 int32 sc = (pa & 3) << 3;\r
497 int32 mask = (lnt == L_WORD)? 0xFFFF: 0xFF;\r
498 int32 t = M[ma >> 2];\r
499 val = ((val & mask) << sc) | (t & ~(mask << sc));\r
500 }\r
501 M[ma >> 2] = val;\r
502 }\r
503else mem_err = 1;\r
504return;\r
505}\r
506\r
507/* Map an address via the translation map */\r
508\r
509t_bool qba_map_addr (uint32 qa, uint32 *ma)\r
510{\r
511int32 qblk = (qa >> VA_V_VPN); /* Qbus blk */\r
512int32 qmma = ((qblk << 2) & CQMAPAMASK) + cq_mbr; /* map entry */\r
513\r
514if (ADDR_IS_MEM (qmma)) { /* legit? */\r
515 int32 qmap = M[qmma >> 2]; /* get map */\r
516 if (qmap & CQMAP_VLD) { /* valid? */\r
517 *ma = ((qmap & CQMAP_PAG) << VA_V_VPN) + VA_GETOFF (qa);\r
518 if (ADDR_IS_MEM (*ma)) return TRUE; /* legit addr */\r
519 cq_serr (*ma); /* slave nxm */\r
520 return FALSE;\r
521 }\r
522 cq_merr (qa); /* master nxm */\r
523 return FALSE;\r
524 }\r
525cq_serr (0); /* inv mem */\r
526return FALSE;\r
527}\r
528\r
529/* Map an address via the translation map - console version (no status changes) */\r
530\r
531t_bool qba_map_addr_c (uint32 qa, uint32 *ma)\r
532{\r
533int32 qblk = (qa >> VA_V_VPN); /* Qbus blk */\r
534int32 qmma = ((qblk << 2) & CQMAPAMASK) + cq_mbr; /* map entry */\r
535\r
536if (ADDR_IS_MEM (qmma)) { /* legit? */\r
537 int32 qmap = M[qmma >> 2]; /* get map */\r
538 if (qmap & CQMAP_VLD) { /* valid? */\r
539 *ma = ((qmap & CQMAP_PAG) << VA_V_VPN) + VA_GETOFF (qa);\r
540 return TRUE; /* legit addr */\r
541 }\r
542 }\r
543return FALSE;\r
544}\r
545\r
546/* Set master error */\r
547\r
548void cq_merr (int32 pa)\r
549{\r
550if (cq_dser & CQDSER_ERR) cq_dser = cq_dser | CQDSER_LST;\r
551cq_dser = cq_dser | CQDSER_MNX; /* master nxm */\r
552cq_mear = (pa >> VA_V_VPN) & CQMEAR_MASK; /* page addr */\r
553return;\r
554}\r
555\r
556/* Set slave error */\r
557\r
558void cq_serr (int32 pa)\r
559{\r
560if (cq_dser & CQDSER_ERR) cq_dser = cq_dser | CQDSER_LST;\r
561cq_dser = cq_dser | CQDSER_SNX; /* slave nxm */\r
562cq_sear = (pa >> VA_V_VPN) & CQSEAR_MASK;\r
563return;\r
564}\r
565\r
566/* Reset I/O bus */\r
567\r
568void ioreset_wr (int32 data)\r
569{\r
570reset_all (5); /* from qba on... */\r
571return;\r
572}\r
573\r
574/* Powerup CQBIC */\r
575\r
576t_stat qba_powerup (void)\r
577{\r
578cq_mbr = 0;\r
579cq_scr = CQSCR_POK;\r
580return SCPE_OK;\r
581}\r
582\r
583/* Reset CQBIC */\r
584\r
585t_stat qba_reset (DEVICE *dptr)\r
586{\r
587int32 i;\r
588\r
589if (sim_switches & SWMASK ('P')) qba_powerup ();\r
590cq_scr = (cq_scr & CQSCR_BHL) | CQSCR_POK;\r
591cq_dser = cq_mear = cq_sear = cq_ipc = 0;\r
592for (i = 0; i < IPL_HLVL; i++) int_req[i] = 0;\r
593return SCPE_OK;\r
594}\r
595\r
596/* Qbus I/O buffer routines, aligned access\r
597\r
598 Map_ReadB - fetch byte buffer from memory\r
599 Map_ReadW - fetch word buffer from memory\r
600 Map_WriteB - store byte buffer into memory\r
601 Map_WriteW - store word buffer into memory\r
602*/\r
603\r
604int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf)\r
605{\r
606int32 i;\r
607uint32 ma, dat;\r
608\r
609if ((ba | bc) & 03) { /* check alignment */\r
610 for (i = ma = 0; i < bc; i++, buf++) { /* by bytes */\r
611 if ((ma & VA_M_OFF) == 0) { /* need map? */\r
612 if (!qba_map_addr (ba + i, &ma)) /* inv or NXM? */\r
613 return (bc - i);\r
614 }\r
615 *buf = ReadB (ma);\r
616 ma = ma + 1;\r
617 }\r
618 }\r
619else {\r
620 for (i = ma = 0; i < bc; i = i + 4, buf++) { /* by longwords */\r
621 if ((ma & VA_M_OFF) == 0) { /* need map? */\r
622 if (!qba_map_addr (ba + i, &ma)) /* inv or NXM? */\r
623 return (bc - i);\r
624 }\r
625 dat = ReadL (ma); /* get lw */\r
626 *buf++ = dat & BMASK; /* low 8b */\r
627 *buf++ = (dat >> 8) & BMASK; /* next 8b */\r
628 *buf++ = (dat >> 16) & BMASK; /* next 8b */\r
629 *buf = (dat >> 24) & BMASK;\r
630 ma = ma + 4;\r
631 }\r
632 }\r
633return 0;\r
634}\r
635\r
636int32 Map_ReadW (uint32 ba, int32 bc, uint16 *buf)\r
637{\r
638int32 i;\r
639uint32 ma,dat;\r
640\r
641ba = ba & ~01;\r
642bc = bc & ~01;\r
643if ((ba | bc) & 03) { /* check alignment */\r
644 for (i = ma = 0; i < bc; i = i + 2, buf++) { /* by words */\r
645 if ((ma & VA_M_OFF) == 0) { /* need map? */\r
646 if (!qba_map_addr (ba + i, &ma)) /* inv or NXM? */\r
647 return (bc - i);\r
648 }\r
649 *buf = ReadW (ma);\r
650 ma = ma + 2;\r
651 }\r
652 }\r
653else {\r
654 for (i = ma = 0; i < bc; i = i + 4, buf++) { /* by longwords */\r
655 if ((ma & VA_M_OFF) == 0) { /* need map? */\r
656 if (!qba_map_addr (ba + i, &ma)) /* inv or NXM? */\r
657 return (bc - i);\r
658 }\r
659 dat = ReadL (ma); /* get lw */\r
660 *buf++ = dat & WMASK; /* low 16b */\r
661 *buf = (dat >> 16) & WMASK; /* high 16b */\r
662 ma = ma + 4;\r
663 }\r
664 }\r
665return 0;\r
666}\r
667\r
668int32 Map_WriteB (uint32 ba, int32 bc, uint8 *buf)\r
669{\r
670int32 i;\r
671uint32 ma, dat;\r
672\r
673if ((ba | bc) & 03) { /* check alignment */\r
674 for (i = ma = 0; i < bc; i++, buf++) { /* by bytes */\r
675 if ((ma & VA_M_OFF) == 0) { /* need map? */\r
676 if (!qba_map_addr (ba + i, &ma)) /* inv or NXM? */\r
677 return (bc - i);\r
678 }\r
679 WriteB (ma, *buf);\r
680 ma = ma + 1;\r
681 }\r
682 }\r
683else {\r
684 for (i = ma = 0; i < bc; i = i + 4, buf++) { /* by longwords */\r
685 if ((ma & VA_M_OFF) == 0) { /* need map? */\r
686 if (!qba_map_addr (ba + i, &ma)) /* inv or NXM? */\r
687 return (bc - i);\r
688 }\r
689 dat = (uint32) *buf++; /* get low 8b */\r
690 dat = dat | (((uint32) *buf++) << 8); /* merge next 8b */\r
691 dat = dat | (((uint32) *buf++) << 16); /* merge next 8b */\r
692 dat = dat | (((uint32) *buf) << 24); /* merge hi 8b */\r
693 WriteL (ma, dat); /* store lw */\r
694 ma = ma + 4;\r
695 }\r
696 }\r
697return 0;\r
698}\r
699\r
700int32 Map_WriteW (uint32 ba, int32 bc, uint16 *buf)\r
701{\r
702int32 i;\r
703uint32 ma, dat;\r
704\r
705ba = ba & ~01;\r
706bc = bc & ~01;\r
707if ((ba | bc) & 03) { /* check alignment */\r
708 for (i = ma = 0; i < bc; i = i + 2, buf++) { /* by words */\r
709 if ((ma & VA_M_OFF) == 0) { /* need map? */\r
710 if (!qba_map_addr (ba + i, &ma)) /* inv or NXM? */\r
711 return (bc - i);\r
712 }\r
713 WriteW (ma, *buf);\r
714 ma = ma + 2;\r
715 }\r
716 }\r
717else {\r
718 for (i = ma = 0; i < bc; i = i + 4, buf++) { /* by longwords */\r
719 if ((ma & VA_M_OFF) == 0) { /* need map? */\r
720 if (!qba_map_addr (ba + i, &ma)) /* inv or NXM? */\r
721 return (bc - i);\r
722 }\r
723 dat = (uint32) *buf++; /* get low 16b */\r
724 dat = dat | (((uint32) *buf) << 16); /* merge hi 16b */\r
725 WriteL (ma, dat); /* store lw */\r
726 ma = ma + 4;\r
727 }\r
728 }\r
729return 0;\r
730}\r
731\r
732/* Memory examine via map (word only) */\r
733\r
734t_stat qba_ex (t_value *vptr, t_addr exta, UNIT *uptr, int32 sw)\r
735{\r
736uint32 qa = (uint32) exta, pa;\r
737\r
738if ((vptr == NULL) || (qa >= CQMSIZE)) return SCPE_ARG;\r
739if (qba_map_addr_c (qa, &pa) && ADDR_IS_MEM (pa)) {\r
740 *vptr = (uint32) ReadW (pa);\r
741 return SCPE_OK;\r
742 }\r
743return SCPE_NXM;\r
744}\r
745\r
746/* Memory deposit via map (word only) */\r
747\r
748t_stat qba_dep (t_value val, t_addr exta, UNIT *uptr, int32 sw)\r
749{\r
750uint32 qa = (uint32) exta, pa;\r
751\r
752if (qa >= CQMSIZE) return SCPE_ARG;\r
753if (qba_map_addr_c (qa, &pa) && ADDR_IS_MEM (pa)) {\r
754 WriteW (pa, (int32) val);\r
755 return SCPE_OK;\r
756 }\r
757return SCPE_NXM;\r
758}\r
759\r
760/* Enable/disable autoconfiguration */\r
761\r
762t_stat set_autocon (UNIT *uptr, int32 val, char *cptr, void *desc)\r
763{\r
764if (cptr != NULL) return SCPE_ARG;\r
765autcon_enb = val;\r
766return auto_config (NULL, 0);\r
767}\r
768\r
769/* Show autoconfiguration status */\r
770\r
771t_stat show_autocon (FILE *st, UNIT *uptr, int32 val, void *desc)\r
772{\r
773fprintf (st, "autoconfiguration ");\r
774fprintf (st, autcon_enb? "enabled": "disabled");\r
775return SCPE_OK;\r
776}\r
777\r
778/* Change device address */\r
779\r
780t_stat set_addr (UNIT *uptr, int32 val, char *cptr, void *desc)\r
781{\r
782DEVICE *dptr;\r
783DIB *dibp;\r
784uint32 newba;\r
785t_stat r;\r
786\r
787if (cptr == NULL) return SCPE_ARG;\r
788if ((val == 0) || (uptr == NULL)) return SCPE_IERR;\r
789dptr = find_dev_from_unit (uptr);\r
790if (dptr == NULL) return SCPE_IERR;\r
791dibp = (DIB *) dptr->ctxt;\r
792if (dibp == NULL) return SCPE_IERR;\r
793newba = (uint32) get_uint (cptr, 16, IOPAGEBASE+IOPAGEMASK, &r); /* get new */\r
794if (r != SCPE_OK) return r;\r
795if ((newba <= IOPAGEBASE) || /* must be > 0 */\r
796 (newba % ((uint32) val))) return SCPE_ARG; /* check modulus */\r
797dibp->ba = newba; /* store */\r
798dptr->flags = dptr->flags & ~DEV_FLTA; /* not floating */\r
799autcon_enb = 0; /* autoconfig off */\r
800return SCPE_OK;\r
801}\r
802\r
803/* Show device address */\r
804\r
805t_stat show_addr (FILE *st, UNIT *uptr, int32 val, void *desc)\r
806{\r
807DEVICE *dptr;\r
808DIB *dibp;\r
809\r
810if (uptr == NULL) return SCPE_IERR;\r
811dptr = find_dev_from_unit (uptr);\r
812if (dptr == NULL) return SCPE_IERR;\r
813dibp = (DIB *) dptr->ctxt;\r
814if ((dibp == NULL) || (dibp->ba <= IOPAGEBASE)) return SCPE_IERR;\r
815fprintf (st, "address=%08X", dibp->ba);\r
816if (dibp->lnt > 1)\r
817 fprintf (st, "-%08X", dibp->ba + dibp->lnt - 1);\r
818if (dptr->flags & DEV_FLTA) fprintf (st, "*");\r
819return SCPE_OK;\r
820}\r
821\r
822/* Set address floating */\r
823\r
824t_stat set_addr_flt (UNIT *uptr, int32 val, char *cptr, void *desc)\r
825{\r
826DEVICE *dptr;\r
827\r
828if (cptr == NULL) return SCPE_ARG;\r
829if ((val == 0) || (uptr == NULL)) return SCPE_IERR;\r
830dptr = find_dev_from_unit (uptr);\r
831if (dptr == NULL) return SCPE_IERR;\r
832dptr->flags = dptr->flags | DEV_FLTA; /* floating */\r
833return auto_config (NULL, 0); /* autoconfigure */\r
834}\r
835\r
836/* Change device vector */\r
837\r
838t_stat set_vec (UNIT *uptr, int32 arg, char *cptr, void *desc)\r
839{\r
840DEVICE *dptr;\r
841DIB *dibp;\r
842uint32 newvec;\r
843t_stat r;\r
844\r
845if (cptr == NULL) return SCPE_ARG;\r
846if (uptr == NULL) return SCPE_IERR;\r
847dptr = find_dev_from_unit (uptr);\r
848if (dptr == NULL) return SCPE_IERR;\r
849dibp = (DIB *) dptr->ctxt;\r
850if (dibp == NULL) return SCPE_IERR;\r
851newvec = (uint32) get_uint (cptr, 16, VEC_Q + 01000, &r);\r
852if ((r != SCPE_OK) || (newvec <= VEC_Q) ||\r
853 ((newvec + (dibp->vnum * 4)) >= (VEC_Q + 01000)) ||\r
854 (newvec & ((dibp->vnum > 1)? 07: 03))) return SCPE_ARG;\r
855dibp->vec = newvec;\r
856dptr->flags = dptr->flags & ~DEV_FLTA; /* not floating */\r
857autcon_enb = 0; /* autoconfig off */\r
858return SCPE_OK;\r
859}\r
860\r
861/* Show device vector */\r
862\r
863t_stat show_vec (FILE *st, UNIT *uptr, int32 arg, void *desc)\r
864{\r
865DEVICE *dptr;\r
866DIB *dibp;\r
867uint32 vec, numvec;\r
868\r
869if (uptr == NULL) return SCPE_IERR;\r
870dptr = find_dev_from_unit (uptr);\r
871if (dptr == NULL) return SCPE_IERR;\r
872dibp = (DIB *) dptr->ctxt;\r
873if (dibp == NULL) return SCPE_IERR;\r
874vec = dibp->vec;\r
875if (arg) numvec = arg;\r
876else numvec = dibp->vnum;\r
877if (vec == 0) fprintf (st, "no vector");\r
878else {\r
879 fprintf (st, "vector=%X", vec);\r
880 if (numvec > 1) fprintf (st, "-%X", vec + (4 * (numvec - 1)));\r
881 }\r
882return SCPE_OK;\r
883}\r
884\r
885/* Build dispatch tables */\r
886\r
887t_stat build_dsp_tab (DEVICE *dptr, DIB *dibp)\r
888{\r
889uint32 i, idx;\r
890\r
891if ((dptr == NULL) || (dibp == NULL)) return SCPE_IERR; /* validate args */\r
892for (i = 0; i < dibp->lnt; i = i + 2) { /* create entries */\r
893 idx = ((dibp->ba + i) & IOPAGEMASK) >> 1; /* index into disp */\r
894 if ((iodispR[idx] && dibp->rd && /* conflict? */\r
895 (iodispR[idx] != dibp->rd)) ||\r
896 (iodispW[idx] && dibp->wr &&\r
897 (iodispW[idx] != dibp->wr))) {\r
898 printf ("Device %s address conflict at %08o\n",\r
899 sim_dname (dptr), dibp->ba);\r
900 if (sim_log) fprintf (sim_log,\r
901 "Device %s address conflict at %08o\n",\r
902 sim_dname (dptr), dibp->ba);\r
903 return SCPE_STOP;\r
904 }\r
905 if (dibp->rd) iodispR[idx] = dibp->rd; /* set rd dispatch */\r
906 if (dibp->wr) iodispW[idx] = dibp->wr; /* set wr dispatch */\r
907 iodibp[idx] = dibp; /* remember DIB */\r
908 }\r
909return SCPE_OK;\r
910}\r
911\r
912\r
913/* Build interrupt tables */\r
914\r
915t_stat build_int_vec (DEVICE *dptr, DIB *dibp)\r
916{\r
917int32 i, idx, vec, ilvl, ibit;\r
918\r
919if ((dptr == NULL) || (dibp == NULL)) return SCPE_IERR; /* validate args */\r
920if (dibp->vnum > VEC_DEVMAX) return SCPE_IERR;\r
921for (i = 0; i < dibp->vnum; i++) { /* loop thru vec */\r
922 idx = dibp->vloc + i; /* vector index */\r
923 vec = dibp->vec? (dibp->vec + (i * 4)): 0; /* vector addr */\r
924 ilvl = idx / 32;\r
925 ibit = idx % 32;\r
926 if ((int_ack[ilvl][ibit] && dibp->ack[i] && /* conflict? */\r
927 (int_ack[ilvl][ibit] != dibp->ack[i])) ||\r
928 (int_vec[ilvl][ibit] && vec &&\r
929 (int_vec[ilvl][ibit] != vec))) {\r
930 printf ("Device %s interrupt slot conflict at %d\n",\r
931 sim_dname (dptr), idx);\r
932 if (sim_log) fprintf (sim_log,\r
933 "Device %s interrupt slot conflict at %d\n",\r
934 sim_dname (dptr), idx);\r
935 return SCPE_STOP;\r
936 }\r
937 if (dibp->ack[i]) int_ack[ilvl][ibit] = dibp->ack[i];\r
938 else if (vec) int_vec[ilvl][ibit] = vec;\r
939 }\r
940return SCPE_OK;\r
941}\r
942\r
943/* Build dib_tab from device list */\r
944\r
945t_stat build_dib_tab (void)\r
946{\r
947int32 i, j;\r
948DEVICE *dptr;\r
949DIB *dibp;\r
950t_stat r;\r
951\r
952for (i = 0; i < IPL_HLVL; i++) { /* clear int tables */\r
953 for (j = 0; j < 32; j++) {\r
954 int_vec[i][j] = 0;\r
955 int_ack[i][j] = NULL;\r
956 }\r
957 }\r
958for (i = 0; i < (IOPAGESIZE >> 1); i++) { /* clear dispatch tab */\r
959 iodispR[i] = NULL;\r
960 iodispW[i] = NULL;\r
961 iodibp[i] = NULL;\r
962 }\r
963for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */\r
964 dibp = (DIB *) dptr->ctxt; /* get DIB */\r
965 if (dibp && !(dptr->flags & DEV_DIS)) { /* defined, enabled? */\r
966 if (r = build_int_vec (dptr, dibp)) /* add to intr tab */\r
967 return r;\r
968 if (r = build_dsp_tab (dptr, dibp)) /* add to dispatch tab */\r
969 return r;\r
970 } /* end if enabled */\r
971 } /* end for */\r
972return SCPE_OK;\r
973}\r
974\r
975/* Show IO space */\r
976\r
977t_stat show_iospace (FILE *st, UNIT *uptr, int32 val, void *desc)\r
978{\r
979uint32 i, j;\r
980DEVICE *dptr;\r
981DIB *dibp;\r
982\r
983if (build_dib_tab ()) return SCPE_OK; /* build IO page */\r
984for (i = 0, dibp = NULL; i < (IOPAGESIZE >> 1); i++) { /* loop thru entries */\r
985 if (iodibp[i] && (iodibp[i] != dibp)) { /* new block? */\r
986 dibp = iodibp[i]; /* DIB for block */\r
987 for (j = 0, dptr = NULL; sim_devices[j] != NULL; j++) {\r
988 if (((DIB*) sim_devices[j]->ctxt) == dibp) {\r
989 dptr = sim_devices[j]; /* locate device */\r
990 break;\r
991 } /* end if */\r
992 } /* end for j */\r
993 fprintf (st, "%08X - %08X%c\t%s\n", dibp->ba,\r
994 dibp->ba + dibp->lnt - 1,\r
995 (dptr && (dptr->flags & DEV_FLTA))? '*': ' ',\r
996 dptr? sim_dname (dptr): "CPU");\r
997 } /* end if */\r
998 } /* end for i */\r
999return SCPE_OK;\r
1000}\r
1001\r
1002/* Show QBA virtual address */\r
1003\r
1004t_stat qba_show_virt (FILE *of, UNIT *uptr, int32 val, void *desc)\r
1005{\r
1006t_stat r;\r
1007char *cptr = (char *) desc;\r
1008uint32 qa, pa;\r
1009\r
1010if (cptr) {\r
1011 qa = (uint32) get_uint (cptr, 16, CQMSIZE - 1, &r);\r
1012 if (r == SCPE_OK) {\r
1013 if (qba_map_addr_c (qa, &pa))\r
1014 fprintf (of, "Qbus %-X = physical %-X\n", qa, pa);\r
1015 else fprintf (of, "Qbus %-X: invalid mapping\n", qa);\r
1016 return SCPE_OK;\r
1017 }\r
1018 }\r
1019fprintf (of, "Invalid argument\n");\r
1020return SCPE_OK;\r
1021}\r
1022\r
1023/* Autoconfiguration\r
1024\r
1025 The table reflects the MicroVAX 3900 microcode, with one addition - the\r
1026 number of controllers field handles devices where multiple instances\r
1027 are simulated through a single DEVICE structure (e.g., DZ, VH).\r
1028\r
1029 A minus number of vectors indicates a field that should be calculated\r
1030 but not placed in the DIB (RQ, TQ dynamic vectors) */\r
1031\r
1032#define AUTO_MAXC 4\r
1033#define AUTO_CSRBASE 0010\r
1034#define AUTO_VECBASE 0300\r
1035\r
1036typedef struct {\r
1037 char *dnam[AUTO_MAXC];\r
1038 int32 numc;\r
1039 int32 numv;\r
1040 uint32 amod;\r
1041 uint32 vmod;\r
1042 uint32 fixa[AUTO_MAXC];\r
1043 uint32 fixv[AUTO_MAXC];\r
1044 } AUTO_CON;\r
1045\r
1046AUTO_CON auto_tab[] = {\r
1047 { { NULL }, 1, 2, 0, 8, { 0 } }, /* DLV11J - fx CSRs */\r
1048 { { NULL }, 1, 2, 8, 8 }, /* DJ11 */\r
1049 { { NULL }, 1, 2, 16, 8 }, /* DH11 */\r
1050 { { NULL }, 1, 2, 8, 8 }, /* DQ11 */\r
1051 { { NULL }, 1, 2, 8, 8 }, /* DU11 */\r
1052 { { NULL }, 1, 2, 8, 8 }, /* DUP11 */\r
1053 { { NULL }, 10, 2, 8, 8 }, /* LK11A */\r
1054 { { NULL }, 1, 2, 8, 8 }, /* DMC11 */\r
1055 { { "DZ" }, DZ_MUXES, 2, 8, 8 }, /* DZ11 */\r
1056 { { NULL }, 1, 2, 8, 8 }, /* KMC11 */\r
1057 { { NULL }, 1, 2, 8, 8 }, /* LPP11 */\r
1058 { { NULL }, 1, 2, 8, 8 }, /* VMV21 */\r
1059 { { NULL }, 1, 2, 16, 8 }, /* VMV31 */\r
1060 { { NULL }, 1, 2, 8, 8 }, /* DWR70 */\r
1061 { { "RL", "RLB" }, 1, 1, 8, 4, {IOBA_RL}, {VEC_RL} }, /* RL11 */\r
1062 { { "TS", "TSB", "TSC", "TSD" }, 1, 1, 0, 4, /* TS11 */\r
1063 {IOBA_TS, IOBA_TS + 4, IOBA_TS + 8, IOBA_TS + 12},\r
1064 {VEC_TS} },\r
1065 { { NULL }, 1, 2, 16, 8 }, /* LPA11K */\r
1066 { { NULL }, 1, 2, 8, 8 }, /* KW11C */\r
1067 { { NULL }, 1, 1, 8, 8 }, /* reserved */\r
1068 { { "RX", "RY" }, 1, 1, 8, 4, {IOBA_RX} , {VEC_RX} }, /* RX11/RX211 */\r
1069 { { NULL }, 1, 1, 8, 4 }, /* DR11W */\r
1070 { { NULL }, 1, 1, 8, 4, { 0, 0 }, { 0 } }, /* DR11B - fx CSRs,vec */\r
1071 { { NULL }, 1, 2, 8, 8 }, /* DMP11 */\r
1072 { { NULL }, 1, 2, 8, 8 }, /* DPV11 */\r
1073 { { NULL }, 1, 2, 8, 8 }, /* ISB11 */\r
1074 { { NULL }, 1, 2, 16, 8 }, /* DMV11 */\r
1075 { { "XU", "XUB" }, 1, 1, 8, 4, {IOBA_XU}, {VEC_XU} }, /* DEUNA */\r
1076 { { "XQ", "XQB" }, 1, 1, 0, 4, /* DEQNA */\r
1077 {IOBA_XQ,IOBA_XQB}, {VEC_XQ} },\r
1078 { { "RQ", "RQB", "RQC", "RQD" }, 1, -1, 4, 4, /* RQDX3 */\r
1079 {IOBA_RQ}, {VEC_RQ} },\r
1080 { { NULL }, 1, 8, 32, 4 }, /* DMF32 */\r
1081 { { NULL }, 1, 2, 16, 8 }, /* KMS11 */\r
1082 { { NULL }, 1, 1, 16, 4 }, /* VS100 */\r
1083 { { "TQ", "TQB" }, 1, -1, 4, 4, {IOBA_TQ}, {VEC_TQ} }, /* TQK50 */\r
1084 { { NULL }, 1, 2, 16, 8 }, /* KMV11 */\r
1085 { { "VH" }, VH_MUXES, 2, 16, 8 }, /* DHU11/DHQ11 */\r
1086 { { NULL }, 1, 6, 32, 4 }, /* DMZ32 */\r
1087 { { NULL }, 1, 6, 32, 4 }, /* CP132 */\r
1088 { { NULL }, 1, 2, 64, 8, { 0 } }, /* QVSS - fx CSR */\r
1089 { { NULL }, 1, 1, 8, 4 }, /* VS31 */\r
1090 { { NULL }, 1, 1, 0, 4, { 0 } }, /* LNV11 - fx CSR */\r
1091 { { NULL }, 1, 1, 16, 4 }, /* LNV21/QPSS */\r
1092 { { NULL }, 1, 1, 8, 4, { 0 } }, /* QTA - fx CSR */\r
1093 { { NULL }, 1, 1, 8, 4 }, /* DSV11 */\r
1094 { { NULL }, 1, 2, 8, 8 }, /* CSAM */\r
1095 { { NULL }, 1, 2, 8, 8 }, /* ADV11C */\r
1096 { { NULL }, 1, 0, 8, 0 }, /* AAV11C */\r
1097 { { NULL }, 1, 2, 8, 8, { 0 }, { 0 } }, /* AXV11C - fx CSR,vec */\r
1098 { { NULL }, 1, 2, 4, 8, { 0 } }, /* KWV11C - fx CSR */\r
1099 { { NULL }, 1, 2, 8, 8, { 0 } }, /* ADV11D - fx CSR */\r
1100 { { NULL }, 1, 2, 8, 8, { 0 } }, /* AAV11D - fx CSR */\r
1101 { { "QDSS" }, 1, 3, 0, 16, {IOBA_QDSS} }, /* QDSS - fx CSR */\r
1102 { { NULL }, -1 } /* end table */\r
1103};\r
1104\r
1105t_stat auto_config (char *name, int32 nctrl)\r
1106{\r
1107uint32 csr = IOPAGEBASE + AUTO_CSRBASE;\r
1108uint32 vec = VEC_Q + AUTO_VECBASE;\r
1109AUTO_CON *autp;\r
1110DEVICE *dptr;\r
1111DIB *dibp;\r
1112uint32 j, k, vmask, amask;\r
1113\r
1114if (autcon_enb == 0) return SCPE_OK; /* enabled? */\r
1115if (name) { /* updating? */\r
1116 if (nctrl < 0) return SCPE_ARG;\r
1117 for (autp = auto_tab; autp->numc >= 0; autp++) {\r
1118 for (j = 0; (j < AUTO_MAXC) && autp->dnam[j]; j++) {\r
1119 if (strcmp (name, autp->dnam[j]) == 0)\r
1120 autp->numc = nctrl;\r
1121 }\r
1122 }\r
1123 }\r
1124for (autp = auto_tab; autp->numc >= 0; autp++) { /* loop thru table */\r
1125 if (autp->amod) { /* floating csr? */\r
1126 amask = autp->amod - 1;\r
1127 csr = (csr + amask) & ~amask; /* align csr */\r
1128 }\r
1129 for (j = k = 0; (j < AUTO_MAXC) && autp->dnam[j]; j++) {\r
1130 dptr = find_dev (autp->dnam[j]); /* find ctrl */\r
1131 if ((dptr == NULL) || (dptr->flags & DEV_DIS) ||\r
1132 !(dptr->flags & DEV_FLTA)) continue; /* enabled, floating? */\r
1133 dibp = (DIB *) dptr->ctxt; /* get DIB */\r
1134 if (dibp == NULL) return SCPE_IERR; /* not there??? */\r
1135 if (autp->amod) { /* dyn csr needed? */\r
1136 if (autp->fixa[k]) /* fixed csr avail? */\r
1137 dibp->ba = autp->fixa[k]; /* use it */\r
1138 else { /* no fixed left */\r
1139 dibp->ba = csr; /* set CSR */\r
1140 csr += (autp->numc * autp->amod); /* next CSR */\r
1141 } /* end else */\r
1142 } /* end if dyn csr */\r
1143 if (autp->numv && autp->vmod) { /* dyn vec needed? */\r
1144 uint32 numv = abs (autp->numv); /* get num vec */\r
1145 if (autp->fixv[k]) { /* fixed vec avail? */\r
1146 if (autp->numv > 0)\r
1147 dibp->vec = autp->fixv[k]; /* use it */\r
1148 }\r
1149 else { /* no fixed left */\r
1150 vmask = autp->vmod - 1;\r
1151 vec = (vec + vmask) & ~vmask; /* align vector */\r
1152 if (autp->numv > 0)\r
1153 dibp->vec = vec; /* set vector */\r
1154 vec += (autp->numc * numv * 4);\r
1155 } /* end else */\r
1156 } /* end if dyn vec */\r
1157 k++; /* next instance */\r
1158 } /* end for j */\r
1159 if (autp->amod) csr = csr + 2; /* flt CSR? gap */\r
1160 } /* end for i */\r
1161return SCPE_OK;\r
1162}\r