~ubuntu-branches/ubuntu/utopic/simh/utopic

« back to all changes in this revision

Viewing changes to VAX/vax_io.c

  • Committer: Bazaar Package Importer
  • Author(s): Vince Mulhollon
  • Date: 2004-04-20 20:01:26 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20040420200126-ehsuleda8xcgi51h
Tags: 3.2.0-1
New upstream 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* vax_io.c: VAX Qbus IO simulator
 
2
 
 
3
   Copyright (c) 1998-2004, Robert M Supnik
 
4
 
 
5
   Permission is hereby granted, free of charge, to any person obtaining a
 
6
   copy of this software and associated documentation files (the "Software"),
 
7
   to deal in the Software without restriction, including without limitation
 
8
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
 
9
   and/or sell copies of the Software, and to permit persons to whom the
 
10
   Software is furnished to do so, subject to the following conditions:
 
11
 
 
12
   The above copyright notice and this permission notice shall be included in
 
13
   all copies or substantial portions of the Software.
 
14
 
 
15
   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
16
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
17
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 
18
   ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 
19
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 
20
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
21
 
 
22
   Except as contained in this notice, the name of Robert M Supnik shall not
 
23
   be used in advertising or otherwise to promote the sale, use or other dealings
 
24
   in this Software without prior written authorization from Robert M Supnik.
 
25
 
 
26
   qba          Qbus adapter
 
27
 
 
28
   21-Mar-04    RMS     Added RXV21 support
 
29
   21-Dec-03    RMS     Fixed bug in autoconfigure vector assignment; added controls
 
30
   21-Nov-03    RMS     Added check for interrupt slot conflict (found by Dave Hittner)
 
31
   29-Oct-03    RMS     Fixed WriteX declaration (found by Mark Pizzolato)
 
32
   19-Apr-03    RMS     Added optimized byte and word DMA routines
 
33
   12-Mar-03    RMS     Added logical name support
 
34
   22-Dec-02    RMS     Added console halt support
 
35
   12-Oct-02    RMS     Added autoconfigure support
 
36
                        Added SHOW IO space routine
 
37
   29-Sep-02    RMS     Added dynamic table support
 
38
   07-Sep-02    RMS     Added TMSCP and variable vector support
 
39
*/
 
40
 
 
41
#include "vax_defs.h"
 
42
 
 
43
/* CQBIC system configuration register */
 
44
 
 
45
#define CQSCR_POK       0x00008000                      /* power ok RO1 */
 
46
#define CQSCR_BHL       0x00004000                      /* BHALT enb */
 
47
#define CQSCR_AUX       0x00000400                      /* aux mode RONI */
 
48
#define CQSCR_DBO       0x0000000C                      /* offset NI */
 
49
#define CQSCR_RW        (CQSCR_BHL | CQSCR_DBO)
 
50
#define CQSCR_MASK      (CQSCR_RW | CQSCR_POK | CQSCR_AUX)
 
51
 
 
52
/* CQBIC DMA system error register - W1C */
 
53
 
 
54
#define CQDSER_BHL      0x00008000                      /* BHALT NI */
 
55
#define CQDSER_DCN      0x00004000                      /* DC ~OK NI */
 
56
#define CQDSER_MNX      0x00000080                      /* master NXM */
 
57
#define CQDSER_MPE      0x00000020                      /* master par NI */
 
58
#define CQDSER_SME      0x00000010                      /* slv mem err NI */
 
59
#define CQDSER_LST      0x00000008                      /* lost err */
 
60
#define CQDSER_TMO      0x00000004                      /* no grant NI */
 
61
#define CQDSER_SNX      0x00000001                      /* slave NXM */
 
62
#define CQDSER_ERR      (CQDSER_MNX | CQDSER_MPE | CQDSER_TMO | CQDSER_SNX)
 
63
#define CQDSER_MASK     0x0000C0BD
 
64
 
 
65
/* CQBIC master error address register */
 
66
 
 
67
#define CQMEAR_MASK     0x00001FFF                      /* Qbus page */
 
68
 
 
69
/* CQBIC slave error address register */
 
70
 
 
71
#define CQSEAR_MASK     0x000FFFFF                      /* mem page */
 
72
 
 
73
/* CQBIC map base register */
 
74
 
 
75
#define CQMBR_MASK      0x1FFF8000                      /* 32KB aligned */
 
76
 
 
77
/* CQBIC IPC register */
 
78
 
 
79
#define CQIPC_QME       0x00008000                      /* Qbus read NXM W1C */
 
80
#define CQIPC_INV       0x00004000                      /* CAM inval NIWO */
 
81
#define CQIPC_AHLT      0x00000100                      /* aux halt NI */
 
82
#define CQIPC_DBIE      0x00000040                      /* dbell int enb NI */
 
83
#define CQIPC_LME       0x00000020                      /* local mem enb */
 
84
#define CQIPC_DB        0x00000001                      /* doorbell req NI */
 
85
#define CQIPC_W1C       CQIPC_QME
 
86
#define CQIPC_RW        (CQIPC_AHLT | CQIPC_DBIE | CQIPC_LME | CQIPC_DB)
 
87
#define CQIPC_MASK      (CQIPC_RW | CQIPC_QME )
 
88
 
 
89
/* CQBIC map entry */
 
90
 
 
91
#define CQMAP_VLD       0x80000000                      /* valid */
 
92
#define CQMAP_PAG       0x000FFFFF                      /* mem page */
 
93
 
 
94
int32 int_req[IPL_HLVL] = { 0 };                        /* intr, IPL 14-17 */
 
95
int32 cq_scr = 0;                                       /* SCR */
 
96
int32 cq_dser = 0;                                      /* DSER */
 
97
int32 cq_mear = 0;                                      /* MEAR */
 
98
int32 cq_sear = 0;                                      /* SEAR */
 
99
int32 cq_mbr = 0;                                       /* MBR */
 
100
int32 cq_ipc = 0;                                       /* IPC */
 
101
 
 
102
extern uint32 *M;
 
103
extern UNIT cpu_unit;
 
104
extern int32 PSL, SISR, trpirq, mem_err, hlt_pin;
 
105
extern int32 p1;
 
106
extern int32 ssc_bto;
 
107
extern int32 autcon_enb;
 
108
extern jmp_buf save_env;
 
109
extern DEVICE *sim_devices[];
 
110
 
 
111
extern int32 ReadB (uint32 pa);
 
112
extern int32 ReadW (uint32 pa);
 
113
extern int32 ReadL (uint32 pa);
 
114
extern void WriteB (uint32 pa, int32 val);
 
115
extern void WriteW (uint32 pa, int32 val);
 
116
extern void WriteL (uint32 pa, int32 val);
 
117
extern FILE *sim_log;
 
118
 
 
119
t_stat dbl_rd (int32 *data, int32 addr, int32 access);
 
120
t_stat dbl_wr (int32 data, int32 addr, int32 access);
 
121
int32 eval_int (void);
 
122
void cq_merr (int32 pa);
 
123
void cq_serr (int32 pa);
 
124
t_stat qba_reset (DEVICE *dptr);
 
125
 
 
126
/* Qbus adapter data structures
 
127
 
 
128
   qba_dev      QBA device descriptor
 
129
   qba_unit     QBA units
 
130
   qba_reg      QBA register list
 
131
*/
 
132
 
 
133
DIB qba_dib = { IOBA_DBL, IOLN_DBL, &dbl_rd, &dbl_wr, 0 };
 
134
 
 
135
UNIT qba_unit = { UDATA (NULL, 0, 0) };
 
136
 
 
137
REG qba_reg[] = {
 
138
        { HRDATA (SCR, cq_scr, 16) },
 
139
        { HRDATA (DSER, cq_dser, 8) },
 
140
        { HRDATA (MEAR, cq_mear, 13) },
 
141
        { HRDATA (SEAR, cq_sear, 20) },
 
142
        { HRDATA (MBR, cq_mbr, 29) },
 
143
        { HRDATA (IPC, cq_ipc, 16) },
 
144
        { HRDATA (IPL17, int_req[3], 32), REG_RO },
 
145
        { HRDATA (IPL16, int_req[2], 32), REG_RO },
 
146
        { HRDATA (IPL15, int_req[1], 32), REG_RO },
 
147
        { HRDATA (IPL14, int_req[0], 32), REG_RO },
 
148
        { NULL }  };
 
149
 
 
150
DEVICE qba_dev = {
 
151
        "QBA", &qba_unit, qba_reg, NULL,
 
152
        1, 0, 0, 0, 0, 0,
 
153
        NULL, NULL, &qba_reset,
 
154
        NULL, NULL, NULL,
 
155
        &qba_dib, DEV_QBUS };
 
156
 
 
157
/* IO page addresses */
 
158
 
 
159
DIB *dib_tab[DIB_MAX];                                  /* DIB table */
 
160
 
 
161
/* Interrupt request to interrupt action map */
 
162
 
 
163
int32 (*int_ack[IPL_HLVL][32])();                       /* int ack routines */
 
164
 
 
165
/* Interrupt request to vector map */
 
166
 
 
167
int32 int_vec[IPL_HLVL][32];                            /* int req to vector */
 
168
 
 
169
/* The KA65x handles errors in I/O space as follows
 
170
 
 
171
        - read: set DSER<7>, latch addr in MEAR, machine check
 
172
        - write: set DSER<7>, latch addr in MEAR, MEMERR interrupt
 
173
*/
 
174
 
 
175
int32 ReadQb (uint32 pa)
 
176
{
 
177
int32 i, val;
 
178
DIB *dibp;
 
179
 
 
180
for (i = 0; dibp = dib_tab[i]; i++ ) {
 
181
        if ((pa >= dibp->ba) &&
 
182
           (pa < (dibp->ba + dibp->lnt))) {
 
183
            dibp->rd (&val, pa, READ);
 
184
            return val;  }  }
 
185
cq_merr (pa);
 
186
MACH_CHECK (MCHK_READ);
 
187
return 0;
 
188
}
 
189
 
 
190
void WriteQb (uint32 pa, int32 val, int32 mode)
 
191
{
 
192
int32 i;
 
193
DIB *dibp;
 
194
 
 
195
for (i = 0; dibp = dib_tab[i]; i++ ) {
 
196
        if ((pa >= dibp->ba) &&
 
197
           (pa < (dibp->ba + dibp->lnt))) {
 
198
            dibp->wr (val, pa, mode);
 
199
            return;  }  }
 
200
cq_merr (pa);
 
201
mem_err = 1;
 
202
return;
 
203
}
 
204
 
 
205
/* ReadIO - read I/O space
 
206
 
 
207
   Inputs:
 
208
        pa      =       physical address
 
209
        lnt     =       length (BWLQ)
 
210
   Output:
 
211
        longword of data
 
212
*/
 
213
 
 
214
int32 ReadIO (int32 pa, int32 lnt)
 
215
{
 
216
int32 iod;
 
217
 
 
218
iod = ReadQb (pa);                                      /* wd from Qbus */
 
219
if (lnt < L_LONG) iod = iod << ((pa & 2)? 16: 0);       /* bw? position */
 
220
else iod = (ReadQb (pa + 2) << 16) | iod;               /* lw, get 2nd wd */
 
221
SET_IRQL;
 
222
return iod;
 
223
}
 
224
 
 
225
/* WriteIO - write I/O space
 
226
 
 
227
   Inputs:
 
228
        pa      =       physical address
 
229
        val     =       data to write, right justified in 32b longword
 
230
        lnt     =       length (BWLQ)
 
231
   Outputs:
 
232
        none
 
233
*/
 
234
 
 
235
void WriteIO (int32 pa, int32 val, int32 lnt)
 
236
{
 
237
if (lnt == L_BYTE) WriteQb (pa, val, WRITEB);
 
238
else if (lnt == L_WORD) WriteQb (pa, val, WRITE);
 
239
else {  WriteQb (pa, val & 0xFFFF, WRITE);
 
240
        WriteQb (pa + 2, (val >> 16) & 0xFFFF, WRITE);  }
 
241
SET_IRQL;
 
242
return;
 
243
}
 
244
 
 
245
/* Find highest priority outstanding interrupt */
 
246
 
 
247
int32 eval_int (void)
 
248
{
 
249
int32 ipl = PSL_GETIPL (PSL);
 
250
int32 i, t;
 
251
 
 
252
static const int32 sw_int_mask[IPL_SMAX] = {
 
253
        0xFFFE, 0xFFFC, 0xFFF8, 0xFFF0,                 /* 0 - 3 */
 
254
        0xFFE0, 0xFFC0, 0xFF80, 0xFF00,                 /* 4 - 7 */
 
255
        0xFE00, 0xFC00, 0xF800, 0xF000,                 /* 8 - B */
 
256
        0xE000, 0xC000, 0x8000 };                       /* C - E */
 
257
 
 
258
if (hlt_pin) return IPL_HLTPIN;                         /* hlt pin int */
 
259
if ((ipl < IPL_MEMERR) && mem_err) return IPL_MEMERR;   /* mem err int */
 
260
for (i = IPL_HMAX; i >= IPL_HMIN; i--) {                /* chk hwre int */
 
261
        if (i <= ipl) return 0;                         /* at ipl? no int */
 
262
        if (int_req[i - IPL_HMIN]) return i;  }         /* req != 0? int */
 
263
if (ipl >= IPL_SMAX) return 0;                          /* ipl >= sw max? */
 
264
if ((t = SISR & sw_int_mask[ipl]) == 0) return 0;       /* eligible req */
 
265
for (i = IPL_SMAX; i > ipl; i--) {                      /* check swre int */
 
266
        if ((t >> i) & 1) return i;  }                  /* req != 0? int */
 
267
return 0;
 
268
}
 
269
 
 
270
/* Return vector for highest priority hardware interrupt at IPL lvl */
 
271
 
 
272
int32 get_vector (int32 lvl)
 
273
{
 
274
int32 i;
 
275
int32 l = lvl - IPL_HMIN;
 
276
 
 
277
for (i = 0; int_req[l] && (i < 32); i++) {
 
278
        if ((int_req[l] >> i) & 1) {
 
279
            int_req[l] = int_req[l] & ~(1u << i);
 
280
            if (int_ack[l][i]) return int_ack[l][i]();
 
281
            return int_vec[l][i];  }  }
 
282
return 0;
 
283
}
 
284
 
 
285
/* CQBIC registers
 
286
 
 
287
   SCR          system configuration register
 
288
   DSER         DMA system error register (W1C)
 
289
   MEAR         master error address register (RO)
 
290
   SEAR         slave error address register (RO)
 
291
   MBR          map base register
 
292
   IPC          inter-processor communication register
 
293
*/
 
294
 
 
295
int32 cqbic_rd (int32 pa)
 
296
{
 
297
int32 rg = (pa - CQBICBASE) >> 2;
 
298
 
 
299
switch (rg) {
 
300
case 0:                                                 /* SCR */
 
301
        return (cq_scr | CQSCR_POK) & CQSCR_MASK;
 
302
case 1:                                                 /* DSER */
 
303
        return cq_dser & CQDSER_MASK;
 
304
case 2:                                                 /* MEAR */
 
305
        return cq_mear & CQMEAR_MASK;
 
306
case 3:                                                 /* SEAR */
 
307
        return cq_sear & CQSEAR_MASK;
 
308
case 4:                                                 /* MBR */
 
309
        return cq_mbr & CQMBR_MASK;  }
 
310
return 0;
 
311
}
 
312
 
 
313
void cqbic_wr (int32 pa, int32 val, int32 lnt)
 
314
{
 
315
int32 nval, rg = (pa - CQBICBASE) >> 2;
 
316
 
 
317
if (lnt < L_LONG) {
 
318
        int32 sc = (pa & 3) << 3;
 
319
        int32 mask = (lnt == L_WORD)? 0xFFFF: 0xFF;
 
320
        int32 t = cqbic_rd (pa);
 
321
        nval = ((val & mask) << sc) | (t & ~(mask << sc));
 
322
        val = val << sc;  }
 
323
else nval = val;
 
324
 
 
325
switch (rg) {
 
326
case 0:                                                 /* SCR */
 
327
        cq_scr = ((cq_scr & ~CQSCR_RW) | (nval & CQSCR_RW)) & CQSCR_MASK;
 
328
        break;
 
329
case 1:                                                 /* DSER */
 
330
        cq_dser = (cq_dser & ~val) & CQDSER_MASK;
 
331
        if (val & CQDSER_SME) cq_ipc = cq_ipc & ~CQIPC_QME;
 
332
        break;
 
333
case 2: case 3:
 
334
        cq_merr (pa);                                   /* MEAR, SEAR */
 
335
        MACH_CHECK (MCHK_WRITE);
 
336
        break;
 
337
case 4:                                                 /* MBR */
 
338
        cq_mbr = nval & CQMBR_MASK;
 
339
        break;  }
 
340
return;
 
341
}
 
342
 
 
343
/* IPC can be read as local register or as Qbus I/O
 
344
   Because of the W1C */
 
345
 
 
346
int32 cqipc_rd (int32 pa)
 
347
{
 
348
return cq_ipc & CQIPC_MASK;                             /* IPC */
 
349
}
 
350
 
 
351
void cqipc_wr (int32 pa, int32 val, int32 lnt)
 
352
{
 
353
int32 nval = val;
 
354
 
 
355
if (lnt < L_LONG) {
 
356
        int32 sc = (pa & 3) << 3;
 
357
        nval = val << sc;  }
 
358
 
 
359
cq_ipc = cq_ipc & ~(nval & CQIPC_W1C);                  /* W1C */
 
360
if ((pa & 3) == 0)                                      /* low byte only */
 
361
        cq_ipc = ((cq_ipc & ~CQIPC_RW) | (val & CQIPC_RW)) & CQIPC_MASK;
 
362
return;
 
363
}
 
364
 
 
365
/* I/O page routines */
 
366
 
 
367
t_stat dbl_rd (int32 *data, int32 addr, int32 access)
 
368
{
 
369
*data = cq_ipc & CQIPC_MASK;
 
370
return SCPE_OK;
 
371
}
 
372
 
 
373
t_stat dbl_wr (int32 data, int32 addr, int32 access)
 
374
{
 
375
cqipc_wr (addr, data, (access == WRITEB)? L_BYTE: L_WORD);
 
376
return SCPE_OK;
 
377
}
 
378
 
 
379
/* CQBIC map read and write (reflects to main memory)
 
380
 
 
381
   Read error: set DSER<0>, latch slave address, machine check
 
382
   Write error: set DSER<0>, latch slave address, memory error interrupt
 
383
*/
 
384
 
 
385
int32 cqmap_rd (int32 pa)
 
386
{
 
387
int32 ma = (pa & CQMAPAMASK) + cq_mbr;                  /* mem addr */
 
388
 
 
389
if (ADDR_IS_MEM (ma)) return M[ma >> 2];
 
390
cq_serr (ma);                                           /* set err */
 
391
MACH_CHECK (MCHK_READ);                                 /* mcheck */
 
392
return 0;
 
393
}
 
394
 
 
395
void cqmap_wr (int32 pa, int32 val, int32 lnt)
 
396
{
 
397
int32 ma = (pa & CQMAPAMASK) + cq_mbr;                  /* mem addr */
 
398
 
 
399
if (ADDR_IS_MEM (ma)) {
 
400
        if (lnt < L_LONG) {
 
401
            int32 sc = (pa & 3) << 3;
 
402
            int32 mask = (lnt == L_WORD)? 0xFFFF: 0xFF;
 
403
            int32 t = M[ma >> 2];
 
404
            val = ((val & mask) << sc) | (t & ~(mask << sc));  }
 
405
        M[ma >> 2] = val;  }
 
406
else {  cq_serr (ma);                                   /* error */
 
407
        mem_err = 1;  }
 
408
return;
 
409
}
 
410
 
 
411
/* CQBIC Qbus memory read and write (reflects to main memory)
 
412
 
 
413
   May give master or slave error, depending on where the failure occurs
 
414
*/
 
415
 
 
416
int32 cqmem_rd (int32 pa)
 
417
{
 
418
int32 qa = pa & CQMAMASK;                               /* Qbus addr */
 
419
uint32 ma;
 
420
 
 
421
if (map_addr (qa, &ma)) return M[ma >> 2];              /* map addr */
 
422
MACH_CHECK (MCHK_READ);                                 /* err? mcheck */
 
423
return 0;
 
424
}
 
425
 
 
426
void cqmem_wr (int32 pa, int32 val, int32 lnt)
 
427
{
 
428
int32 qa = pa & CQMAMASK;                               /* Qbus addr */
 
429
uint32 ma;
 
430
 
 
431
if (map_addr (qa, &ma)) {                               /* map addr */
 
432
        if (lnt < L_LONG) {
 
433
            int32 sc = (pa & 3) << 3;
 
434
            int32 mask = (lnt == L_WORD)? 0xFFFF: 0xFF;
 
435
            int32 t = M[ma >> 2];
 
436
            val = ((val & mask) << sc) | (t & ~(mask << sc));  }
 
437
        M[ma >> 2] = val;  }
 
438
else mem_err = 1;
 
439
return;
 
440
}
 
441
 
 
442
/* Map an address via the translation map */
 
443
 
 
444
t_bool map_addr (uint32 qa, uint32 *ma)
 
445
{
 
446
int32 qblk = (qa >> VA_V_VPN);                          /* Qbus blk */
 
447
int32 qmma = ((qblk << 2) & CQMAPAMASK) + cq_mbr;       /* map entry */
 
448
 
 
449
if (ADDR_IS_MEM (qmma)) {                               /* legit? */
 
450
        int32 qmap = M[qmma >> 2];                      /* get map */
 
451
        if (qmap & CQMAP_VLD) {                         /* valid? */
 
452
            *ma = ((qmap & CQMAP_PAG) << VA_V_VPN) + VA_GETOFF (qa);
 
453
            if (ADDR_IS_MEM (*ma)) return 1;            /* legit addr */
 
454
            cq_serr (*ma);                              /* slave nxm */
 
455
            return 0;  }
 
456
        cq_merr (qa);                                   /* master nxm */
 
457
        return 0;  }
 
458
cq_serr (0);                                            /* inv mem */
 
459
return 0;
 
460
}
 
461
 
 
462
/* Set master error */
 
463
 
 
464
void cq_merr (int32 pa)
 
465
{
 
466
if (cq_dser & CQDSER_ERR) cq_dser = cq_dser | CQDSER_LST;
 
467
cq_dser = cq_dser | CQDSER_MNX;                         /* master nxm */
 
468
cq_mear = (pa >> VA_V_VPN) & CQMEAR_MASK;               /* page addr */
 
469
return;
 
470
}
 
471
 
 
472
/* Set slave error */
 
473
 
 
474
void cq_serr (int32 pa)
 
475
{
 
476
if (cq_dser & CQDSER_ERR) cq_dser = cq_dser | CQDSER_LST;
 
477
cq_dser = cq_dser | CQDSER_SNX;                         /* slave nxm */
 
478
cq_sear = (pa >> VA_V_VPN) & CQSEAR_MASK;
 
479
return;
 
480
}
 
481
 
 
482
/* Reset I/O bus */
 
483
 
 
484
void ioreset_wr (int32 data)
 
485
{
 
486
reset_all (5);                                          /* from qba on... */
 
487
return;
 
488
}
 
489
 
 
490
/* Reset CQBIC */
 
491
 
 
492
t_stat qba_reset (DEVICE *dptr)
 
493
{
 
494
int32 i;
 
495
 
 
496
cq_scr = (cq_scr & CQSCR_BHL) | CQSCR_POK;
 
497
cq_dser = cq_mear = cq_sear = cq_ipc = 0;
 
498
for (i = 0; i < IPL_HLVL; i++) int_req[i] = 0;
 
499
return SCPE_OK;
 
500
}
 
501
 
 
502
/* Powerup CQBIC */
 
503
 
 
504
t_stat qba_powerup (void)
 
505
{
 
506
cq_mbr = 0;
 
507
cq_scr = CQSCR_POK;
 
508
return qba_reset (&qba_dev);
 
509
}
 
510
 
 
511
/* I/O buffer routines, aligned access
 
512
 
 
513
   map_ReadB    -       fetch byte buffer from memory
 
514
   map_ReadW    -       fetch word buffer from memory
 
515
   map_ReadL    -       fetch longword buffer from memory
 
516
   map_WriteB   -       store byte buffer into memory
 
517
   map_WriteW   -       store word buffer into memory
 
518
   map_WriteL   -       store longword buffer into memory
 
519
*/
 
520
 
 
521
int32 map_readB (uint32 ba, int32 bc, uint8 *buf)
 
522
{
 
523
int32 i;
 
524
uint32 ma, dat;
 
525
 
 
526
if ((ba | bc) & 03) {                                   /* check alignment */
 
527
        for (i = ma = 0; i < bc; i++, buf++) {          /* by bytes */
 
528
            if ((ma & VA_M_OFF) == 0) {                 /* need map? */
 
529
                if (!map_addr (ba + i, &ma) ||          /* inv or NXM? */
 
530
                    !ADDR_IS_MEM (ma)) return (bc - i);  }
 
531
                *buf = ReadB (ma);
 
532
                ma = ma + 1;  }
 
533
        }
 
534
else {  for (i = ma = 0; i < bc; i = i + 4, buf++) {    /* by longwords */
 
535
            if ((ma & VA_M_OFF) == 0) {                 /* need map? */
 
536
                if (!map_addr (ba + i, &ma) ||          /* inv or NXM? */
 
537
                    !ADDR_IS_MEM (ma)) return (bc - i);  }
 
538
            dat = ReadL (ma);                           /* get lw */
 
539
            *buf++ = dat & BMASK;                       /* low 8b */
 
540
            *buf++ = (dat >> 8) & BMASK;                /* next 8b */
 
541
            *buf++ = (dat >> 16) & BMASK;               /* next 8b */
 
542
            *buf = (dat >> 24) & BMASK;
 
543
            ma = ma + 4;  }
 
544
        }
 
545
return 0;
 
546
}
 
547
 
 
548
int32 map_readW (uint32 ba, int32 bc, uint16 *buf)
 
549
{
 
550
int32 i;
 
551
uint32 ma,dat;
 
552
 
 
553
ba = ba & ~01;
 
554
bc = bc & ~01;
 
555
if ((ba | bc) & 03) {                                   /* check alignment */
 
556
        for (i = ma = 0; i < bc; i = i + 2, buf++) {    /* by words */
 
557
            if ((ma & VA_M_OFF) == 0) {                 /* need map? */
 
558
                if (!map_addr (ba + i, &ma) ||          /* inv or NXM? */
 
559
                    !ADDR_IS_MEM (ma)) return (bc - i);  }
 
560
            *buf = ReadW (ma);
 
561
            ma = ma + 2;  }
 
562
        }
 
563
else {  for (i = ma = 0; i < bc; i = i + 4, buf++) {    /* by longwords */
 
564
            if ((ma & VA_M_OFF) == 0) {                 /* need map? */
 
565
                if (!map_addr (ba + i, &ma) ||          /* inv or NXM? */
 
566
                    !ADDR_IS_MEM (ma)) return (bc - i);  }
 
567
            dat = ReadL (ma);                           /* get lw */
 
568
            *buf++ = dat & WMASK;                       /* low 16b */
 
569
            *buf = (dat >> 16) & WMASK;                 /* high 16b */
 
570
            ma = ma + 4;  }
 
571
        }
 
572
return 0;
 
573
}
 
574
 
 
575
int32 map_readL (uint32 ba, int32 bc, uint32 *buf)
 
576
{
 
577
int32 i;
 
578
uint32 ma;
 
579
 
 
580
ba = ba & ~03;
 
581
bc = bc & ~03;
 
582
for (i = ma = 0; i < bc; i = i + 4, buf++) {            /* by lw */
 
583
        if ((ma & VA_M_OFF) == 0) {                     /* need map? */
 
584
            if (!map_addr (ba + i, &ma) ||              /* inv or NXM? */
 
585
                !ADDR_IS_MEM (ma)) return (bc - i);  }
 
586
        *buf = ReadL (ma);
 
587
        ma = ma + 4;  }
 
588
return 0;
 
589
}
 
590
 
 
591
int32 map_writeB (uint32 ba, int32 bc, uint8 *buf)
 
592
{
 
593
int32 i;
 
594
uint32 ma, dat;
 
595
 
 
596
if ((ba | bc) & 03) {                                   /* check alignment */
 
597
        for (i = ma = 0; i < bc; i++, buf++) {          /* by bytes */
 
598
            if ((ma & VA_M_OFF) == 0) {                 /* need map? */
 
599
                if (!map_addr (ba + i, &ma) ||          /* inv or NXM? */
 
600
                    !ADDR_IS_MEM (ma)) return (bc - i);  }
 
601
            WriteB (ma, *buf);
 
602
            ma = ma + 1;  }
 
603
        }
 
604
else {  for (i = ma = 0; i < bc; i = i + 4, buf++) {    /* by longwords */
 
605
            if ((ma & VA_M_OFF) == 0) {                 /* need map? */
 
606
                if (!map_addr (ba + i, &ma) ||          /* inv or NXM? */
 
607
                    !ADDR_IS_MEM (ma)) return (bc - i);  }
 
608
            dat = (uint32) *buf++;                      /* get low 8b */
 
609
            dat = dat | (((uint32) *buf++) << 8);       /* merge next 8b */
 
610
            dat = dat | (((uint32) *buf++) << 16);      /* merge next 8b */
 
611
            dat = dat | (((uint32) *buf) << 24);        /* merge hi 8b */
 
612
            WriteL (ma, dat);                           /* store lw */
 
613
            ma = ma + 4;  }
 
614
        }
 
615
return 0;
 
616
}
 
617
 
 
618
int32 map_writeW (uint32 ba, int32 bc, uint16 *buf)
 
619
{
 
620
int32 i;
 
621
uint32 ma, dat;
 
622
 
 
623
ba = ba & ~01;
 
624
bc = bc & ~01;
 
625
if ((ba | bc) & 03) {                                   /* check alignment */
 
626
        for (i = ma = 0; i < bc; i = i + 2, buf++) {    /* by words */
 
627
            if ((ma & VA_M_OFF) == 0) {                 /* need map? */
 
628
                if (!map_addr (ba + i, &ma) ||          /* inv or NXM? */
 
629
                    !ADDR_IS_MEM (ma)) return (bc - i);  }
 
630
            WriteW (ma, *buf);
 
631
            ma = ma + 2;  }
 
632
        }
 
633
else {  for (i = ma = 0; i < bc; i = i + 4, buf++) {    /* by longwords */
 
634
            if ((ma & VA_M_OFF) == 0) {                 /* need map? */
 
635
                if (!map_addr (ba + i, &ma) ||          /* inv or NXM? */
 
636
                    !ADDR_IS_MEM (ma)) return (bc - i);  }
 
637
            dat = (uint32) *buf++;                      /* get low 16b */
 
638
            dat = dat | (((uint32) *buf) << 16);        /* merge hi 16b */
 
639
            WriteL (ma, dat);                           /* store lw */
 
640
            ma = ma + 4;  }
 
641
        }
 
642
return 0;
 
643
}
 
644
 
 
645
int32 map_writeL (uint32 ba, int32 bc, uint32 *buf)
 
646
{
 
647
int32 i;
 
648
uint32 ma;
 
649
 
 
650
ba = ba & ~03;
 
651
bc = bc & ~03;
 
652
for (i = ma = 0; i < bc; i = i + 4, buf++) {            /* by lw */
 
653
        if ((ma & VA_M_OFF) == 0) {                     /* need map? */
 
654
            if (!map_addr (ba + i, &ma) ||              /* inv or NXM? */
 
655
                !ADDR_IS_MEM (ma)) return (bc - i);  }
 
656
        WriteL (ma, *buf);
 
657
        ma = ma + 4;  }
 
658
return 0;
 
659
}
 
660
 
 
661
/* Enable/disable autoconfiguration */
 
662
 
 
663
t_stat set_autocon (UNIT *uptr, int32 val, char *cptr, void *desc)
 
664
{
 
665
if (cptr != NULL) return SCPE_ARG;
 
666
autcon_enb = val;
 
667
return auto_config (0, 0);
 
668
}
 
669
 
 
670
/* Show autoconfiguration status */
 
671
 
 
672
t_stat show_autocon (FILE *st, UNIT *uptr, int32 val, void *desc)
 
673
{
 
674
fprintf (st, "autoconfiguration ");
 
675
fprintf (st, autcon_enb? "enabled": "disabled");
 
676
return SCPE_OK;
 
677
}
 
678
 
 
679
/* Change device address */
 
680
 
 
681
t_stat set_addr (UNIT *uptr, int32 val, char *cptr, void *desc)
 
682
{
 
683
DEVICE *dptr;
 
684
DIB *dibp;
 
685
uint32 newba;
 
686
t_stat r;
 
687
 
 
688
if (cptr == NULL) return SCPE_ARG;
 
689
if ((val == 0) || (uptr == NULL)) return SCPE_IERR;
 
690
dptr = find_dev_from_unit (uptr);
 
691
if (dptr == NULL) return SCPE_IERR;
 
692
dibp = (DIB *) dptr->ctxt;
 
693
if (dibp == NULL) return SCPE_IERR;
 
694
newba = (uint32) get_uint (cptr, 16, IOPAGEBASE+IOPAGEMASK, &r);        /* get new */
 
695
if (r != SCPE_OK) return r;
 
696
if ((newba <= IOPAGEBASE) ||                            /* must be > 0 */
 
697
    (newba % ((uint32) val))) return SCPE_ARG;          /* check modulus */
 
698
dibp->ba = newba;                                       /* store */
 
699
dptr->flags = dptr->flags & ~DEV_FLTA;                  /* not floating */
 
700
autcon_enb = 0;                                         /* autoconfig off */
 
701
return SCPE_OK;
 
702
}
 
703
 
 
704
/* Show device address */
 
705
 
 
706
t_stat show_addr (FILE *st, UNIT *uptr, int32 val, void *desc)
 
707
{
 
708
DEVICE *dptr;
 
709
DIB *dibp;
 
710
 
 
711
if (uptr == NULL) return SCPE_IERR;
 
712
dptr = find_dev_from_unit (uptr);
 
713
if (dptr == NULL) return SCPE_IERR;
 
714
dibp = (DIB *) dptr->ctxt;
 
715
if ((dibp == NULL) || (dibp->ba <= IOPAGEBASE)) return SCPE_IERR;
 
716
fprintf (st, "address=%08X", dibp->ba);
 
717
if (dibp->lnt > 1)
 
718
        fprintf (st, "-%08X", dibp->ba + dibp->lnt - 1);
 
719
if (dptr->flags & DEV_FLTA) fprintf (st, "*");
 
720
return SCPE_OK;
 
721
}
 
722
 
 
723
/* Set address floating */
 
724
 
 
725
t_stat set_addr_flt (UNIT *uptr, int32 val, char *cptr, void *desc)
 
726
{
 
727
DEVICE *dptr;
 
728
 
 
729
if (cptr == NULL) return SCPE_ARG;
 
730
if ((val == 0) || (uptr == NULL)) return SCPE_IERR;
 
731
dptr = find_dev_from_unit (uptr);
 
732
if (dptr == NULL) return SCPE_IERR;
 
733
dptr->flags = dptr->flags | DEV_FLTA;                   /* floating */
 
734
return auto_config (0, 0);                              /* autoconfigure */
 
735
}
 
736
 
 
737
/* Change device vector */
 
738
 
 
739
t_stat set_vec (UNIT *uptr, int32 arg, char *cptr, void *desc)
 
740
{
 
741
DEVICE *dptr;
 
742
DIB *dibp;
 
743
uint32 newvec;
 
744
t_stat r;
 
745
 
 
746
if (cptr == NULL) return SCPE_ARG;
 
747
if (uptr == NULL) return SCPE_IERR;
 
748
dptr = find_dev_from_unit (uptr);
 
749
if (dptr == NULL) return SCPE_IERR;
 
750
dibp = (DIB *) dptr->ctxt;
 
751
if (dibp == NULL) return SCPE_IERR;
 
752
newvec = (uint32) get_uint (cptr, 16, VEC_Q + 01000, &r);
 
753
if ((r != SCPE_OK) || (newvec <= VEC_Q) ||
 
754
    ((newvec + (dibp->vnum * 4)) >= (VEC_Q + 01000)) ||
 
755
    (newvec & ((dibp->vnum > 1)? 07: 03))) return SCPE_ARG;
 
756
dibp->vec = newvec;
 
757
dptr->flags = dptr->flags & ~DEV_FLTA;                  /* not floating */
 
758
autcon_enb = 0;                                         /* autoconfig off */
 
759
return SCPE_OK;
 
760
}
 
761
 
 
762
/* Show device vector */
 
763
 
 
764
t_stat show_vec (FILE *st, UNIT *uptr, int32 arg, void *desc)
 
765
{
 
766
DEVICE *dptr;
 
767
DIB *dibp;
 
768
uint32 vec, numvec;
 
769
 
 
770
if (uptr == NULL) return SCPE_IERR;
 
771
dptr = find_dev_from_unit (uptr);
 
772
if (dptr == NULL) return SCPE_IERR;
 
773
dibp = (DIB *) dptr->ctxt;
 
774
if (dibp == NULL) return SCPE_IERR;
 
775
vec = dibp->vec;
 
776
if (arg) numvec = arg;
 
777
else numvec = dibp->vnum;
 
778
if (vec == 0) fprintf (st, "no vector");
 
779
else {  fprintf (st, "vector=%X", vec);
 
780
        if (numvec > 1) fprintf (st, "-%X", vec + (4 * (numvec - 1)));  }
 
781
return SCPE_OK;
 
782
}
 
783
 
 
784
/* Test for conflict in device addresses */
 
785
 
 
786
t_bool dev_conflict (DIB *curr)
 
787
{
 
788
uint32 i, end;
 
789
DEVICE *dptr;
 
790
DIB *dibp;
 
791
 
 
792
end = curr->ba + curr->lnt - 1;                         /* get end */
 
793
for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {     /* loop thru dev */
 
794
        dibp = (DIB *) dptr->ctxt;                      /* get DIB */
 
795
        if ((dibp == NULL) || (dibp == curr) ||
 
796
            (dptr->flags & DEV_DIS)) continue;
 
797
        if (((curr->ba >= dibp->ba) &&                  /* overlap start? */
 
798
            (curr->ba < (dibp->ba + dibp->lnt))) ||
 
799
            ((end >= dibp->ba) &&                       /* overlap end? */
 
800
            (end < (dibp->ba + dibp->lnt)))) {
 
801
                printf ("Device %s address conflict at %08X\n",
 
802
                    sim_dname (dptr), dibp->ba);
 
803
                if (sim_log) fprintf (sim_log,
 
804
                    "Device %s address conflict at %08X\n",
 
805
                    sim_dname (dptr), dibp->ba);
 
806
                return TRUE;  }  }
 
807
return FALSE;
 
808
}
 
809
 
 
810
/* Build interrupt tables */
 
811
 
 
812
t_bool build_int_vec (int32 vloc, int32 ivec, int32 (*iack)(void) )
 
813
{
 
814
int32 ilvl = vloc / 32;
 
815
int32 ibit = vloc % 32;
 
816
 
 
817
if (iack != NULL) {
 
818
        if (int_ack[ilvl][ibit] &&
 
819
           (int_ack[ilvl][ibit] != iack)) return TRUE;
 
820
         int_ack[ilvl][ibit] = iack;  }
 
821
else if (ivec != 0) {
 
822
        if (int_vec[ilvl][ibit] &&
 
823
            (int_vec[ilvl][ibit] != ivec)) return TRUE;
 
824
        int_vec[ilvl][ibit] = ivec;  }
 
825
return FALSE;
 
826
}
 
827
 
 
828
/* Build dib_tab from device list */
 
829
 
 
830
t_stat build_dib_tab (void)
 
831
{
 
832
int32 i, j, k;
 
833
DEVICE *dptr;
 
834
DIB *dibp;
 
835
 
 
836
for (i = 0; i < IPL_HLVL; i++) {                        /* clear int tables */
 
837
        for (j = 0; j < 32; j++) {
 
838
            int_vec[i][j] = 0;
 
839
            int_ack[i][j] = NULL;  }  }
 
840
for (i = j = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */
 
841
        dibp = (DIB *) dptr->ctxt;                      /* get DIB */
 
842
        if (dibp && !(dptr->flags & DEV_DIS)) {         /* defined, enabled? */
 
843
            if (dibp->vnum > VEC_DEVMAX) return SCPE_IERR;
 
844
            for (k = 0; k < dibp->vnum; k++) {          /* loop thru vec */
 
845
                if (build_int_vec (dibp->vloc + k,      /* add vector */
 
846
                    dibp->vec + (k * 4), dibp->ack[k])) {
 
847
                    printf ("Device %s interrupt slot conflict at %d\n",
 
848
                        sim_dname (dptr), dibp->vloc + k);
 
849
                    if (sim_log) fprintf (sim_log,
 
850
                        "Device %s interrupt slot conflict at %d\n",
 
851
                        sim_dname (dptr), dibp->vloc + k);
 
852
                    return SCPE_IERR;  }  }
 
853
            if (dibp->lnt != 0) {                       /* I/O addresses? */
 
854
                dib_tab[j++] = dibp;                    /* add DIB to dib_tab */
 
855
                if (j >= DIB_MAX) return SCPE_IERR;  }  /* too many? */ 
 
856
            }                                           /* end if enabled */
 
857
        }                                               /* end for */
 
858
dib_tab[j] = NULL;                                      /* end with NULL */
 
859
for (i = 0; (dibp = dib_tab[i]) != NULL; i++) {         /* test built dib_tab */
 
860
        if (dev_conflict (dibp)) return SCPE_STOP;  }   /* for conflicts */
 
861
return FALSE;
 
862
}
 
863
 
 
864
/* Show dib_tab */
 
865
 
 
866
t_stat show_iospace (FILE *st, UNIT *uptr, int32 val, void *desc)
 
867
{
 
868
int32 i, j, done = 0;
 
869
DEVICE *dptr;
 
870
DIB *dibt;
 
871
 
 
872
build_dib_tab ();                                       /* build table */
 
873
while (done == 0) {                                     /* sort ascending */
 
874
        done = 1;                                       /* assume done */
 
875
        for (i = 0; dib_tab[i + 1] != NULL; i++) {      /* check table */
 
876
            if (dib_tab[i]->ba > dib_tab[i + 1]->ba) {  /* out of order? */
 
877
                dibt = dib_tab[i];                      /* interchange */
 
878
                dib_tab[i] = dib_tab[i + 1];
 
879
                dib_tab[i + 1] = dibt;
 
880
                done = 0;  }  }                         /* not done */
 
881
        }                                               /* end while */
 
882
for (i = 0; dib_tab[i] != NULL; i++) {                  /* print table */
 
883
        for (j = 0, dptr = NULL; sim_devices[j] != NULL; j++) {
 
884
            if (((DIB*) sim_devices[j]->ctxt) == dib_tab[i]) {
 
885
                dptr = sim_devices[j];
 
886
                break;  }  }
 
887
        fprintf (st, "%08X - %08X%c\t%s\n", dib_tab[i]->ba,
 
888
                dib_tab[i]->ba + dib_tab[i]->lnt - 1,
 
889
                (dptr && (dptr->flags & DEV_FLTA))? '*': ' ',
 
890
                dptr? sim_dname (dptr): "CPU");
 
891
        }
 
892
return SCPE_OK;
 
893
}
 
894
 
 
895
/* Autoconfiguration */
 
896
 
 
897
#define AUTO_DYN        0001
 
898
#define AUTO_VEC        0002
 
899
#define AUTO_MAXC       4
 
900
#define AUTO_CSRBASE    0010
 
901
#define AUTO_VECBASE    0300
 
902
 
 
903
struct auto_con {
 
904
        uint32  amod;
 
905
        uint32  vmod;
 
906
        uint32  flags;
 
907
        uint32  num;
 
908
        uint32  fix;
 
909
        char    *dnam[AUTO_MAXC]; };
 
910
 
 
911
struct auto_con auto_tab[AUTO_LNT + 1] = {
 
912
        { 0x7, 0x7 },                                   /* DJ11 */
 
913
        { 0xf, 0x7 },                                   /* DH11 */
 
914
        { 0x7, 0x7 },                                   /* DQ11 */
 
915
        { 0x7, 0x7 },                                   /* DU11 */
 
916
        { 0x7, 0x7 },                                   /* DUP11 */
 
917
        { 0x7, 0x7 },                                   /* LK11A */
 
918
        { 0x7, 0x7 },                                   /* DMC11 */
 
919
        { 0x7, 0x7, AUTO_VEC, DZ_MUXES, 0, { "DZ" } },
 
920
 
 
921
        { 0x7, 0x7 },                                   /* KMC11 */
 
922
        { 0x7, 0x7 },                                   /* LPP11 */
 
923
        { 0x7, 0x7 },                                   /* VMV21 */
 
924
        { 0xf, 0x7 },                                   /* VMV31 */
 
925
        { 0x7, 0x7 },                                   /* DWR70 */
 
926
        { 0x7, 0x3, AUTO_DYN|AUTO_VEC, 0, IOBA_RL, { "RL", "RLB" } },
 
927
        { 0xf, 0x7 },                                   /* LPA11K */
 
928
        { 0x7, 0x7 },                                   /* KW11C */
 
929
 
 
930
        { 0x7, 0 },                                     /* reserved */
 
931
        { 0x7, 0x3, AUTO_DYN|AUTO_VEC, 0, IOBA_RX, { "RX", "RY" } },
 
932
        { 0x7, 0x3 },                                   /* DR11W */
 
933
        { 0x7, 0x3 },                                   /* DR11B */
 
934
        { 0x7, 0x7 },                                   /* DMP11 */
 
935
        { 0x7, 0x7 },                                   /* DPV11 */
 
936
        { 0x7, 0x7 },                                   /* ISB11 */
 
937
        { 0xf, 0x7 },                                   /* DMV11 */
 
938
 
 
939
        { 0x7, 0x3 },                                   /* DEUNA/DELUA */
 
940
        { 0x3, 0x3, AUTO_DYN|AUTO_VEC, 0, IOBA_RQ, { "RQ", "RQB", "RQC", "RQD" } },
 
941
        { 0x1f, 0x3 },                                  /* DMF32 */
 
942
        { 0xf, 0x7 },                                   /* KMS11 */
 
943
        { 0xf, 0x3 },                                   /* VS100 */
 
944
        { 0x3, 0x3, AUTO_DYN|AUTO_VEC, 0, IOBA_TQ, { "TQ", "TQB" } },
 
945
        { 0xf, 0x7 },                                   /* KMV11 */
 
946
        { 0xf, 0x7 },                                   /* DHU11/DHQ11 */
 
947
 
 
948
        { 0x1f, 0x7 },                                  /* DMZ32 */
 
949
        { 0x1f, 0x7 },                                  /* CP132 */
 
950
        { 0 },                                          /* padding */
 
951
};
 
952
 
 
953
t_stat auto_config (uint32 rank, uint32 nctrl)
 
954
{
 
955
uint32 csr = IOPAGEBASE + AUTO_CSRBASE;
 
956
uint32 vec = VEC_Q + AUTO_VECBASE;
 
957
struct auto_con *autp;
 
958
DEVICE *dptr;
 
959
DIB *dibp;
 
960
int32 i, j, k;
 
961
extern DEVICE *find_dev (char *ptr);
 
962
 
 
963
if (autcon_enb == 0) return SCPE_OK;                    /* enabled? */
 
964
if (rank > AUTO_LNT) return SCPE_IERR;                  /* legal rank? */
 
965
if (rank) auto_tab[rank - 1].num = nctrl;               /* update num? */
 
966
for (i = 0, autp = auto_tab; i < AUTO_LNT; i++) {       /* loop thru table */
 
967
        for (j = k = 0; (j < AUTO_MAXC) && autp->dnam[j]; j++) {
 
968
            dptr = find_dev (autp->dnam[j]);            /* find ctrl */
 
969
            if ((dptr == NULL) || (dptr->flags & DEV_DIS) ||
 
970
                !(dptr->flags & DEV_FLTA)) continue;    /* enabled, floating? */
 
971
            dibp = (DIB *) dptr->ctxt;                  /* get DIB */
 
972
            if ((k++ == 0) && autp->fix)                /* 1st & fixed? */
 
973
                dibp->ba = autp->fix;                   /* gets fixed CSR */
 
974
            else {                                      /* no, float */
 
975
                dibp->ba = csr;                         /* set CSR */
 
976
                csr = (csr + autp->amod + 1) & ~autp->amod;     /* next CSR */
 
977
                if ((autp->flags & AUTO_DYN) == 0)      /* static? */
 
978
                    csr = csr + ((autp->num - 1) * (autp->amod + 1));
 
979
                if (autp->flags & AUTO_VEC) {           /* vectors too? */
 
980
                    dibp->vec = (vec + autp->vmod) & ~autp->vmod;
 
981
                    if (autp->flags & AUTO_DYN) vec = vec + autp->vmod + 1;
 
982
                    else vec = vec + (autp->num * (autp->vmod + 1));  }
 
983
                }                                       /* end else flt */
 
984
            }                                           /* end for j */
 
985
        autp++;
 
986
        csr = (csr + autp->amod + 1) & ~autp->amod;     /* gap */
 
987
        }                                               /* end for i */
 
988
return SCPE_OK;
 
989
}