/* PDQ3_stddev.c: PDQ3 simulator standard devices | |
Work derived from Copyright (c) 2004-2012, Robert M. Supnik | |
Copyright (c) 2013 Holger Veit | |
Permission is hereby granted, free of charge, to any person obtaining a | |
copy of this software and associated documentation files (the "Software"), | |
to deal in the Software without restriction, including without limitation | |
the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
and/or sell copies of the Software, and to permit persons to whom the | |
Software is furnished to do so, subject to the following conditions: | |
The above copyright notice and this permission notice shall be included in | |
all copies or substantial portions of the Software. | |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | |
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
Except as contained in this notice, the names of Robert M Supnik and Holger Veit | |
shall not be used in advertising or otherwise to promote the sale, use or | |
other dealings in this Software without prior written authorization from | |
Robert M Supnik and Holger Veit. | |
2013xxxx hv initial version | |
20130902 hv added telnet multiplexer code | |
20131020 hv fixed CON interrupt handling | |
20131103 hv connect CON_ATTACH logic with DSR, so that DSR is set if tcp connect | |
20141003 hv compiler suggested warnings (vc++2013, gcc) | |
*/ | |
#include "pdq3_defs.h" | |
#include <ctype.h> | |
extern UNIT cpu_unit; | |
extern UNIT con_unit[]; | |
static t_stat con_termsvc(UNIT *uptr); | |
static t_stat con_pollsvc(UNIT *uptr); | |
static t_stat con_reset(DEVICE* dptr); | |
static t_stat tim_reset(DEVICE *dptr); | |
static t_stat tim0_svc(UNIT* uptr); | |
static t_stat tim1_svc(UNIT* uptr); | |
static t_stat tim2_svc(UNIT* uptr); | |
/* CON USART registers */ | |
/* This is described as positive logic, and represents the | |
* content of the corresponding registers. | |
* However, the USART is connected to inverted DAL lines | |
* and needs to be written to with the inverted value | |
* This is done in CPU Read/Write */ | |
#define CONC1_LOOP 0x80 /* 0=loopmode diagnostic, 1=normal full duplex */ | |
#define CONC1_BRK 0x40 /* 1=send break */ | |
#define CONC1_MISC 0x20 /* 1=one stop bit, 0=two */ | |
#define CONC1_ECHO 0x10 /* 1=echo received data */ | |
#define CONC1_PE 0x08 /* 1=check parity */ | |
#define CONC1_RE 0x04 /* 1=enable receiver */ | |
#define CONC1_RTS 0x02 /* 1=enable transmitter if CTS */ | |
#define CONC1_DTR 0x01 /* 1=enable CD, DSR,RI interrupts */ | |
static uint8 con_ctrl1; | |
#define CONC2_CLENMASK 0xc0 /* number of bits */ | |
#define CONC2_CLEN8 0x00 | |
#define CONC2_CLEN7 0x40 | |
#define CONC2_CLEN6 0x80 | |
#define CONC2_CLEN5 0xc0 | |
#define CONC2_MODE 0x20 /* not used set to 0 (async mode) */ | |
#define CONC2_ODDEVN 0x10 /* 0=even parity */ | |
#define CONC2_RXCLK 0x08 /* not used, set to 1 */ | |
#define CONC2_CLKMASK 0x07 /* clock selector */ | |
#define CONC2_CLK110 0x06 /* must be set to 001 (rate 1 clock) */ | |
static uint8 con_ctrl2; | |
#define CONS_DSC 0x80 /* set to 1 after status read, cleared by DSR/DCD/RI */ | |
#define CONS_DSR 0x40 /* DSR input */ | |
#define CONS_CD 0x20 /* DCD input */ | |
#define CONS_FE 0x10 /* 1=framing error */ | |
#define CONS_PE 0x08 /* 1=parity error */ | |
#define CONS_OE 0x04 /* 1= overrun error */ | |
#define CONS_DR 0x02 /* set to 1 if data received, 0 if data read */ | |
#define CONS_THRE 0x01 /* set to 1 if data xmit buffer empty */ | |
static uint8 con_status; | |
static uint8 con_xmit; | |
static uint8 con_rcv; | |
/************************************************************************************************ | |
* Onboard Console | |
***********************************************************************************************/ | |
/* con data structures | |
con_dev con device descriptor | |
con_unit con unit descriptor | |
con_mod con modifier list | |
con_reg con register list | |
*/ | |
IOINFO con_ioinfo1 = { NULL, CON_IOBASE, 4, CON_RCV_VEC, 4, con_read, con_write }; | |
IOINFO con_ioinfo2 = { &con_ioinfo1, 0, 0, CON_XMT_VEC, 3, con_read, con_write }; | |
DEVCTXT con_ctxt = { &con_ioinfo2 }; | |
UNIT con_unit[] = { | |
{ UDATA (&con_pollsvc, UNIT_ATTABLE, 0), CON_POLLRATE, }, | |
{ UDATA (&con_termsvc, UNIT_IDLE, 0), CON_TERMRATE, } | |
}; | |
static UNIT* con_tti = &con_unit[0]; /* shorthand for console input and output units */ | |
static UNIT* con_tto = &con_unit[1]; | |
REG con_reg[] = { | |
{ HRDATA (CTRL1, con_ctrl1, 8) }, | |
{ HRDATA (CTRL2, con_ctrl2, 8) }, | |
{ HRDATA (STAT, con_status, 8) }, | |
{ HRDATA (XMIT, con_xmit, 8) }, | |
{ HRDATA (RCV, con_rcv, 8) }, | |
{ NULL } | |
}; | |
MTAB con_mod[] = { | |
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", NULL, &show_iobase }, | |
{ MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", NULL, &show_iovec }, | |
{ MTAB_XTD|MTAB_VDV, 0, "PRIO", "PRIO", NULL, &show_ioprio }, | |
{ 0 } | |
}; | |
DEBTAB con_dflags[] = { | |
{ "WRITE", DBG_CON_WRITE }, | |
{ "READ", DBG_CON_READ }, | |
{ "SVC", DBG_CON_SVC }, | |
{ 0, 0 } | |
}; | |
DEVICE con_dev = { | |
"CON", /*name*/ | |
con_unit, /*units*/ | |
con_reg, /*registers*/ | |
con_mod, /*modifiers*/ | |
2, /*numunits*/ | |
16, /*aradix*/ | |
16, /*awidth*/ | |
1, /*aincr*/ | |
8, /*dradix*/ | |
8, /*dwidth*/ | |
NULL, /*examine*/ | |
NULL, /*deposit*/ | |
&con_reset, /*reset*/ | |
NULL, /*boot*/ | |
NULL, /*attach*/ | |
NULL, /*detach*/ | |
&con_ctxt, /*ctxt*/ | |
DEV_DEBUG|DEV_DISABLE, /*flags*/ | |
0, /*dctrl*/ | |
con_dflags, /*debflags*/ | |
NULL, /*msize*/ | |
NULL /*lname*/ | |
}; | |
/* bus reset handler */ | |
t_stat con_binit() { | |
con_status = CONS_THRE; | |
setbit(con_status, CONS_DSR); | |
con_ctrl1 = 0; /* no echo, receiver disabled, transmitter disabled */ | |
con_ctrl2 = 0; /* ASYNC mode, 8bits, Clock 1X */ | |
con_xmit = 0; | |
con_rcv = 0; | |
return SCPE_OK; | |
} | |
/* common handlers */ | |
static t_stat con_reset(DEVICE* dptr) | |
{ | |
DEVCTXT* ctxt = (DEVCTXT*)dptr->ctxt; | |
int32 wait = con_tti->wait = CON_POLLRATE; | |
sim_rtcn_init (wait, TMR_CONPOLL); /* init poll timer */ | |
sim_cancel(con_tto); /* disable output service */ | |
/* register/deregister I/O handlers */ | |
if (dptr->flags & DEV_DIS) { | |
del_ioh(ctxt->ioi); | |
} else { | |
add_ioh(ctxt->ioi); | |
con_tti->buf = 0; | |
sim_activate (con_tti, wait); | |
} | |
return con_binit(); | |
} | |
t_stat con_attach(UNIT* uptr, char* cptr) { | |
setbit(con_status, CONS_DSR|CONS_DSC); | |
return SCPE_OK; | |
} | |
t_stat con_detach(UNIT* uptr) { | |
clrbit(con_status, CONS_DSR); | |
setbit(con_status, CONS_DSC); | |
return SCPE_OK; | |
} | |
#define XMITENABLED() (isbitset(con_ctrl1,CONC1_RTS)) | |
#define XMITENABLE() setbit(con_ctrl1,CONC1_RTS) | |
#define XMITDISABLE() clrbit(con_ctrl1,CONC1_RTS) | |
#define XMITEMPTY() (isbitset(con_status, CONS_THRE)) | |
#define RCVENABLED() (isbitset(con_ctrl1,CONC1_RE)) | |
#define RCVFULL() (isbitset(con_status, CONS_DR)) | |
#define RCVENABLE() setbit(con_ctrl1,CONC1_RE) | |
#define RCVDISABLE() clrbit(con_ctrl1,CONC1_RE) | |
#define DSRACTIVE() (isbitset(con_ctrl1,CONC1_DTR) && isbitset(con_status,CONS_DSR)) | |
/* The transmit interrupt is raised continuously, | |
* as long as the transmit holding reg is empty and the transmitter is enabled. | |
* It will be deasserted when the tranmit reg is full or tranmitter disabled. | |
*/ | |
#define XMITINTR() cpu_assertInt(INT_CONT, XMITEMPTY()) | |
/* The receive interrupt is raised continuously, | |
* when the receiver holding register is full and the receiver is enabled. | |
* it will be deasserted when the receiver reg is read or the receiver disabled. | |
*/ | |
#define RCVINTR() cpu_assertInt(INT_CONR, RCVFULL()) | |
/* The DSR interrupt is raised when DSC is set to 1 (pos logic) | |
* and DTR is active, cleared if status is read */ | |
#define DSRINTR() cpu_assertInt(INT_PRNT, DSRACTIVE()) | |
/* Terminal output service */ | |
t_stat con_termsvc (UNIT *uptr) { | |
t_stat rc = SCPE_OK; | |
int ch = sim_tt_outcvt(uptr->buf, TT_GET_MODE(uptr->flags)); | |
if (XMITENABLED()) { /* tranmitter enabled */ | |
if (ch >= 0) { | |
if ((rc = sim_putchar_s(ch)) != SCPE_OK) { | |
sim_activate(uptr, uptr->wait); /* did not emit char, reschedule termsvc */ | |
return rc == SCPE_STALL ? SCPE_OK : rc; | |
} | |
} | |
} | |
uptr->pos = uptr->pos + 1; | |
setbit(con_status, CONS_THRE); /* set transmitter holding reg empty */ | |
cpu_assertInt(INT_CONT, TRUE); /* generate an interrupt because of DRQO */ | |
return SCPE_OK; | |
} | |
/* Terminal input service */ | |
t_stat con_pollsvc(UNIT *uptr) { | |
int32 ch; | |
uptr->wait = sim_rtcn_calb(CON_TPS, TMR_CONPOLL); /* calibrate timer */ | |
sim_activate(uptr, uptr->wait); /* restart polling */ | |
if ((ch = sim_poll_kbd()) < SCPE_KFLAG) /* check keyboard */ | |
return ch; | |
uptr->buf = (ch & SCPE_BREAK) ? 0 : sim_tt_inpcvt(ch, TT_GET_MODE(uptr->flags)); | |
uptr->pos = uptr->pos + 1; | |
if (RCVENABLED()) { /* receiver enabled? */ | |
if (RCVFULL()) /* handle data overrun */ | |
setbit(con_status, CONS_OE); | |
con_rcv = ch & 0xff; /* put in receiver register */ | |
setbit(con_status, CONS_DR); /* notify: data received */ | |
cpu_assertInt(INT_CONR, TRUE); /* generate interrupt because of DRQI */ | |
if (isbitset(con_ctrl1, CONC1_ECHO)) { /* echo? XXX handle in telnet handler? */ | |
/* XXX use direct send here, not sending via con_termsvc */ | |
sim_putchar_s(ch); | |
} | |
} | |
return SCPE_OK; | |
} | |
static int set_parity(int c, int odd) | |
{ | |
int i, p = 0; | |
for (i=0; i<8; i++) | |
if (c & (1<<i)) p ^= 1; | |
c |= p ? 0 : 0x80; | |
if (!odd) c ^= 0x80; | |
return c; | |
} | |
#if 0 | |
// currently unused | |
static int get_parity(int c, int even) | |
{ | |
int i, p = 0; | |
for (i=0; i<8; i++) | |
if (c & (1<<i)) p ^= 1; | |
if (even) p ^= 1; | |
return p; | |
} | |
#endif | |
// functions from memory handler to read and write a char | |
// note: the usart is connected to inverted data lines, | |
// this is fixed by negating input and output | |
// | |
// The logic in here uses the positive logic conventions as | |
// described in the WD1931 data sheet, not the ones in the PDQ-3_Hardware_Users_Manual | |
t_stat con_write(t_addr ioaddr, uint16 data) { | |
/* note usart has inverted bus, so all data is inverted */ | |
data = (~data) & 0xff; | |
switch (ioaddr & 0x0003) { | |
case 0: /* CTRL1 */ | |
con_ctrl1 = data & 0xff; | |
if (!RCVENABLED()) { /* disable receiver */ | |
clrbit(con_status,CONS_FE|CONS_PE|CONS_OE|CONS_DR); | |
sim_cancel(con_tti); | |
} else { | |
sim_activate(con_tti, con_tti->wait); /* start poll service, will raise interrupt if buffer full */ | |
} | |
if (!XMITENABLED()) { /* disable transmitter */ | |
/* will drain current pending xmit service. RTS output is assumed to become inactive | |
* (it is not necessary to emulate it) */ | |
} else { | |
if (XMITEMPTY()) { | |
} else { | |
/* some char in THR, start service to emit */ | |
sim_activate(con_tto, con_tto->wait); | |
} | |
} | |
break; | |
case 1: | |
con_ctrl2 = data & 0xff; | |
break; | |
case 2: | |
// ignore this here - DLE register | |
break; | |
case 3: | |
switch (con_ctrl2 & CONC2_CLENMASK) { | |
case CONC2_CLEN5: data &= 0x1f; break; | |
case CONC2_CLEN6: data &= 0x3f; break; | |
case CONC2_CLEN7: data &= 0x7f; | |
if (isbitset(con_ctrl1,CONC1_PE)) | |
data = set_parity(data, con_ctrl2 & CONC2_ODDEVN); | |
break; | |
case CONC2_CLEN8: data &= 0xff; break; | |
} | |
con_xmit = data & 0xff; | |
con_tto->buf = data; | |
clrbit(con_status,CONS_THRE); | |
if (XMITENABLED()) | |
sim_activate(con_tto, con_tto->wait); | |
} | |
// RCVINTR(); | |
XMITINTR(); | |
DSRINTR(); | |
sim_debug(DBG_CON_WRITE, &con_dev, DBG_PCFORMAT0 "Byte write %02x (pos logic) to $%04x\n", DBG_PC, data & 0xff, ioaddr); | |
return SCPE_OK; | |
} | |
t_stat con_read(t_addr ioaddr, uint16 *data) { | |
switch (ioaddr & 0x0003) { | |
case 0: /* CTRL1 */ | |
*data = con_ctrl1; | |
break; | |
case 1: | |
*data = con_ctrl2; | |
break; | |
case 2: | |
/* XXX find out whether terminal is attached to console? */ | |
setbit(con_status, CONS_DSR); | |
// else clrbit(con_status, CONS_DSR); | |
*data = con_status; | |
clrbit(con_status,CONS_DSC); /* acknowledge change in DSR/DCD */ | |
break; | |
case 3: | |
*data = con_rcv; | |
clrbit(con_status,CONS_DR); | |
cpu_assertInt(INT_CONR, FALSE); | |
} | |
sim_debug(DBG_CON_READ, &con_dev, DBG_PCFORMAT1 "Byte read %02x (pos logic) from $%04x\n", DBG_PC, *data & 0xff, ioaddr); | |
/* note usart has inverted bus, so returned data must be negated */ | |
*data = ~(*data); | |
return SCPE_OK; | |
} | |
/************************************************************************************************ | |
* Onboard 8253 timer | |
***********************************************************************************************/ | |
struct i8253 { | |
uint16 cnt; | |
uint16 preset; | |
uint16 mode; | |
t_bool hilo; /* which half of 16 bit cnt is to be set */ | |
}; | |
struct i8253 tim[3]; | |
IOINFO tim_ioinfo1 = { NULL, TIM_IOBASE, 4, TIM_TICK_VEC, 6, tim_read, tim_write }; | |
IOINFO tim_ioinfo2 = { &tim_ioinfo1, 0, 0, TIM_INTVL_VEC, 7, tim_read, tim_write }; | |
DEVCTXT tim_ctxt = { &tim_ioinfo2 }; | |
UNIT tim_unit[] = { | |
{ UDATA (&tim0_svc, 0, 0), CON_POLLRATE, }, | |
{ UDATA (&tim1_svc, 0, 0), CON_POLLRATE, }, | |
{ UDATA (&tim2_svc, 0, 0), CON_POLLRATE, } | |
}; | |
REG tim_reg[] = { | |
{ HRDATA (CNT0, tim[0].cnt, 16) }, | |
{ HRDATA (CNT1, tim[1].cnt, 16) }, | |
{ HRDATA (CNT2, tim[2].cnt, 16) }, | |
{ HRDATA (MODE0, tim[0].mode, 8) }, | |
{ HRDATA (MODE1, tim[1].mode, 8) }, | |
{ HRDATA (MODE2, tim[2].mode, 8) }, | |
{ NULL } | |
}; | |
MTAB tim_mod[] = { | |
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", NULL, &show_iobase }, | |
{ MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", NULL, &show_iovec }, | |
{ MTAB_XTD|MTAB_VDV, 0, "PRIO", "PRIO", NULL, &show_ioprio }, | |
{ 0 } | |
}; | |
DEBTAB tim_dflags[] = { | |
{ "WRITE", DBG_TIM_WRITE }, | |
{ "READ", DBG_TIM_READ }, | |
{ "SVC", DBG_TIM_SVC }, | |
{ 0, 0 } | |
}; | |
DEVICE tim_dev = { | |
"TIM", /*name*/ | |
tim_unit, /*units*/ | |
tim_reg, /*registers*/ | |
tim_mod, /*modifiers*/ | |
3, /*numunits*/ | |
16, /*aradix*/ | |
16, /*awidth*/ | |
1, /*aincr*/ | |
8, /*dradix*/ | |
8, /*dwidth*/ | |
NULL, /*examine*/ | |
NULL, /*deposit*/ | |
&tim_reset, /*reset*/ | |
NULL, /*boot*/ | |
NULL, /*attach*/ | |
NULL, /*detach*/ | |
&tim_ctxt, /*ctxt*/ | |
DEV_DEBUG, /*flags*/ | |
0, /*dctrl*/ | |
tim_dflags, /*debflags*/ | |
NULL, /*msize*/ | |
NULL /*lname*/ | |
}; | |
t_stat tim_reset(DEVICE *dptr) | |
{ | |
DEVCTXT* ctxt = (DEVCTXT*)dptr->ctxt; | |
if (dptr->flags & DEV_DIS) { | |
del_ioh(ctxt->ioi); | |
sim_cancel(&tim_unit[0]); | |
sim_cancel(&tim_unit[1]); | |
sim_cancel(&tim_unit[2]); | |
} else { | |
add_ioh(ctxt->ioi); | |
} | |
return SCPE_OK; | |
} | |
t_stat tim_read(t_addr ioaddr, uint16 *data) | |
{ | |
int n = ioaddr & 0x0003; | |
if (n == 3) | |
*data = 0xff; | |
else { | |
*data = (tim[n].hilo ? tim[n].cnt : (tim[n].cnt >> 8)) & 0xff; | |
sim_debug(DBG_TIM_READ, &tim_dev, DBG_PCFORMAT1 "Read %s timer%d: %02x\n", | |
DBG_PC, tim[n].hilo ? "high" : "low", n, *data); | |
tim[n].hilo = ! tim[n].hilo; | |
} | |
return SCPE_OK; | |
} | |
static uint16 sethi(uint16 val, uint16 data) { | |
val &= 0xff; | |
val |= (data << 8); | |
return val; | |
} | |
static uint16 setlo(uint16 val, uint16 data) { | |
val &= 0xff00; | |
val |= data; | |
return val; | |
} | |
t_stat tim_write(t_addr ioaddr, uint16 data) | |
{ | |
int n = ioaddr & 0x0003; | |
data &= 0xff; | |
if (n == 3) { | |
n = (data & 0xc0) >> 6; | |
sim_debug(DBG_TIM_WRITE, &tim_dev, DBG_PCFORMAT0 "Timer%d: mode=%d\n", | |
DBG_PC, n, (data >> 1) & 7); | |
if (n == 3) { | |
sim_printf("Unimplemented: Mode=0xc0\n"); | |
return STOP_IMPL; | |
} | |
if (data & 0x01) { | |
sim_printf("Unimplemented: BCD mode: timer=%d\n",n); | |
return STOP_IMPL; | |
} | |
if (!( (data & 0x0e)==0x00 || (data & 0x0e)==0x04)) { | |
sim_printf("Unimplemented: Mode not 0 or 2: timer=%d\n",n); | |
return STOP_IMPL; | |
} | |
if ((data & 0x30) != 0x30) { | |
sim_printf("Unimplemented: not 16 bit load: timer=%d\n",n); | |
return STOP_IMPL; | |
} | |
tim[n].mode = data; | |
} else { | |
if (tim[n].hilo) { | |
tim[n].preset = sethi(tim[n].preset, data); | |
tim[n].cnt = sethi(tim[n].cnt, data); | |
if (n < 2) { /* timer 2 is triggered by timer 1 */ | |
int32 time = 1250000 / tim[n].cnt; | |
sim_cancel(&tim_unit[n]); | |
sim_activate(&tim_unit[n], time); | |
} | |
} else { | |
tim[n].preset = setlo(tim[n].preset, data); | |
tim[n].cnt = setlo(tim[n].cnt, data); | |
} | |
sim_debug(DBG_TIM_WRITE, &tim_dev, DBG_PCFORMAT0 "Timer%d: %s cnt=%02x\n", | |
DBG_PC, n, tim[n].hilo ? "high":"low", data); | |
tim[n].hilo = !tim[n].hilo; | |
} | |
return SCPE_OK; | |
} | |
/* baud rate timer 0 is programmed in mode 2 - actually, this is ignored */ | |
static t_stat tim0_svc(UNIT* uptr) | |
{ | |
int32 time = 1250000 / tim[0].preset; | |
sim_activate(uptr, time); | |
sim_debug(DBG_TIM_SVC, &tim_dev, DBG_PCFORMAT2 "Timer0: SVC call\n", DBG_PC); | |
return SCPE_OK; | |
} | |
/* system timer 1 is programmed in mode 2, causes interrupt each time it is 0 */ | |
static t_stat tim1_svc(UNIT* uptr) | |
{ | |
int32 time = 1250000 / tim[0].preset; | |
sim_debug(DBG_TIM_SVC, &tim_dev, DBG_PCFORMAT2 "Timer1: SVC call\n", DBG_PC); | |
sim_activate(uptr, time); | |
cpu_raiseInt(INT_TICK); | |
reg_ssr |= SSR_TICK; /* notify TICK timer int occurred */ | |
/* handle interval timer */ | |
if (tim[2].cnt > 0) tim[2].cnt--; | |
if (tim[2].cnt == 0) { | |
cpu_raiseInt(INT_INTVL); | |
reg_ssr |= SSR_INTVL; /* notify INTVL timer int occurred */ | |
if ((tim[2].mode & 0x0e) == 0x04) { | |
tim[2].cnt = tim[2].preset; /* restart timer */ | |
} /* otherwise single shot */ | |
} | |
return SCPE_OK; | |
} | |
/* interval timer 2 is programmed in mode 0 (single shot) or 2 (rate generator) | |
* this is triggered by timer1 - svc is ignored here */ | |
static t_stat tim2_svc(UNIT* uptr) | |
{ | |
sim_debug(DBG_TIM_SVC, &tim_dev, DBG_PCFORMAT2 "Timer2: SVC call - should not occur\n", DBG_PC); | |
return SCPE_OK; | |
} | |