1 /*************************************************************************
2  *                                                                       *
3  * $Id: s100_ss1.c 1997 2008-07-18 05:29:52Z hharte $                    *
4  *                                                                       *
5  * Copyright (c) 2007-2008 Howard M. Harte.                              *
6  * http://www.hartetec.com                                               *
7  *                                                                       *
8  * Permission is hereby granted, free of charge, to any person obtaining *
9  * a copy of this software and associated documentation files (the       *
10  * "Software"), to deal in the Software without restriction, including   *
11  * without limitation the rights to use, copy, modify, merge, publish,   *
12  * distribute, sublicense, and/or sell copies of the Software, and to    *
13  * permit persons to whom the Software is furnished to do so, subject to *
14  * the following conditions:                                             *
15  *                                                                       *
16  * The above copyright notice and this permission notice shall be        *
17  * included in all copies or substantial portions of the Software.       *
18  *                                                                       *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       *
20  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    *
21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND                 *
22  * NONINFRINGEMENT. IN NO EVENT SHALL HOWARD M. HARTE BE LIABLE FOR ANY  *
23  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  *
24  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     *
25  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                *
26  *                                                                       *
27  * Except as contained in this notice, the name of Howard M. Harte shall *
28  * not be used in advertising or otherwise to promote the sale, use or   *
29  * other dealings in this Software without prior written authorization   *
30  * Howard M. Harte.                                                      *
31  *                                                                       *
32  * SIMH Interface based on altairz80_hdsk.c, by Peter Schorn.            *
33  *                                                                       *
34  * Module Description:                                                   *
35  *     CompuPro System Support 1 module for SIMH.                        *
36  * Note this does not include the Boot ROM on the System Support 1 Card  *
37  *                                                                       *
38  * Environment:                                                          *
39  *     User mode only                                                    *
40  *                                                                       *
41  *************************************************************************/
42 
43 /*#define DBG_MSG */
44 
45 #include "altairz80_defs.h"
46 
47 #if defined (_WIN32)
48 #include <windows.h>
49 #endif
50 
51 #include <time.h>
52 
53 #ifdef DBG_MSG
54 #define DBG_PRINT(args) printf args
55 #else
56 #define DBG_PRINT(args)
57 #endif
58 
59 /* Debug flags */
60 #define ERROR_MSG   (1 << 0)
61 #define TRACE_MSG   (1 << 1)
62 #define PIC_MSG     (1 << 2)
63 #define TC_MSG      (1 << 3)
64 #define RTC_MSG     (1 << 4)
65 #define MATH_MSG    (1 << 5)
66 #define UART_MSG    (1 << 6)
67 #define IRQ_MSG     (1 << 7)
68 
69 #define SS1_MAX_TIMERS    3
70 
71 typedef struct {
72     PNP_INFO    pnp;    /* Plug and Play */
73 } SS1_INFO;
74 
75 static SS1_INFO ss1_info_data = { { 0x0, 0, 0x50, 16 } };
76 
77 extern t_stat set_iobase(UNIT *uptr, int32 val, char *cptr, void *desc);
78 extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc);
79 extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,
80         int32 (*routine)(const int32, const int32, const int32), uint8 unmap);
81 extern uint32 PCX;
82 
83 static t_stat ss1_reset(DEVICE *ss1_dev);
84 static t_stat ss1_svc (UNIT *uptr);
85 static uint8 SS1_Read(const uint32 Addr);
86 static uint8 SS1_Write(const uint32 Addr, uint8 cData);
87 static int32 ss1dev(const int32 port, const int32 io, const int32 data);
88 void raise_ss1_interrupt(uint8 isr_index);
89 
90 /* SS1 Interrupt Controller notes:
91  *
92  * Msster 8259:
93  * IRQ0 = VI0
94  * IRQ1 = VI1       - DISK3 Interrupt
95  * IRQ2 = VI2       - IF3 Rx Interrupt
96  * IRQ3 = VI3       - IF3 Tx Interrupt
97  * IRQ4 = VI4       - DISK1A
98  * IRQ5 = VI5       - ?
99  * IRQ6 = VI6
100  * <Cascade>
101  *
102  * Slave 8259:
103  * IRQ0 = VI7           0x48
104  * IRQ1 = Timer0        0x49
105  * IRQ2 = Timer1        0x4A
106  * IRQ3 = Timer2        0x4B
107  * IRQ4 = 9511 SVRQ     0x4C
108  * IRQ5 = 9511 END      0x4D
109  * IRQ6 = 2651 TxRDY    0x4E
110  * IRQ7 = 2651 RxRDY    0x4F
111  */
112 #define MASTER_PIC  0
113 #define SLAVE_PIC   1
114 
115 #define VI0_IRQ_OFFSET      0
116 #define VI1_IRQ_OFFSET      1
117 #define VI2_IRQ_OFFSET      2
118 #define VI3_IRQ_OFFSET      3
119 #define VI4_IRQ_OFFSET      4
120 #define VI5_IRQ_OFFSET      5
121 #define VI6_IRQ_OFFSET      6
122 #define VI7_IRQ_OFFSET      0
123 #define TC0_IRQ_OFFSET      1
124 #define TC1_IRQ_OFFSET      2
125 #define TC2_IRQ_OFFSET      3
126 #define MSVRQ_IRQ_OFFSET    4
127 #define MEND_IRQ_OFFSET     5
128 #define TXRDY_IRQ_OFFSET    6
129 #define RXRDY_IRQ_OFFSET    7
130 
131 typedef struct {
132     uint8 config_cnt;
133     uint8 ICW[5];
134     uint8 IMR;      /* OCW1 = IMR */
135     uint8 OCW2;
136     uint8 OCW3;
137     uint8 IRR;
138     uint8 ISR;
139 } I8259_REGS;
140 
141 I8259_REGS ss1_pic[2];
142 
143 /* SS1 Timer notes:
144  *
145  * T0, T1, T2 inputs connected to 2MHz clock on SS1
146  * T0 IRQ connected to Slave IRQ 1
147  * T1 IRQ connected to Slave IRQ 2
148  * T2 IRQ connected to Slave IRQ 3
149  */
150 typedef struct {
151     uint16 count[3];    /* Current counter value for each timer. */
152     uint8 mode[3];      /* Current mode of each timer. */
153     uint8 bcd[3];
154     uint8 rl[3];
155     uint8 CTL;
156 } I8253_REGS;
157 
158 I8253_REGS ss1_tc[1];
159 
160 #define I8253_CTL_SC_MASK   0xC0
161 #define I8253_CTL_RL_MASK   0x30
162 #define I8253_CTL_MODE_MASK 0x0E
163 #define I8253_CTL_BCD       0x01
164 
165 typedef struct {
166     uint8 digit_sel;
167     uint8 flags;
168 } RTC_REGS;
169 
170 RTC_REGS ss1_rtc[1];
171 
172 static UNIT ss1_unit[] = {
173     { UDATA (&ss1_svc, UNIT_FIX | UNIT_DISABLE | UNIT_ROABLE, 0) },
174     { UDATA (&ss1_svc, UNIT_FIX | UNIT_DISABLE | UNIT_ROABLE, 0) },
175     { UDATA (&ss1_svc, UNIT_FIX | UNIT_DISABLE | UNIT_ROABLE, 0) },
176     { UDATA (&ss1_svc, UNIT_FIX | UNIT_DISABLE | UNIT_ROABLE, 0) }
177 };
178 
179 static REG ss1_reg[] = {
180     { HRDATA (MPIC_IMR,   ss1_pic[MASTER_PIC].IMR,            8), },
181     { HRDATA (MPIC_IRR,   ss1_pic[MASTER_PIC].IRR,            8), },
182     { HRDATA (MPIC_ISR,   ss1_pic[MASTER_PIC].ISR,            8), },
183     { HRDATA (MPIC_OCW2,  ss1_pic[MASTER_PIC].OCW2,           8), },
184     { HRDATA (MPIC_OCW3,  ss1_pic[MASTER_PIC].OCW3,           8), },
185 
186     { HRDATA (SPIC_IMR,   ss1_pic[SLAVE_PIC].IMR,             8), },
187     { HRDATA (SPIC_IRR,   ss1_pic[SLAVE_PIC].IRR,             8), },
188     { HRDATA (SPIC_ISR,   ss1_pic[SLAVE_PIC].ISR,             8), },
189     { HRDATA (SPIC_OCW2,  ss1_pic[SLAVE_PIC].OCW2,            8), },
190     { HRDATA (SPIC_OCW3,  ss1_pic[SLAVE_PIC].OCW3,            8), },
191 
192     { HRDATA (T0_MODE,    ss1_tc[0].mode,                     3), },
193     { HRDATA (T0_COUNT,   ss1_tc[0].count,                    16), },
194     { HRDATA (T1_MODE,    ss1_tc[1].mode,                     3), },
195     { HRDATA (T1_COUNT,   ss1_tc[1].count,                    16), },
196     { HRDATA (T2_MODE,    ss1_tc[2].mode,                     3), },
197     { HRDATA (T2_COUNT,   ss1_tc[2].count,                    16), },
198 
199     { HRDATA (RTC_DIGIT,  ss1_rtc[0].digit_sel,               4), },
200     { HRDATA (RTC_FLAGS,  ss1_rtc[0].flags,                   4), },
201 
202     { NULL }
203 };
204 
205 static MTAB ss1_mod[] = {
206     { MTAB_XTD|MTAB_VDV,    0,              "IOBASE",   "IOBASE",   &set_iobase, &show_iobase, NULL },
207     { 0 }
208 };
209 
210 /* Debug Flags */
211 static DEBTAB ss1_dt[] = {
212     { "ERROR",  ERROR_MSG },
213     { "TRACE",  TRACE_MSG },
214     { "PIC",    PIC_MSG },
215     { "TC",     TC_MSG },
216     { "RTC",    RTC_MSG },
217     { "MATH",   MATH_MSG },
218     { "UART",   UART_MSG },
219     { "IRQ",    IRQ_MSG },
220     { NULL,     0 }
221 };
222 
223 DEVICE ss1_dev = {
224     "SS1", ss1_unit, ss1_reg, ss1_mod,
225     SS1_MAX_TIMERS, 10, 31, 1, SS1_MAX_TIMERS, SS1_MAX_TIMERS,
226     NULL, NULL, &ss1_reset,
227     NULL, NULL, NULL,
228     &ss1_info_data, (DEV_DISABLE | DEV_DIS | DEV_DEBUG), ERROR_MSG,
229     ss1_dt, NULL, "Compupro System Support 1 SS1"
230 };
231 
232 /* Reset routine */
ss1_reset(DEVICE * dptr)233 static t_stat ss1_reset(DEVICE *dptr)
234 {
235     PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt;
236 
237     if(dptr->flags & DEV_DIS) { /* Disconnect I/O Ports */
238         sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &ss1dev, TRUE);
239     } else {
240         /* Connect SS1 at base address */
241         if(sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &ss1dev, FALSE) != 0) {
242             printf("%s: error mapping I/O resource at 0x%04x\n", __FUNCTION__, pnp->io_base);
243             return SCPE_ARG;
244         } else {
245             DBG_PRINT(("SS1: Mapped I/O resource at 0x%04x, len=%d\n", pnp->io_base, pnp->io_size));
246             ss1_unit[0].u4 = 0;
247             ss1_unit[1].u4 = 1;
248             ss1_unit[2].u4 = 2;
249             ss1_unit[3].u4 = 3;
250             ss1_pic[MASTER_PIC].IMR = 0xFF;
251             ss1_pic[SLAVE_PIC].IMR = 0xFF;
252         }
253     }
254     return SCPE_OK;
255 }
256 
ss1dev(const int32 port,const int32 io,const int32 data)257 static int32 ss1dev(const int32 port, const int32 io, const int32 data)
258 {
259     DBG_PRINT(("SS1: IO %s, Port %02x\n", io ? "WR" : "RD", port));
260     if(io) {
261         SS1_Write(port, data);
262         return 0;
263     } else {
264         return(SS1_Read(port));
265     }
266 }
267 
268 #define SS1_M8259_L     0x00
269 #define SS1_M8259_H     0x01
270 #define SS1_S8259_L     0x02
271 #define SS1_S8259_H     0x03
272 #define SS1_8253_TC0    0x04
273 #define SS1_8253_TC1    0x05
274 #define SS1_8253_TC2    0x06
275 #define SS1_8253_CTL    0x07
276 #define SS1_9511A_DATA  0x08
277 #define SS1_9511A_CMD   0x09
278 #define SS1_RTC_CMD     0x0A
279 #define SS1_RTC_DATA    0x0B
280 #define SS1_UART_DATA   0x0C
281 #define SS1_UART_STAT   0x0D
282 #define SS1_UART_MODE   0x0E
283 #define SS1_UART_CMD    0x0F
284 
285 extern int32 sio0d(const int32 port, const int32 io, const int32 data);
286 extern int32 sio0s(const int32 port, const int32 io, const int32 data);
287 
288 static struct tm currentTime;
289 static int32 toBCD(const int32 x);
290 
SS1_Read(const uint32 Addr)291 static uint8 SS1_Read(const uint32 Addr)
292 {
293     uint8 cData = 0x00;
294 
295     uint8 sel_pic = MASTER_PIC;
296     uint8 sel_tc = 0;
297     time_t now;
298 
299     switch(Addr & 0x0F) {
300         case SS1_S8259_L:
301             sel_pic = SLAVE_PIC;
302         case SS1_M8259_L:
303             if((ss1_pic[sel_pic].OCW3 & 0x03) == 0x03) {
304                 cData = ss1_pic[sel_pic].ISR;
305                 sim_debug(PIC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
306                           " RD: %s PIC ISR=0x%02x.\n", PCX, (sel_pic ? "Slave " : "Master"), cData);
307             } else if((ss1_pic[sel_pic].OCW3 & 0x03) == 0x02) {
308                 cData = ss1_pic[sel_pic].IRR;
309                 sim_debug(PIC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
310                           " RD: %s PIC IRR=0x%02x.\n", PCX, (sel_pic ? "Slave " : "Master"), cData);
311             } else {
312                 cData = 0xFF;
313             }
314             break;
315         case SS1_S8259_H:
316             sel_pic = SLAVE_PIC;
317         case SS1_M8259_H:
318             cData = ss1_pic[sel_pic].IMR;
319             sim_debug(PIC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
320                       " RD: %s PIC IMR=0x%02x.\n", PCX, (sel_pic ? "Slave " : "Master"), cData);
321             ss1_pic[sel_pic].IMR = cData;
322             break;
323         case SS1_8253_CTL:
324             cData = ss1_tc[0].CTL;
325             sim_debug(TC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
326                       " RD: TC CTL=0x%02x.\n", PCX, cData);
327             break;
328         case SS1_8253_TC2:
329             sel_tc++;
330         case SS1_8253_TC1:
331             sel_tc++;
332         case SS1_8253_TC0:
333             sim_debug(TC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
334                       " RD: TC [%d]=0x%02x.\n", PCX, sel_tc, cData);
335             break;
336         case SS1_9511A_DATA:
337         case SS1_9511A_CMD:
338             sim_debug(MATH_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
339                       " RD: Math Coprocessor not Implemented.\n", PCX);
340             break;
341         case SS1_RTC_CMD:
342             cData = 0xFF;
343             sim_debug(RTC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
344                       " RD: RTC  Cmd=0x%02x.\n", PCX, cData);
345             break;
346         case SS1_RTC_DATA:
347                 time(&now);
348                 currentTime = *localtime(&now);
349 
350             switch(ss1_rtc[0].digit_sel) {
351             case 0:
352                 cData = toBCD(currentTime.tm_sec) & 0xF;
353                 break;
354             case 1:
355                 cData = (toBCD(currentTime.tm_sec) >> 4) & 0xF;
356                 break;
357             case 2:
358                 cData = toBCD(currentTime.tm_min) & 0xF;
359                 break;
360             case 3:
361                 cData = (toBCD(currentTime.tm_min) >> 4) & 0xF;
362                 break;
363             case 4:
364                 cData = toBCD(currentTime.tm_hour) & 0xF;
365                 break;
366             case 5:
367                 cData = (toBCD(currentTime.tm_hour) >> 4) & 0x3;
368                 cData |= 0x08;  /* Set to 24-hour format */
369                 break;
370             case 6:
371                 cData = toBCD(currentTime.tm_wday) & 0xF;
372                 break;
373             case 7:
374                 cData = toBCD(currentTime.tm_mday) & 0xF;
375                 break;
376             case 8:
377                 cData = (toBCD(currentTime.tm_mday) >> 4) & 0xF;
378                 break;
379             case 9:
380                 cData = toBCD(currentTime.tm_mon+1) & 0xF;
381                 break;
382             case 10:
383                 cData = (toBCD(currentTime.tm_mon+1) >> 4) & 0xF;
384                 break;
385             case 11:
386                 cData = toBCD(currentTime.tm_year-22) & 0xF;
387                 break;
388             case 12:
389                 cData = (toBCD(currentTime.tm_year-22) >> 4) & 0xF;
390                 break;
391             default:
392                 cData = 0;
393                 break;
394             }
395             sim_debug(RTC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
396                       " RD: RTC Data[%x]=0x%02x.\n", PCX, ss1_rtc[0].digit_sel, cData);
397 
398             break;
399         case SS1_UART_DATA:
400             cData = sio0d(Addr, 0, 0);
401             sim_debug(UART_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
402                       " RD: UART Data=0x%02x.\n", PCX, cData);
403             break;
404         case SS1_UART_STAT:
405             cData = sio0s(Addr, 0, 0);
406             sim_debug(UART_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
407                       " RD: UART Stat=0x%02x.\n", PCX, cData);
408             break;
409         case SS1_UART_MODE:
410         case SS1_UART_CMD:
411             sim_debug(UART_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
412                       " RD: UART not Implemented.\n", PCX);
413             break;
414     }
415 
416     return (cData);
417 
418 }
419 
420 uint16 newcount = 0;
421 uint8 bc;
422 
423 static void generate_ss1_interrupt(void);
424 
SS1_Write(const uint32 Addr,uint8 cData)425 static uint8 SS1_Write(const uint32 Addr, uint8 cData)
426 {
427 
428     uint8 sel_pic = MASTER_PIC;
429     uint8 sel_tc = 0;
430     uint8 sel_timer = 0;
431 
432     switch(Addr & 0x0F) {
433         case SS1_S8259_L:
434             sel_pic = SLAVE_PIC;
435         case SS1_M8259_L:
436             if(cData & 0x10) {
437                 sim_debug(PIC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
438                           " WR: %s PIC ICW1=0x%02x.\n", PCX, (sel_pic ? "Slave " : "Master"), cData);
439                 ss1_pic[sel_pic].ICW[1] = cData;
440                 ss1_pic[sel_pic].config_cnt=1;
441             } else {
442                 if(cData & 0x08) { /* OCW3 */
443                     sim_debug(PIC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
444                               " WR: %s PIC OCW3=0x%02x.\n", PCX, (sel_pic ? "Slave " : "Master"), cData);
445                     ss1_pic[sel_pic].OCW3 = cData;
446                 } else { /* OCW2 */
447                     sim_debug(PIC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
448                               " WR: %s PIC OCW2=0x%02x.\n", PCX, (sel_pic ? "Slave " : "Master"), cData);
449                     ss1_pic[sel_pic].OCW2 = cData;
450                 }
451             }
452             break;
453         case SS1_S8259_H:
454             sel_pic = SLAVE_PIC;
455         case SS1_M8259_H:
456             if(ss1_pic[sel_pic].config_cnt == 0) {
457                 sim_debug(PIC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " WR: %s PIC IMR=0x%02x.\n", PCX, (sel_pic ? "Slave " : "Master"), cData);
458                 ss1_pic[sel_pic].IMR = cData;
459                 generate_ss1_interrupt();
460             } else {
461                 ss1_pic[sel_pic].config_cnt++;
462                 sim_debug(PIC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " WR: %s PIC ICW%d=0x%02x.\n", PCX, (sel_pic ? "Slave " : "Master"), ss1_pic[sel_pic].config_cnt, cData);
463                 ss1_pic[sel_pic].ICW[ss1_pic[sel_pic].config_cnt] = cData;
464 
465                 ss1_unit[0].u3 = ss1_pic[SLAVE_PIC].ICW[2]+TC0_IRQ_OFFSET;
466                 ss1_unit[1].u3 = ss1_pic[SLAVE_PIC].ICW[2]+TC1_IRQ_OFFSET;
467                 ss1_unit[2].u3 = ss1_pic[SLAVE_PIC].ICW[2]+TC2_IRQ_OFFSET;
468 
469                 if(ss1_pic[sel_pic].config_cnt == 4) {
470                     ss1_pic[sel_pic].config_cnt = 0;
471                 }
472             }
473             break;
474         case SS1_8253_CTL:
475             ss1_tc[0].CTL = cData;
476             sel_timer = (ss1_tc[0].CTL & I8253_CTL_SC_MASK) >> 6;
477             sim_debug(TC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
478                       " WR: TC CTL=0x%02x.\n",
479                       PCX, ss1_tc[0].CTL);
480             if(ss1_tc[0].CTL & I8253_CTL_BCD) {
481                 sim_debug(ERROR_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
482                           " Timer %d: BCD Mode not supported: TC CTL=0x%02x.\n",
483                           PCX, sel_timer, ss1_tc[0].CTL);
484             }
485             ss1_tc[0].bcd[sel_timer] = (ss1_tc[0].CTL & I8253_CTL_BCD);
486             ss1_tc[0].mode[sel_timer] = (ss1_tc[0].CTL & I8253_CTL_MODE_MASK) >> 1;
487             ss1_tc[0].rl[sel_timer] = (ss1_tc[0].CTL & I8253_CTL_RL_MASK) >> 4;
488             sim_debug(TRACE_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
489                       " Timer %d: Mode: %d, RL=%d, %s.\n",
490                       PCX, sel_timer, ss1_tc[0].mode[sel_timer],
491                       ss1_tc[0].rl[sel_timer],
492                       ss1_tc[0].bcd[sel_timer] ? "BCD" : "Binary");
493             newcount = 0;
494             bc=0;
495             break;
496         case SS1_8253_TC2:
497             sel_tc++;
498         case SS1_8253_TC1:
499             sel_tc++;
500         case SS1_8253_TC0:
501             if(ss1_tc[0].rl[sel_timer] == 3) {
502                 if(bc==0) {
503                     newcount = cData;
504                 }
505                 if(bc==1) {
506                     newcount |= (cData << 8);
507                     sim_activate(&ss1_unit[sel_tc], newcount);
508                 }
509                 bc++;
510             }
511 
512             if(ss1_tc[0].rl[sel_timer] == 2) {
513                 newcount = (cData << 8);
514                 sim_activate(&ss1_unit[sel_tc], newcount);
515             }
516 
517             sim_debug(TC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
518                       " WR: TC [%d]=0x%02x.\n", PCX, sel_tc, cData);
519             if(sel_tc == 0) {
520             }
521             break;
522         case SS1_9511A_DATA:
523         case SS1_9511A_CMD:
524             sim_debug(TRACE_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
525                       " WR: Math Coprocessor not Implemented.\n", PCX);
526             break;
527         case SS1_RTC_CMD:
528             ss1_rtc[0].digit_sel = cData & 0x0F;
529             ss1_rtc[0].flags = (cData >> 4) & 0x0F;
530             sim_debug(RTC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
531                       " WR: RTC  Cmd=0x%02x (%s%s%s SEL=%x)\n",
532                       PCX, cData,
533                       ss1_rtc[0].flags & 0x4 ? "HOLD " :"",
534                       ss1_rtc[0].flags & 0x2 ? "WR" :"",
535                       ss1_rtc[0].flags & 0x1 ? "RD" :"",
536                       ss1_rtc[0].digit_sel);
537             break;
538         case SS1_RTC_DATA:
539             sim_debug(RTC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
540                       " WR: RTC Data=0x%02x\n", PCX, cData);
541             break;
542         case SS1_UART_DATA:
543             sim_debug(UART_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
544                       " WR: UART Data=0x%02x.\n", PCX, cData);
545             sio0d(Addr, 1, cData);
546             break;
547         case SS1_UART_STAT:
548             sim_debug(UART_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
549                       " WR: UART Stat=0x%02x.\n", PCX, cData);
550             sio0s(Addr, 1, cData);
551             break;
552         case SS1_UART_MODE:
553         case SS1_UART_CMD:
554             sim_debug(TRACE_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT
555                       " WR: UART not Implemented.\n", PCX);
556             break;
557     }
558 
559     return(0);
560 }
561 
raise_ss1_interrupt(uint8 isr_index)562 void raise_ss1_interrupt(uint8 isr_index)
563 {
564     uint8 irq_bit;
565     if(isr_index < 7) { /* VI0-6 on master PIC */
566         irq_bit = (1 << isr_index);
567         ss1_pic[MASTER_PIC].ISR |= irq_bit;
568         generate_ss1_interrupt();
569     } else { /* VI7 is on slave PIC */
570         ss1_pic[SLAVE_PIC].ISR |= 1;
571         generate_ss1_interrupt();
572     }
573 }
574 extern void cpu_raise_interrupt(uint32 irq);
575 
generate_ss1_interrupt(void)576 static void generate_ss1_interrupt(void)
577 {
578     uint8 irq, irq_pend, irq_index = 0, irq_bit = 0;
579 
580     uint8 pic;
581 
582     for(pic=MASTER_PIC;pic<=SLAVE_PIC;pic++) {
583         irq_pend = (~ss1_pic[pic].IMR) & ss1_pic[pic].ISR;
584 
585         while(irq_pend) {
586 
587             irq_bit = irq_pend & 1;
588             if(irq_bit) {
589                 ss1_pic[pic].IRR |= (irq_bit << irq_index);
590                 irq = ss1_pic[pic].ICW[2]+irq_index;
591                 sim_debug(IRQ_MSG, &ss1_dev, "Handling interrupt on %s PIC: IMR=0x%02x, ISR=0x%02x, IRR=0x%02x, index=%d\n", pic ? "SLAVE" : "MASTER", ss1_pic[pic].IMR, ss1_pic[pic].ISR, ss1_pic[pic].IRR, irq_index);
592                 cpu_raise_interrupt(irq);
593                 ss1_pic[pic].IRR &= ~(irq_bit << irq_index);
594                 ss1_pic[pic].ISR &= ~(irq_bit << irq_index);
595                 if(irq_pend & 0x7E) {
596 /*              sim_debug(IRQ_MSG, &ss1_dev, "Requeue interrupt on %s PIC: IMR=0x%02x, ISR=0x%02x, IRR=0x%02x, index=%d\n", pic ? "SLAVE" : "MASTER", ss1_pic[pic].IMR, ss1_pic[pic].ISR, ss1_pic[pic].IRR, irq_index);
597 */
598                     sim_activate(&ss1_unit[3], 1000);  /* requeue, because more interrupts are pending. */
599                 }
600                 break;
601             } else {
602                 irq_index++;
603                 irq_pend = irq_pend >> 1;
604             }
605         }
606     }
607 }
608 
609 
610 /* Unit service routine */
611 /* Unit 0-2 = Timer0-2, Unit3=ISR queue */
ss1_svc(UNIT * uptr)612 static t_stat ss1_svc (UNIT *uptr)
613 {
614     uint8 cData;
615     uint8 irq_bit = 0;
616 
617     /* Handle SS1 UART Rx interrupts here. */
618     cData = sio0s(0x5D, 0, 0);
619     if(cData & 2) { /* && ((ss1_pic[SLAVE_PIC].IMR & 0x80) == 0)) { */
620         ss1_pic[SLAVE_PIC].ISR |= 0x80;
621         generate_ss1_interrupt();
622         sim_activate(uptr, 1000);  /* requeue, because we still need to handle the timer interrupt. */
623     } else if((cData & 1) && ((ss1_pic[SLAVE_PIC].IMR & 0x40) == 0)) {
624         sim_debug(IRQ_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " Calling UART Tx ISR.\n", PCX);
625         ss1_pic[SLAVE_PIC].ISR |= 0x40;
626         generate_ss1_interrupt();
627         sim_activate(uptr, 1000);   /* requeue, because we still need to handle the timer interrupt. */
628     } else if (uptr->u4 == 0x3) {   /* ISR was requeued because additional interrupts were pending. */
629         generate_ss1_interrupt();
630     } else {
631         switch(uptr->u4) {
632             case 0:
633                 irq_bit = 2;
634                 break;
635             case 1:
636                 irq_bit = 4;
637                 break;
638             case 2:
639                 irq_bit = 8;
640                 break;
641         }
642         if(ss1_tc[0].mode[uptr->u4] == 0x0) {
643             sim_debug(TC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " Calling Timer%d ISR.\n", PCX, uptr->u4);
644             ss1_pic[SLAVE_PIC].ISR |= irq_bit;
645             generate_ss1_interrupt();
646         }
647         if(ss1_tc[0].mode[uptr->u4] == 0x3) {
648             sim_debug(TC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " Calling Timer%d ISR.\n", PCX, uptr->u4);
649             ss1_pic[SLAVE_PIC].ISR |= irq_bit;
650             generate_ss1_interrupt();
651             sim_debug(TC_MSG, &ss1_dev, "Timer %d, mode %d, reloading\n", uptr->u4, ss1_tc[0].mode[uptr->u4]);
652                 sim_activate(uptr, 33280);
653         }
654     }
655 
656     sim_activate(&ss1_unit[3], 1000000);  // requeue, because more interrupts are pending.
657 
658     return SCPE_OK;
659 }
660 
toBCD(const int32 x)661 static int32 toBCD(const int32 x) {
662     return (x / 10) * 16 + (x % 10);
663 }
664 
665