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