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