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