1 /* vax780_sbi.c: VAX 11/780 SBI
3 Copyright (c) 2004-2008, Robert M Supnik
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:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
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.
22 Except as contained in this notice, the name of Robert M Supnik shall not be
23 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.
26 This module contains the VAX 11/780 system-specific registers and devices.
30 31-May-2008 RMS Fixed machine_check calling sequence (found by Peter Schorn)
31 03-May-2006 RMS Fixed writes to ACCS
32 28-May-08 RMS Inlined physical memory routines
37 /* 11/780 specific IPRs */
39 /* Writeable control store */
41 #define WCSA_RW 0xFFFF /* writeable */
42 #define WCSA_ADDR 0x1FFF /* addr */
43 #define WCSA_CTR 0x6000 /* counter */
44 #define WCSA_CTR_INC 0x2000 /* increment */
45 #define WCSA_CTR_MAX 0x6000 /* max value */
46 #define WCSD_RD_VAL 0xFF /* fixed read val */
47 #define WCSD_WR 0xFFFFFFFF /* write */
48 #define MBRK_RW 0x1FFF /* microbreak */
50 /* System registers */
52 #define SBIFS_RD (0x031F0000|SBI_FAULTS) /* SBI faults */
53 #define SBIFS_WR 0x03140000
54 #define SBIFS_W1C 0x00080000
56 #define SBISC_RD 0xFFFF0000 /* SBI silo comp */
57 #define SBISC_WR 0x7FFF0000
58 #define SBISC_LOCK 0x80000000 /* lock */
60 #define SBIMT_RD 0xFFFFFF00 /* SBI maint */
61 #define SBIMT_WR 0xFFFFF900
63 #define SBIER_CRDIE 0x00008000 /* SBI error, CRD IE */
64 #define SBIER_CRD 0x00004000 /* CRD */
65 #define SBIER_RDS 0x00002000 /* RDS */
66 #define SBIER_TMO 0x00001000 /* timeout */
67 #define SBIER_STA 0x00000C00 /* timeout status (0) */
68 #define SBIER_CNF 0x00000100 /* error confirm */
69 #define SBIER_IBRDS 0x00000080
70 #define SBIER_IBTMO 0x00000040
71 #define SBIER_IBSTA 0x00000030
72 #define SBIER_IBCNF 0x00000008
73 #define SBIER_MULT 0x00000004 /* multiple errors */
74 #define SBIER_FREE 0x00000002 /* SBI free */
75 #define SBIER_RD 0x0000FDFE
76 #define SBIER_WR 0x00008000
77 #define SBIER_W1C 0x000070C0
78 #define SBIER_TMOW1C (SBIER_TMO|SBIER_STA|SBIER_CNF|SBIER_MULT)
79 #define SBIER_IBTW1C (SBIER_IBTMO|SBIER_STA|SBIER_IBCNF)
81 #define SBITMO_V_MODE 30 /* mode */
82 #define SBITMO_VIRT 0x20000000 /* physical */
84 #define SBIQC_MBZ 0xC0000007 /* MBZ */
86 /* VAX-11/780 boot device definitions */
97 uint32 nexus_req
[NEXUS_HLVL
]; /* nexus int req */
98 uint32 sbi_fs
= 0; /* SBI fault status */
99 uint32 sbi_sc
= 0; /* SBI silo comparator */
100 uint32 sbi_mt
= 0; /* SBI maintenance */
101 uint32 sbi_er
= 0; /* SBI error status */
102 uint32 sbi_tmo
= 0; /* SBI timeout addr */
104 static t_stat (*nexusR
[NEXUS_NUM
])(int32
*dat
, int32 ad
, int32 md
);
105 static t_stat (*nexusW
[NEXUS_NUM
])(int32 dat
, int32 ad
, int32 md
);
107 static struct boot_dev boot_tab
[] = {
108 { "RP", BOOT_MB
, 0 },
109 { "HK", BOOT_HK
, 0 },
110 { "RL", BOOT_RL
, 0 },
111 { "RQ", BOOT_UDA
, 1 << 24 },
112 { "TQ", BOOT_TK
, 1 << 24 },
118 extern int32 ASTLVL
, SISR
;
119 extern int32 mapen
, pme
, trpirq
;
121 extern int32 mchk_va
, mchk_ref
;
122 extern int32 crd_err
, mem_err
, hlt_pin
;
123 extern int32 tmr_int
, tti_int
, tto_int
;
124 extern jmp_buf save_env
;
126 extern int32 sim_switches
;
127 extern DEVICE
*sim_devices
[];
128 extern FILE *sim_log
;
129 extern CTAB
*sim_vm_cmd
;
131 t_stat
sbi_reset (DEVICE
*dptr
);
132 void sbi_set_tmo (int32 pa
);
133 void uba_eval_int (void);
134 t_stat
vax780_boot (int32 flag
, char *ptr
);
136 extern t_stat
vax780_fload (int flag
, char *cptr
);
137 extern int32
intexc (int32 vec
, int32 cc
, int32 ipl
, int ei
);
138 extern int32
iccs_rd (void);
139 extern int32
nicr_rd (void);
140 extern int32
icr_rd (t_bool interp
);
141 extern int32
todr_rd (void);
142 extern int32
rxcs_rd (void);
143 extern int32
rxdb_rd (void);
144 extern int32
txcs_rd (void);
145 extern void iccs_wr (int32 dat
);
146 extern void nicr_wr (int32 dat
);
147 extern void todr_wr (int32 dat
);
148 extern void rxcs_wr (int32 dat
);
149 extern void txcs_wr (int32 dat
);
150 extern void txdb_wr (int32 dat
);
151 extern void init_mbus_tab (void);
152 extern void init_ubus_tab (void);
153 extern t_stat
build_mbus_tab (DEVICE
*dptr
, DIB
*dibp
);
154 extern t_stat
build_ubus_tab (DEVICE
*dptr
, DIB
*dibp
);
156 /* SBI data structures
158 sbi_dev SBI device descriptor
160 sbi_reg SBI register list
163 UNIT sbi_unit
= { UDATA (NULL
, 0, 0) };
166 { HRDATA (NREQ14
, nexus_req
[0], 16) },
167 { HRDATA (NREQ15
, nexus_req
[1], 16) },
168 { HRDATA (NREQ16
, nexus_req
[2], 16) },
169 { HRDATA (NREQ17
, nexus_req
[3], 16) },
170 { HRDATA (WCSA
, wcs_addr
, 16) },
171 { HRDATA (WCSD
, wcs_data
, 32) },
172 { HRDATA (MBRK
, wcs_mbrk
, 13) },
173 { HRDATA (SBIFS
, sbi_fs
, 32) },
174 { HRDATA (SBISC
, sbi_sc
, 32) },
175 { HRDATA (SBIMT
, sbi_mt
, 32) },
176 { HRDATA (SBIER
, sbi_er
, 32) },
177 { HRDATA (SBITMO
, sbi_tmo
, 32) },
182 "SBI", &sbi_unit
, sbi_reg
, NULL
,
184 NULL
, NULL
, &sbi_reset
,
189 /* Special boot command, overrides regular boot */
191 CTAB vax780_cmd
[] = {
192 { "BOOT", &vax780_boot
, RU_BOOT
,
193 "bo{ot} <device>{/R5:flg} boot device\n" },
194 { "FLOAD", &vax780_fload
, 0,
195 "fl{oad} <file> {<start>} load file from console floppy\n" },
199 /* The VAX 11/780 has three sources of interrupts
201 - internal device interrupts (CPU, console, clock)
202 - nexus interupts (e.g., memory controller, MBA, UBA)
203 - external device interrupts (Unibus)
205 Internal devices vector to fixed SCB locations.
207 Nexus interrupts vector to an SCB location based on this
208 formula: SCB_NEXUS + ((IPL - 0x14) * 0x40) + (TR# * 0x4)
210 External device interrupts do not vector directly.
211 Instead, the interrupt handler for a given UBA IPL
212 reads a vector register that contains the Unibus vector
215 /* Find highest priority vectorable interrupt */
217 int32
eval_int (void)
219 int32 ipl
= PSL_GETIPL (PSL
);
222 static const int32 sw_int_mask
[IPL_SMAX
] = {
223 0xFFFE, 0xFFFC, 0xFFF8, 0xFFF0, /* 0 - 3 */
224 0xFFE0, 0xFFC0, 0xFF80, 0xFF00, /* 4 - 7 */
225 0xFE00, 0xFC00, 0xF800, 0xF000, /* 8 - B */
226 0xE000, 0xC000, 0x8000 /* C - E */
229 if (hlt_pin
) return IPL_HLTPIN
; /* hlt pin int */
230 if ((ipl
< IPL_MEMERR
) && mem_err
) return IPL_MEMERR
; /* mem err int */
231 if ((ipl
< IPL_CRDERR
) && crd_err
) return IPL_CRDERR
; /* crd err int */
232 if ((ipl
< IPL_CLKINT
) && tmr_int
) return IPL_CLKINT
; /* clock int */
233 uba_eval_int (); /* update UBA */
234 for (i
= IPL_HMAX
; i
>= IPL_HMIN
; i
--) { /* chk hwre int */
235 if (i
<= ipl
) return 0; /* at ipl? no int */
236 if (nexus_req
[i
- IPL_HMIN
]) return i
; /* req != 0? int */
238 if ((ipl
< IPL_TTINT
) && (tti_int
|| tto_int
)) /* console int */
240 if (ipl
>= IPL_SMAX
) return 0; /* ipl >= sw max? */
241 if ((t
= SISR
& sw_int_mask
[ipl
]) == 0) return 0; /* eligible req */
242 for (i
= IPL_SMAX
; i
> ipl
; i
--) { /* check swre int */
243 if ((t
>> i
) & 1) return i
; /* req != 0? int */
248 /* Return vector for highest priority hardware interrupt at IPL lvl */
250 int32
get_vector (int32 lvl
)
254 if (lvl
== IPL_MEMERR
) { /* mem error? */
258 if (lvl
== IPL_CRDERR
) { /* CRD error? */
262 if (lvl
== IPL_CLKINT
) { /* clock? */
263 tmr_int
= 0; /* clear req */
264 return SCB_INTTIM
; /* return vector */
266 if (lvl
> IPL_HMAX
) { /* error req lvl? */
267 ABORT (STOP_UIPL
); /* unknown intr */
269 if ((lvl
<= IPL_HMAX
) && (lvl
>= IPL_HMIN
)) { /* nexus? */
271 for (i
= 0; nexus_req
[l
] && (i
< NEXUS_NUM
); i
++) {
272 if ((nexus_req
[l
] >> i
) & 1) {
273 nexus_req
[l
] = nexus_req
[l
] & ~(1u << i
);
274 return SCB_NEXUS
+ (l
<< 6) + (i
<< 2); /* return vector */
278 if (lvl
== IPL_TTINT
) { /* console? */
279 if (tti_int
) { /* input? */
280 tti_int
= 0; /* clear req */
281 return SCB_TTI
; /* return vector */
283 if (tto_int
) { /* output? */
284 tto_int
= 0; /* clear req */
285 return SCB_TTO
; /* return vector */
291 /* Read 780-specific IPR's */
293 int32
ReadIPR (int32 rg
)
299 case MT_ICCS
: /* ICCS */
303 case MT_NICR
: /* NICR */
307 case MT_ICR
: /* ICR */
308 val
= icr_rd (FALSE
);
311 case MT_TODR
: /* TODR */
315 case MT_ACCS
: /* ACCS (not impl) */
319 case MT_WCSA
: /* WCSA */
320 val
= wcs_addr
& WCSA_RW
;
323 case MT_WCSD
: /* WCSD */
327 case MT_RXCS
: /* RXCS */
331 case MT_RXDB
: /* RXDB */
335 case MT_TXCS
: /* TXCS */
339 case MT_SBIFS
: /* SBIFS */
340 val
= sbi_fs
& SBIFS_RD
;
343 case MT_SBIS
: /* SBIS */
347 case MT_SBISC
: /* SBISC */
348 val
= sbi_sc
& SBISC_RD
;
351 case MT_SBIMT
: /* SBIMT */
352 val
= sbi_mt
& SBIMT_RD
;
355 case MT_SBIER
: /* SBIER */
356 val
= sbi_er
& SBIER_RD
;
359 case MT_SBITA
: /* SBITA */
363 case MT_MBRK
: /* MBRK */
364 val
= wcs_mbrk
& MBRK_RW
;
367 case MT_SID
: /* SID */
368 val
= VAX780_SID
| VAX780_ECO
| VAX780_PLANT
| VAX780_SN
;
378 /* Write 780-specific IPR's */
380 void WriteIPR (int32 rg
, int32 val
)
384 case MT_ICCS
: /* ICCS */
388 case MT_NICR
: /* NICR */
392 case MT_TODR
: /* TODR */
396 case MT_ACCS
: /* ACCS (not impl) */
399 case MT_WCSA
: /* WCSA */
400 wcs_addr
= val
& WCSA_RW
;
403 case MT_WCSD
: /* WCSD */
404 wcs_data
= val
& WCSD_WR
;
405 wcs_addr
= (wcs_addr
& ~WCSA_CTR
) |
406 ((wcs_addr
+ WCSA_CTR_INC
) & WCSA_CTR
);
407 if ((wcs_addr
& WCSA_CTR
) == WCSA_CTR_MAX
)
408 wcs_addr
= (wcs_addr
& ~WCSA_ADDR
) |
409 ((wcs_addr
+ 1) & WCSA_ADDR
);
412 case MT_RXCS
: /* RXCS */
416 case MT_TXCS
: /* TXCS */
420 case MT_TXDB
: /* TXDB */
424 case MT_SBIFS
: /* SBIFS */
425 sbi_fs
= (sbi_fs
& ~SBIFS_WR
) | (val
& SBIFS_WR
);
426 sbi_fs
= sbi_fs
& ~(val
& SBIFS_W1C
);
429 case MT_SBISC
: /* SBISC */
430 sbi_sc
= (sbi_sc
& ~(SBISC_LOCK
|SBISC_WR
)) | (val
& SBISC_WR
);
433 case MT_SBIMT
: /* SBIMT */
434 sbi_mt
= (sbi_mt
& ~SBIMT_WR
) | (val
& SBIMT_WR
);
437 case MT_SBIER
: /* SBIER */
438 sbi_er
= (sbi_er
& ~SBIER_WR
) | (val
& SBIER_WR
);
439 sbi_er
= sbi_er
& ~(val
& SBIER_W1C
);
440 if (val
& SBIER_TMO
) sbi_er
= sbi_er
& ~SBIER_TMOW1C
;
441 if (val
& SBIER_IBTMO
) sbi_er
= sbi_er
& ~SBIER_IBTW1C
;
442 if ((sbi_er
& SBIER_CRDIE
) && (sbi_er
& SBIER_CRD
))
447 case MT_SBIQC
: /* SBIQC */
448 if (val
& SBIQC_MBZ
) { RSVD_OPND_FAULT
; }
450 WriteLP (val
+ 4, 0);
453 case MT_MBRK
: /* MBRK */
454 wcs_mbrk
= val
& MBRK_RW
;
464 /* ReadReg - read register space
467 pa = physical address
473 int32
ReadReg (int32 pa
, int32 lnt
)
477 if (ADDR_IS_REG (pa
)) { /* reg space? */
478 nexus
= NEXUS_GETNEX (pa
); /* get nexus */
479 if (nexusR
[nexus
] && /* valid? */
480 (nexusR
[nexus
] (&val
, pa
, lnt
) == SCPE_OK
)) {
485 sbi_set_tmo (pa
); /* timeout */
486 MACH_CHECK (MCHK_RD_F
); /* machine check */
490 /* WriteReg - write register space
493 pa = physical address
494 val = data to write, right justified in 32b longword
500 void WriteReg (int32 pa
, int32 val
, int32 lnt
)
504 if (ADDR_IS_REG (pa
)) { /* reg space? */
505 nexus
= NEXUS_GETNEX (pa
); /* get nexus */
506 if (nexusW
[nexus
] && /* valid? */
507 (nexusW
[nexus
] (val
, pa
, lnt
) == SCPE_OK
)) {
512 sbi_set_tmo (pa
); /* timeout */
513 mem_err
= 1; /* interrupt */
518 /* Set SBI timeout - machine checks only on reads */
520 void sbi_set_tmo (int32 pa
)
522 if ((sbi_er
& SBIER_TMO
) == 0) { /* not yet set? */
523 sbi_tmo
= pa
>> 2; /* save addr */
524 if (mchk_ref
== REF_V
) sbi_tmo
|= SBITMO_VIRT
| /* virt? add mode */
525 (PSL_GETCUR (PSL
) << SBITMO_V_MODE
);
526 sbi_er
|= SBIER_TMO
; /* set tmo flag */
528 else sbi_er
|= SBIER_MULT
; /* yes, multiple */
532 /* Set SBI error confirmation - always machine checks */
534 void sbi_set_errcnf (void)
536 if (sbi_er
& SBIER_CNF
) sbi_er
|= SBIER_MULT
;
537 else sbi_er
|= SBIER_CNF
;
538 MACH_CHECK (MCHK_RD_F
);
544 Error status word format
547 <6:4> = arith trap code
551 int32
machine_check (int32 p1
, int32 opc
, int32 cc
, int32 delta
)
555 err
= (GET_TRAP (trpirq
) << 4) | (pme
<< 3) | ASTLVL
; /* error word */
556 cc
= intexc (SCB_MCHK
, cc
, 0, IE_SVE
); /* take exception */
557 acc
= ACC_MASK (KERN
); /* in kernel mode */
559 SP
= SP
- 44; /* push 11 words */
560 Write (SP
, 40, L_LONG
, WA
); /* # bytes */
561 Write (SP
+ 4, p1
, L_LONG
, WA
); /* mcheck type */
562 Write (SP
+ 8, err
, L_LONG
, WA
); /* CPU error status */
563 Write (SP
+ 12, 0, L_LONG
, WA
); /* uPC */
564 Write (SP
+ 16, mchk_va
, L_LONG
, WA
); /* VA */
565 Write (SP
+ 20, 0, L_LONG
, WA
); /* D register */
566 Write (SP
+ 24, mapen
, L_LONG
, WA
); /* TB status 1 */
567 Write (SP
+ 28, 0, L_LONG
, WA
); /* TB status 2 */
568 Write (SP
+ 32, sbi_tmo
, L_LONG
, WA
); /* SBI timeout addr */
569 Write (SP
+ 36, 0, L_LONG
, WA
); /* cache status */
570 Write (SP
+ 40, sbi_er
, L_LONG
, WA
); /* SBI error */
572 sbi_er
= sbi_er
& ~SBIER_TMOW1C
; /* clr SBIER<tmo> etc */
578 int32
con_halt (int32 code
, int32 cc
)
584 /* Special boot command - linked into SCP by initial reset
586 Syntax: BOOT <device>{/R5:val}
588 Sets up R0-R5, calls SCP boot processor with effective BOOT CPU
591 t_stat
vax780_boot (int32 flag
, char *ptr
)
594 char *slptr
, *regptr
;
595 int32 i
, r5v
, unitno
;
601 regptr
= get_glyph (ptr
, gbuf
, 0); /* get glyph */
602 if (slptr
= strchr (gbuf
, '/')) { /* found slash? */
603 regptr
= strchr (ptr
, '/'); /* locate orig */
604 *slptr
= 0; /* zero in string */
606 dptr
= find_unit (gbuf
, &uptr
); /* find device */
607 if ((dptr
== NULL
) || (uptr
== NULL
)) return SCPE_ARG
;
608 dibp
= (DIB
*) dptr
->ctxt
; /* get DIB */
609 if (dibp
== NULL
) return SCPE_ARG
;
610 unitno
= (int32
) (uptr
- dptr
->units
);
612 if ((strncmp (regptr
, "/R5:", 4) == 0) ||
613 (strncmp (regptr
, "/R5=", 4) == 0) ||
614 (strncmp (regptr
, "/r5:", 4) == 0) ||
615 (strncmp (regptr
, "/r5=", 4) == 0)) {
616 r5v
= (int32
) get_uint (regptr
+ 4, 16, LMASK
, &r
);
617 if (r
!= SCPE_OK
) return r
;
619 else if (*regptr
!= 0) return SCPE_ARG
;
620 for (i
= 0; boot_tab
[i
].name
!= NULL
; i
++) {
621 if (strcmp (dptr
->name
, boot_tab
[i
].name
) == 0) {
622 R
[0] = boot_tab
[i
].code
;
623 if (dptr
->flags
& DEV_MBUS
) {
624 R
[1] = dibp
->ba
+ TR_MBA0
;
629 R
[2] = boot_tab
[i
].let
| (dibp
->ba
& UBADDRMASK
);
634 return run_cmd (flag
, "CPU");
640 /* Bootstrap - finish up bootstrap process */
642 t_stat
cpu_boot (int32 unitno
, DEVICE
*dptr
)
646 printf ("Loading boot code from vmb.exe\n");
647 if (sim_log
) fprintf (sim_log
,
648 "Loading boot code from vmb.exe\n");
649 r
= load_cmd (0, "-O vmb.exe 200");
650 if (r
!= SCPE_OK
) return r
;
657 t_stat
sbi_reset (DEVICE
*dptr
)
667 sim_vm_cmd
= vax780_cmd
;
673 t_stat
show_nexus (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
)
675 fprintf (st
, "nexus=%d", val
);
679 /* Init nexus tables */
681 void init_nexus_tab (void)
685 for (i
= 0; i
< NEXUS_NUM
; i
++) {
692 /* Build nexus tables
695 dptr = pointer to device
696 dibp = pointer to DIB
702 t_stat
build_nexus_tab (DEVICE
*dptr
, DIB
*dibp
)
706 if ((dptr
== NULL
) || (dibp
== NULL
)) return SCPE_IERR
;
708 if (idx
>= NEXUS_NUM
) return SCPE_IERR
;
709 if ((nexusR
[idx
] && dibp
->rd
&& /* conflict? */
710 (nexusR
[idx
] != dibp
->rd
)) ||
711 (nexusW
[idx
] && dibp
->wr
&&
712 (nexusW
[idx
] != dibp
->wr
))) {
713 printf ("Nexus %s conflict at %d\n", sim_dname (dptr
), dibp
->ba
);
714 if (sim_log
) fprintf (sim_log
,
715 "Nexus %s conflict at %d\n", sim_dname (dptr
), dibp
->ba
);
718 if (dibp
->rd
) nexusR
[idx
] = dibp
->rd
; /* set rd dispatch */
719 if (dibp
->wr
) nexusW
[idx
] = dibp
->wr
; /* set wr dispatch */
723 /* Build dib_tab from device list */
725 t_stat
build_dib_tab (void)
735 for (i
= 0; (dptr
= sim_devices
[i
]) != NULL
; i
++) { /* loop thru dev */
736 dibp
= (DIB
*) dptr
->ctxt
; /* get DIB */
737 if (dibp
&& !(dptr
->flags
& DEV_DIS
)) { /* defined, enabled? */
738 if (dptr
->flags
& DEV_NEXUS
) { /* Nexus? */
739 if (r
= build_nexus_tab (dptr
, dibp
)) /* add to dispatch table */
742 else if (dptr
->flags
& DEV_MBUS
) { /* Massbus? */
743 if (r
= build_mbus_tab (dptr
, dibp
))
746 else { /* no, Unibus device */
747 if (r
= build_ubus_tab (dptr
, dibp
)) /* add to dispatch tab */
750 } /* end if enabled */