1 /* hp2100_pif.c: HP 12620A/12936A Privileged Interrupt Fence simulator
2
3 Copyright (c) 2008-2020, J. David Bryan
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 THE AUTHOR 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 the author 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 the author.
25
26 PIF 12620A/12936A Privileged Interrupt Fence
27
28 02-Dec-20 JDB RESET no longer presets the interface
29 11-Jun-18 JDB Revised I/O model
30 15-Mar-17 JDB Trace flags are now global
31 11-Mar-17 JDB Revised the trace outputs
32 17-Jan-17 JDB Changed "hp_---sc" and "hp_---dev" to "hp_---_dib"
33 13-May-16 JDB Modified for revised SCP API function parameter types
34 10-Feb-12 JDB Deprecated DEVNO in favor of SC
35 28-Mar-11 JDB Tidied up signal handling
36 26-Oct-10 JDB Changed I/O signal handler for revised signal model
37 26-Jun-08 JDB Rewrote device I/O to model backplane signals
38 18-Jun-08 JDB Created PIF device
39
40 References:
41 - 12620A Breadboard Interface Kit Operating and Service Manual
42 (12620-90001, May 1978)
43 - 12936A Privileged Interrupt Fence Accessory Installation and Service Manual
44 (12936-90001, March 1974)
45
46
47 The Privileged Interupt Fence (PIF) was used in DOS and RTE systems to
48 provide privileged interrupt capability. In non-privileged systems, DOS and
49 RTE vectored all interrupts though the Central Interrupt Control (CIC)
50 routine. Within CIC, the interrupt system was turned off, the interrupt was
51 categorized, the associated driver was identified and mapped into logical
52 memory (if necessary), and the driver entered to handle the device service.
53 When the driver exited, the interrupt system was turned on before returning
54 to the point of interruption in the user's program. In addition, the DOS and
55 RTE operating systems themselves executed with the interrupt system off, as
56 they were not reentrant.
57
58 This process proved too lengthy for certain devices, which would lose
59 interrupts or be forced to limit I/O speeds as a result. To allow faster
60 service, a driver could be written as a "privileged" driver and generated
61 into a privileged system. A privileged system operated with the interrupt
62 system on when handling unprivileged device interrupts or executing within
63 the operating system. The PIF card was installed in the I/O backplane to
64 separate privileged from unprivileged devices by controlling the interrupt
65 priority chain signal (PRL) to lower-priority devices. The privileged cards
66 located below the fence were allowed to interrupt the service routines of the
67 unprivileged cards that were located above the fence.
68
69 When an unprivileged device interrupted, CIC would be entered as usual, and
70 the interrupt system would be turned off. However, after the system state
71 was saved, the PIF would be configured to break the priority chain (deny
72 PRL), so that subsequent interrupts from all unprivileged devices would be
73 deferred. Then the interrupt system would be turned on before normal CIC
74 processing continued. Interrupts from additional unprivileged devices would
75 be held off by the PIF until the driver completed and CIC returned, just as
76 in a non-privileged system.
77
78 However, if a privileged device interrupted, the interrupt would be allowed,
79 because the interrupt system was on, and the priority chain was intact for
80 the devices below the fence. A privileged device bypassed CIC and entered
81 the associated device driver directly, and this would occur even if an
82 unprivileged device driver or the operating system itself were executing.
83 This provided very fast interrupt service time.
84
85 HP produced two PIF cards: the 12936A Privileged Interrupt Fence Accessory
86 for DOS, and the 12620A Breadboard Interface for RTE. They behaved quite
87 differently and were not interchangeable.
88
89 The 12620A had the standard control and flag circuitry. It behaved as most
90 cards did; setting control and flag together lowered PRL and generated an
91 interrupt. The control and flag flip-flops were set and cleared with STC/CLC
92 and STF/CLF instructions. The SFS/SFC instructions could be used to test the
93 flag state.
94
95 The 12936A had a unique behavior. Setting either control or flag lowered
96 PRL. An interrupt occurred when flag was set and control was clear. The
97 control flip-flop was controlled with STC/CLC. The flag flip-flop was set
98 with OTA/B and cleared with CLF. SFC and SFS were not implemented and never
99 skipped.
100 */
101
102
103
104 #include "hp2100_defs.h"
105 #include "hp2100_io.h"
106
107
108
109 /* Device flags */
110
111 #define DEV_V_12936 (DEV_V_UF + 0) /* 12936A card */
112
113 #define DEV_12936 (1 << DEV_V_12936)
114
115
116 /* Interface state */
117
118 typedef struct {
119 FLIP_FLOP control; /* control flip-flop */
120 FLIP_FLOP flag; /* flag flip-flop */
121 FLIP_FLOP flag_buffer; /* flag buffer flip-flop */
122 } CARD_STATE;
123
124 static CARD_STATE pif; /* per-card state */
125
126
127 /* Interface local SCP support routines */
128
129 static IO_INTERFACE pif_interface;
130
131
132 /* Interface local SCP support routines */
133
134 static t_stat pif_reset (DEVICE *dptr);
135 static t_stat pif_set_card (UNIT *uptr, int32 val, char *cptr, void *desc);
136 static t_stat pif_show_card (FILE *st, UNIT *uptr, int32 val, void *desc);
137
138
139 /* Interface SCP data structures */
140
141
142 /* Device information block */
143
144 static DIB pif_dib = {
145 &pif_interface, /* the device's I/O interface function pointer */
146 NULL, /* the power state function pointer */
147 PIF, /* the device's select code (02-77) */
148 0, /* the card index */
149 "12620A/12936A Privileged Interrupt Fence", /* the card description */
150 NULL /* the ROM description */
151 };
152
153
154 /* Unit list.
155
156
157 Implementation notes:
158
159 1. The SIMH developer's manual says that a device's unit list may be NULL.
160 However, if this is done, the register state cannot be examined or
161 altered via SCP. To work around this problem, we define a dummy unit
162 that is not used otherwise.
163 */
164
165 static UNIT pif_unit [] = {
166 { UDATA (NULL, 0, 0) }
167 };
168
169
170 /* Register list */
171
172 static REG pif_reg [] = {
173 /* Macro Name Location Offset */
174 /* ------ ------ ------------------- ------ */
175 { FLDATA (CTL, pif.control, 0) },
176 { FLDATA (FLG, pif.flag, 0) },
177 { FLDATA (FBF, pif.flag_buffer, 0) },
178
179 DIB_REGS (pif_dib),
180
181 { NULL }
182 };
183
184
185 /* Modifier list */
186
187 static MTAB pif_mod [] = {
188 /* Entry Flags Value Print String Match String Validation Display Descriptor */
189 /* ------------------- ----- ------------ ------------ -------------- -------------- ----------------- */
190 { MTAB_XDV, 0, NULL, "12620A", &pif_set_card, NULL, NULL },
191 { MTAB_XDV, 1, NULL, "12936A", &pif_set_card, NULL, NULL },
192 { MTAB_XDV, 0, "TYPE", NULL, NULL, &pif_show_card, NULL },
193
194 { MTAB_XDV, 1u, "SC", "SC", &hp_set_dib, &hp_show_dib, (void *) &pif_dib },
195 { MTAB_XDV | MTAB_NMO, ~1u, "DEVNO", "DEVNO", &hp_set_dib, &hp_show_dib, (void *) &pif_dib },
196 { 0 }
197 };
198
199
200 /* Debugging trace list */
201
202 static DEBTAB pif_deb [] = {
203 { "CMD", TRACE_CMD }, /* interface commands */
204 { "IOBUS", TRACE_IOBUS }, /* interface I/O bus signals and data words */
205 { NULL, 0 }
206 };
207
208
209 /* Device descriptor */
210
211 DEVICE pif_dev = {
212 "PIF", /* device name */
213 pif_unit, /* unit array */
214 pif_reg, /* register array */
215 pif_mod, /* modifier array */
216 1, /* number of units */
217 10, /* address radix */
218 31, /* address width */
219 1, /* address increment */
220 8, /* data radix */
221 8, /* data width */
222 NULL, /* examine routine */
223 NULL, /* deposit routine */
224 &pif_reset, /* reset routine */
225 NULL, /* boot routine */
226 NULL, /* attach routine */
227 NULL, /* detach routine */
228 &pif_dib, /* device information block */
229 DEV_DISABLE | DEV_DEBUG, /* device flags */
230 0, /* debug control flags */
231 pif_deb, /* debug flag name table */
232 NULL, /* memory size change routine */
233 NULL }; /* logical device name */
234
235
236
237 /* Interface local SCP support routines */
238
239
240
241 /* Privileged interrupt fence interface.
242
243 Operation of the 12620A and the 12936A is different. The I/O responses of
244 the two cards are summarized below:
245
246 Signal 12620A Action 12936A Action
247 ------ -------------------- --------------------
248 POPIO Set FBF, FLG Clear FBF, FLG
249 CRS Clear CTL Clear CTL
250 CLC Clear CTL Clear CTL
251 STC Set CTL Set CTL
252 CLF Clear FBF, FLG Clear FBF, FLG
253 STF Set FBF, FLG none
254 SFC Skip if FLG clear none
255 SFS Skip if FLG set none
256 IOI none none
257 IOO none Set FBF, FLG
258 PRL ~(CTL * FLG) ~(CTL + FLG)
259 IRQ CTL * FLG * FBF ~CTL * FLG * FBF
260 IAK Clear FBF Clear FBF
261 SRQ Follows FLG Not driven
262
263 Note that PRL and IRQ are non-standard for the 12936A.
264 */
265
pif_interface(const DIB * dibptr,INBOUND_SET inbound_signals,HP_WORD inbound_value)266 static SIGNALS_VALUE pif_interface (const DIB *dibptr, INBOUND_SET inbound_signals, HP_WORD inbound_value)
267 {
268 const t_bool is_rte_pif = not (pif_dev.flags & DEV_12936); /* TRUE if 12620A card */
269 INBOUND_SIGNAL signal;
270 INBOUND_SET working_set = inbound_signals;
271 SIGNALS_VALUE outbound = { ioNONE, 0 };
272 t_bool irq_enabled = FALSE;
273
274 while (working_set) {
275 signal = IONEXTSIG (working_set); /* isolate the next signal */
276
277 switch (signal) { /* dispatch I/O signal */
278
279 case ioCLF: /* clear flag flip-flop */
280 pif.flag_buffer = CLEAR; /* clear flag buffer and flag */
281 pif.flag = CLEAR;
282 break;
283
284
285 case ioSTF: /* set flag flip-flop */
286 if (is_rte_pif) /* RTE PIF? */
287 pif.flag_buffer = SET; /* set flag buffer */
288 break;
289
290
291 case ioENF: /* enable flag */
292 if (pif.flag_buffer == SET) /* if the flag buffer flip-flop is set */
293 pif.flag = SET; /* then set the flag flip-flop */
294 break;
295
296
297 case ioSFC: /* skip if flag is clear */
298 if (is_rte_pif && pif.flag == CLEAR) /* only the 12620A card */
299 outbound.signals |= ioSKF; /* responds to SFC */
300 break;
301
302
303 case ioSFS: /* skip if flag is set */
304 if (is_rte_pif && pif.flag == SET) /* only the 12620A card */
305 outbound.signals |= ioSKF; /* responds to SFS */
306 break;
307
308
309 case ioIOO: /* I/O data output */
310 if (not is_rte_pif) { /* DOS PIF? */
311 pif.flag_buffer = SET; /* set flag buffer */
312 working_set |= ioENF | ioSIR; /* set ENF and SIR (not normally done for IOO) */
313 }
314 break;
315
316
317 case ioPOPIO: /* power-on preset to I/O */
318 if (is_rte_pif)
319 pif.flag_buffer = SET;
320
321 else {
322 pif.flag_buffer = CLEAR;
323 pif.flag = CLEAR;
324 }
325
326 tprintf (pif_dev, TRACE_CMD, "Power-on reset\n");
327 break;
328
329
330 case ioCRS: /* control reset */
331 pif.control = CLEAR; /* clear control */
332 tprintf (pif_dev, TRACE_CMD, "Control reset\n");
333 break;
334
335
336 case ioCLC: /* clear control flip-flop */
337 pif.control = CLEAR; /* clear control */
338 break;
339
340
341 case ioSTC: /* set control flip-flop */
342 pif.control = SET; /* set control */
343 break;
344
345
346 case ioSIR: /* set interrupt request */
347 if (is_rte_pif & pif.control & pif.flag /* if control and flag are set (12620A) */
348 || not is_rte_pif & (pif.control | pif.flag)) /* or control or flag are clear (12936A) */
349 outbound.signals |= cnVALID; /* then deny PRL */
350 else /* otherwise */
351 outbound.signals |= cnPRL | cnVALID; /* conditionally assert PRL */
352
353 if (~(is_rte_pif ^ pif.control) /* if control is set (12620A) or clear (12936A) */
354 & pif.flag & pif.flag_buffer) /* and flag and flag buffer are set */
355 outbound.signals |= cnIRQ; /* then conditionally assert IRQ */
356
357 if (is_rte_pif && pif.flag == SET) /* if 12620A and flag is set */
358 outbound.signals |= ioSRQ; /* then assert SRQ */
359
360 tprintf (pif_dev, TRACE_CMD, "Fence %s%s lower-priority interrupts\n",
361 (outbound.signals & cnIRQ ? "requests an interrupt and " : ""),
362 (outbound.signals & cnPRL ? "allows" : "inhibits"));
363 break;
364
365
366 case ioIAK: /* interrupt acknowledge */
367 pif.flag_buffer = CLEAR;
368 break;
369
370
371 case ioIEN: /* interrupt enable */
372 irq_enabled = TRUE;
373 break;
374
375
376 case ioPRH: /* priority high */
377 if (irq_enabled && outbound.signals & cnIRQ) /* if IRQ is enabled and conditionally asserted */
378 outbound.signals |= ioIRQ | ioFLG; /* then assert IRQ and FLG */
379
380 if (not irq_enabled || outbound.signals & cnPRL) /* if IRQ is disabled or PRL is conditionally asserted */
381 outbound.signals |= ioPRL; /* then assert it unconditionally */
382 break;
383
384
385 case ioIOI: /* not used by this interface */
386 case ioEDT: /* not used by this interface */
387 case ioPON: /* not used by this interface */
388 break;
389 }
390
391 IOCLEARSIG (working_set, signal); /* remove the current signal from the set */
392 }
393
394 return outbound; /* return the outbound signals and value */
395 }
396
397
398 /* Simulator reset routine */
399
pif_reset(DEVICE * dptr)400 static t_stat pif_reset (DEVICE *dptr)
401 {
402 return SCPE_OK;
403 }
404
405
406
407 /* Privileged interrupt fence local utility routines */
408
409
410 /* Set card type.
411
412 val == 0 --> set to 12936A (DOS PIF)
413 val == 1 --> set to 12620A (RTE PIF)
414 */
415
pif_set_card(UNIT * uptr,int32 val,char * cptr,void * desc)416 static t_stat pif_set_card (UNIT *uptr, int32 val, char *cptr, void *desc)
417 {
418 if ((val < 0) || (val > 1) || (cptr != NULL)) /* sanity check */
419 return SCPE_ARG; /* bad argument */
420
421 if (val) /* DOS PIF selected? */
422 pif_dev.flags = pif_dev.flags | DEV_12936; /* set to 12936A */
423 else /* RTE PIF selected */
424 pif_dev.flags = pif_dev.flags & ~DEV_12936; /* set to 12620A */
425
426 return SCPE_OK;
427 }
428
429
430 /* Show card type */
431
pif_show_card(FILE * st,UNIT * uptr,int32 val,void * desc)432 static t_stat pif_show_card (FILE *st, UNIT *uptr, int32 val, void *desc)
433 {
434 if (pif_dev.flags & DEV_12936)
435 fputs ("12936A", st);
436 else
437 fputs ("12620A", st);
438
439 return SCPE_OK;
440 }
441