1
0
mirror of https://github.com/simh/simh.git synced 2026-01-28 12:49:21 +00:00

SDS: Add Card Reader and Card Punch devices

This commit is contained in:
Ken Rector
2020-12-27 13:51:07 -08:00
committed by Mark Pizzolato
parent 541d1c3c90
commit 79878eb6ed
17 changed files with 1010 additions and 163 deletions

318
SDS/sds_cp.c Normal file
View File

@@ -0,0 +1,318 @@
/* sds_cp.c - SDS-930 Card Punch
Copyright (c) 2020, Ken Rector
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
KEN RECTOR 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 name of Ken Rector shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Ken Rector.
03-Mar-20 kenr Initial Version
*/
/*
This card punch simulator uses sim_card.c to write output records
in CBN format. Data is passed directly to sim_card.c when binary
mode is specified by the buffer control EOM. When BCD mode is
specified by the EOM, output data is translated into Hollerith code
from SDS Internal Code as defined by the SDS 930 Computer Reference Manual
The SDS card punch protocol defined by the 930 Computer Reference manual
specifies that the output image be sent to the buffer 12 times, once
for each row. In this simulator the card image is only written after
termination (TOP) of the twelfth image output.
The Symbol assembler punch routine uses the PBT (Punch Buffer Test)
before issueing a connect EOM to determine if it needs to write 12 rows
per card, or just 1. To make Symbol work right we always return TRUE,
(skip) for this test.
I can't find anything in the computer reference manuals that describes
how this should work. Why did Symbol do this?
*/
#include "sds_defs.h"
#include "sim_card.h"
#define CARD_IN_PUNCH 00004000 /* Card ready to punch */
#define STATUS u3
extern uint32 xfr_req;
extern int32 stop_invins, stop_invdev, stop_inviop;
uint16 cp_buffer[80]; /* card output image */
int32 cp_bptr = 0; /* buf ptr */
int32 cp_blnt = 0; /* buf length */
int32 cp_row = 0; /* row counter */
int32 cp_chr = 0;
int32 cp_eor;
int32 cp_inst; /* saved instr */
t_stat cp_devio(uint32 fnc, uint32 inst, uint32 *dat);
t_stat cp_svc(UNIT *);
t_stat cp_attach(UNIT * uptr, CONST char *file);
t_stat cp_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
t_stat cp_detach(UNIT * uptr);
t_stat cp_wrend(UNIT * uptr);
t_stat cp_show_cap (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
void cp_set_err (UNIT *uptr);
DSPT cp_tplt[] = { { 1, 0 }, { 0, 0 } }; /* template */
DIB cp_dib = { CHAN_W, DEV_CP, XFR_CP, cp_tplt, &cp_devio };
UNIT cp_unit = {UDATA(&cp_svc, UNIT_ATTABLE , 0), 2000 };
MTAB cp_mod[] = {
{MTAB_XTD | MTAB_VDV, 0, "CHANNEL", "CHANNEL",
&set_chan, &show_chan,
NULL, "Device Channel"},
{MTAB_XTD | MTAB_VDV, 0, "FORMAT", "FORMAT",
&sim_card_set_fmt, &sim_card_show_fmt,
NULL,"Card Format"},
{ MTAB_XTD|MTAB_VDV, 0, "CAPACITY", NULL,
NULL, &cp_show_cap, NULL, "Stacker Count" },
{0}
};
REG cp_reg[] = {
{ BRDATA (BUFF, cp_buffer, 16, 16, sizeof(cp_buffer)/sizeof(*cp_buffer)), REG_HRO},
{ DRDATA (BPTR, cp_bptr, 18), PV_LEFT },
{ DRDATA (BLNT, cp_blnt, 18), PV_LEFT },
{ FLDATA (XFR, xfr_req, XFR_V_CP) },
{ ORDATA (INST, cp_inst, 24) },
{ DRDATA (POS, cp_unit.pos, T_ADDR_W), PV_LEFT },
{ NULL }
};
DEVICE cp_dev = {
"CP", &cp_unit, cp_reg, cp_mod,
1, 8, 15, 1, 8, 8,
NULL, NULL, NULL, NULL, &cp_attach, &cp_detach,
&cp_dib, DEV_DISABLE | DEV_DEBUG | DEV_CARD, 0, NULL,
NULL, NULL, NULL, NULL, NULL, NULL
};
/* Convert SDS BCD character into hollerith code */
uint16 sdsbcd_to_hol(uint8 bcd) {
uint16 hol;
/* Handle space correctly */
if (bcd == 0) /* 0 to row 10 */
return 0x200;
if (bcd == 060) /* 60 no punch */
return 0;
/* Convert to top column */
switch (bcd & 060) {
default:
case 000:
hol = 0x000; /* no zone */
break;
case 020:
hol = 0x800; /* 0x200 row 12 */
break;
case 040:
hol = 0x400; /* row 11 */
break;
case 060:
hol = 0x200; /* row 10 */
break;
}
/* Convert to 0-9 row */
bcd &= 017;
if (bcd > 9) {
hol |= 0x2; /* row 8 */
bcd -= 8;
}
if (bcd != 0)
hol |= 1 << (9 - bcd);
return hol;
}
t_stat cp_devio(uint32 fnc, uint32 inst, uint32 *dat) {
UNIT *uptr = &cp_unit;
int32 new_ch;
uint8 chr;
t_stat r;
uint32 t;
switch (fnc) {
case IO_CONN:
new_ch = I_GETEOCH (inst); /* get new chan */
if (new_ch != cp_dib.chan) /* wrong chan? err */
return SCPE_IERR;
if (sim_is_active(uptr))
CRETIOP;
if (uptr->flags & UNIT_ATT) {
cp_inst = inst;
cp_blnt = 0;
cp_bptr = 0;
xfr_req = xfr_req & ~XFR_CP; /* clr xfr flag */
sim_activate (uptr, uptr->wait); /* start timer */
}
else {
cp_set_err (uptr); /* no, err, disc */
CRETIOP;
}
break;
case IO_EOM1: /* I/O Control EOM */
break;
case IO_DISC: /* disconnect TOP */
xfr_req = xfr_req & ~XFR_CP; /* clr xfr flag */
cp_row++;
if (cp_row >= 12) {
if ((r = cp_wrend(uptr)) != SCPE_OK)
return r;
uptr->STATUS &= ~CARD_IN_PUNCH;
}
sim_cancel (uptr); /* deactivate unit */
break;
case IO_WREOR: /* write eor */
break;
case IO_SKS:
new_ch = I_GETSKCH (inst); /* get chan # */
if (new_ch != cp_dib.chan) /* wrong chan? */
return SCPE_IERR;
t = I_GETSKCND (inst); /* get skip cond */
switch (t) { /* case sks cond */
case 010: /* sks 12046 */
// PBT
// /* skip if punch buffer empty */
*dat = 1;
break;
case 020: /* sks 14046 */
// CPT
/* skip if punch is ready to accept connection */
if ((uptr->flags & UNIT_ATT) &&
!(uptr->STATUS & CARD_IN_PUNCH))
*dat = 1;
break;
}
break;
case IO_WRITE:
if (!(uptr->STATUS & CARD_IN_PUNCH))
break;
chr = (*dat) & 077;
xfr_req = xfr_req & ~XFR_CP; /* clr xfr flag */
if (cp_bptr < cp_blnt) {
if (cp_inst & 01000) {
if (cp_chr & 1) /* column binary */
cp_buffer[cp_bptr++] |= chr;
else
cp_buffer[cp_bptr] = (chr << 6);
cp_chr++;
}
else {
cp_buffer[cp_bptr++] = sdsbcd_to_hol(chr); /* bcd */
}
chan_set_ordy (cp_dib.chan);
}
break;
case IO_READ:
CRETINS;
}
return SCPE_OK;
}
/* punch service */
t_stat cp_svc(UNIT *uptr) {
uptr->STATUS |= CARD_IN_PUNCH;
cp_bptr = 0;
cp_blnt = 80;
cp_chr = 0;
chan_set_ordy (cp_dib.chan);
return SCPE_OK;
}
t_stat cp_wrend(UNIT * uptr) {
t_stat st;
st = sim_punch_card(uptr, cp_buffer);
cp_row = 0;
if (st != CDSE_OK) {
cp_set_err(uptr);
return SCPE_IOERR;
}
uptr->STATUS = 0;
return SCPE_OK;
}
/* Fatal error */
void cp_set_err (UNIT *uptr)
{
chan_set_flag (cp_dib.chan, CHF_EOR | CHF_ERR); /* eor, error */
chan_disc (cp_dib.chan); /* disconnect */
xfr_req = xfr_req & ~XFR_CP; /* clear xfr */
sim_cancel (uptr); /* stop */
cp_bptr = 0; /* buf empty */
return;
}
t_stat cp_attach(UNIT * uptr, CONST char *cptr) {
t_stat r;
sim_card_set_fmt (uptr,0,"CBN",NULL);
if ((r = sim_card_attach(uptr, cptr)) != SCPE_OK)
return r;
cp_row = 0;
return SCPE_OK;
}
t_stat cp_detach(UNIT * uptr) {
if (uptr->STATUS & CARD_IN_PUNCH)
sim_punch_card(uptr, cp_buffer);
return sim_card_detach(uptr);
}
/* Channel assignment routines */
t_stat cp_set_chan (UNIT *uptr, int32 val, CONST char *sptr, void *desc)
{
t_stat r;
r = set_chan (uptr, val, sptr, desc);
return r;
}
t_stat cp_show_cap (FILE *st, UNIT *uptr, int32 val, CONST void *desc) {
int n;
if ((n = sim_card_output_hopper_count(uptr)) == 0)
fprintf(st,"stacker empty");
else {
if (n == 1)
fprintf(st,"1 card");
else
fprintf(st,"%d cards",n);
fprintf(st," in stacker");
}
return SCPE_OK;
}

View File

@@ -200,10 +200,11 @@ int32 rtc_tps = 60; /* rtc ticks/sec */
t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
t_stat cpu_reset (DEVICE *dptr);
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat cpu_set_type (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc);
t_bool cpu_is_pc_a_subroutine_call (t_addr **ret_addrs);
t_stat cpu_set_size (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat cpu_set_type (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat cpu_set_hist (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_stat Ea (uint32 wd, uint32 *va);
t_stat EaSh (uint32 wd, uint32 *va);
t_stat Read (uint32 va, uint32 *dat);
@@ -222,8 +223,8 @@ void inst_hist (uint32 inst, uint32 pc, uint32 typ);
t_stat rtc_inst (uint32 inst);
t_stat rtc_svc (UNIT *uptr);
t_stat rtc_reset (DEVICE *dptr);
t_stat rtc_set_freq (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat rtc_show_freq (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat rtc_set_freq (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat rtc_show_freq (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
extern t_bool io_init (void);
extern t_stat op_wyim (uint32 inst, uint32 *dat);
@@ -440,8 +441,8 @@ while (reason == 0) { /* loop until halted */
if (btyp) {
if (btyp & SWMASK ('E')) /* unqualified breakpoint? */
reason = STOP_IBKPT; /* stop simulation */
// else if (btyp & BRK_TYP_DYN_STEPOVER) /* stepover breakpoint? */
// reason = STOP_DBKPT; /* stop simulation */
else if (btyp & BRK_TYP_DYN_STEPOVER) /* stepover breakpoint? */
reason = STOP_DBKPT; /* stop simulation */
else switch (btyp) { /* qualified breakpoint */
case SWMASK ('M'): /* monitor mode */
reason = STOP_MBKPT; /* stop simulation */
@@ -453,6 +454,7 @@ while (reason == 0) { /* loop until halted */
reason = STOP_UBKPT; /* stop simulation */
break;
}
sim_interval++; /* don't count non-executed instruction */
break;
}
}
@@ -1531,9 +1533,126 @@ if (pcq_r)
else return SCPE_IERR;
sim_brk_dflt = SWMASK ('E');
sim_brk_types = SWMASK ('E') | SWMASK ('M') | SWMASK ('N') | SWMASK ('U');
sim_vm_is_subroutine_call = cpu_is_pc_a_subroutine_call;
return SCPE_OK;
}
/* For Next command, determine if should use breakpoints
to step over a subroutine branch or POP or SYSPOP. Return
TRUE if so with a list of addresses where dynamic (temporary)
breakpoints should be set.
*/
typedef enum Next_Case { /* Next Next Atomic Next Forward */
Next_BadOp = 0, /* FALSE FALSE FALSE */
Next_Branch, /* FALSE EA FALSE */
Next_BRM, /* P+1,P+2,P+3 EA+1,P+1,P+2,P+3 P+1,P+2,P+3 */
Next_BRX, /* FALSE EA,P+1 P+1 */
Next_Simple, /* FALSE P+1 P+1 */
Next_POP, /* P+1,P+2 100+OP,P+1,P+2 P+1,P+2 */
Next_Skip, /* P+1,P+2 P+1,P+2 P+1,P+2 */
Next_EXU /* ?? ?? ?? */
} Next_Case;
Next_Case Op_Cases[64] = {
Next_BadOp, Next_Branch, Next_Simple, Next_BadOp, /* HLT BRU EOM ... */
Next_BadOp, Next_BadOp, Next_Simple, Next_BadOp, /* ... ... EOD ... */
Next_Simple, Next_Branch, Next_Simple, Next_Simple, /* MIY BRI MIW POT */
Next_Simple, Next_BadOp, Next_Simple, Next_Simple, /* ETR ... MRG EOR */
Next_Simple, Next_BadOp, Next_Simple, Next_EXU, /* NOP ... ROV EXU */
Next_BadOp, Next_BadOp, Next_BadOp, Next_BadOp, /* ... ... ... ... */
Next_Simple, Next_BadOp, Next_Simple, Next_Simple, /* YIM ... WIM PIN */
Next_BadOp, Next_Simple, Next_Simple, Next_Simple, /* ... STA STB STX */
Next_Skip, Next_BRX, Next_BadOp, Next_BRM, /* SKS BRX ... BRM */
Next_BadOp, Next_BadOp, Next_Simple, Next_BadOp, /* ... ... RCH ... */
Next_Skip, Next_Branch, Next_Skip, Next_Skip, /* SKE BRR SKB SKN */
Next_Simple, Next_Simple, Next_Simple, Next_Simple, /* SUB ADD SUC ADC */
Next_Skip, Next_Simple, Next_Simple, Next_Simple, /* SKR MIN XMA ADM */
Next_Simple, Next_Simple, Next_Simple, Next_Simple, /* MUL DIV RSH LSH */
Next_Skip, Next_Simple, Next_Skip, Next_Skip, /* SKM LDX SKA SKG */
Next_Skip, Next_Simple, Next_Simple, Next_Simple }; /* SKD LDB LDA EAX */
t_bool cpu_is_pc_a_subroutine_call (t_addr **ret_addrs)
{
static t_addr returns[10];
uint32 inst;
Next_Case op_case;
int32 atomic, forward;
t_addr *return_p;
uint32 va;
int32 exu_cnt = 0;
*ret_addrs = return_p = returns;
atomic = sim_switches & SWMASK('A');
forward = sim_switches & SWMASK('F');
if (Read (P, &inst) != SCPE_OK) /* get instruction */
return FALSE;
Exu_Loop:
if (I_POP & inst) { /* determine inst case */
if ((inst & ((I_M_OP << I_V_OP) | I_USR)) == 047000000)
op_case = Next_BRM; /* Treat SBRM like BRM */
else
op_case = Next_POP;
}
else
op_case = Op_Cases[I_GETOP(inst)];
switch (op_case) {
case Next_BadOp:
break;
case Next_BRM:
*return_p++ = (P + 1) & VA_MASK;
*return_p++ = (P + 2) & VA_MASK;
*return_p++ = (P + 3) & VA_MASK;
if (atomic) {
if (Ea (inst, &va) != SCPE_OK)
return FALSE;
*return_p++ = (va + 1) & VA_MASK;
}
break;
case Next_Branch:
if (atomic) {
if (Ea (inst, &va) != SCPE_OK)
return FALSE;
*return_p++ = va & VA_MASK;
}
break;
case Next_BRX:
if (atomic) {
if (Ea (inst, &va) != SCPE_OK)
return FALSE;
*return_p++ = va & VA_MASK;
}
/* -- fall through to Next_Simple case -- */
case Next_Simple:
if (atomic || forward)
*return_p++ = (P + 1) & VA_MASK;
break;
case Next_POP:
if (atomic)
*return_p++ = 0100 + I_GETOP(inst);
/* -- fall through to Next_Skip case -- */
case Next_Skip:
*return_p++ = (P + 1) & VA_MASK;
*return_p++ = (P + 2) & VA_MASK;
break;
case Next_EXU: /* execute inst at EA */
if (++exu_cnt > exu_lim) /* too many? */
return FALSE;
if (Ea (inst, &va) != SCPE_OK) /* decode eff addr */
return FALSE;
if (Read (va, &inst) != SCPE_OK) /* get operand */
return FALSE;
goto Exu_Loop;
}
if (return_p == returns) /* if no cases added, */
return FALSE; /* return FALSE */
else
*return_p = (t_addr)0; /* else append terminator */
return TRUE; /* and return TRUE */
}
/* Memory examine */
t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
@@ -1567,7 +1686,7 @@ return SCPE_OK;
/* Set memory size */
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
t_stat cpu_set_size (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
int32 mc = 0;
uint32 i;
@@ -1586,7 +1705,7 @@ return SCPE_OK;
/* Set system type (1 = Genie, 0 = standard) */
t_stat cpu_set_type (UNIT *uptr, int32 val, char *cptr, void *desc)
t_stat cpu_set_type (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
extern t_stat drm_reset (DEVICE *dptr);
extern DEVICE drm_dev, mux_dev, muxl_dev;
@@ -1664,7 +1783,7 @@ return SCPE_OK;
/* Set frequency */
t_stat rtc_set_freq (UNIT *uptr, int32 val, char *cptr, void *desc)
t_stat rtc_set_freq (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
if (cptr)
return SCPE_ARG;
@@ -1676,7 +1795,7 @@ return SCPE_OK;
/* Show frequency */
t_stat rtc_show_freq (FILE *st, UNIT *uptr, int32 val, void *desc)
t_stat rtc_show_freq (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
fprintf (st, (rtc_tps == 50)? "50Hz": "60Hz");
return SCPE_OK;
@@ -1703,7 +1822,7 @@ return;
/* Set history */
t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc)
t_stat cpu_set_hist (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
int32 i, lnt;
t_stat r;
@@ -1742,15 +1861,14 @@ return SCPE_OK;
/* Show history */
t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc)
t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
int32 ov, k, di, lnt;
char *cptr = (char *) desc;
CONST char *cptr = (CONST char *) desc;
t_stat r;
extern t_value *sim_eval;
InstHistory *h;
static char *cyc[] = { " ", " ", "INT", "TRP" };
static char *modes = "NMU?";
static const char *cyc[] = { " ", " ", "INT", "TRP" };
static const char *modes = "NMU?";
if (hst_lnt == 0) /* enabled? */
return SCPE_NOFNC;

381
SDS/sds_cr.c Normal file
View File

@@ -0,0 +1,381 @@
/* sds_cr.c: SDS-930 card reader simulator
Copyright (c) 2020, Ken Rector
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
KEN RECTOR 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 name of Ken Rector shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Ken Rector.
03-Mar-20 kenr Initial Version
*/
/*
This card reader simulator uses sim_card.c to attach and read input records
in CBN format. When BCD mode is specified by the buffer control EOM, input data
is translated from the Hollerith encoded data in the card columns to the
SDS Internal Code as defined by the SDS 930 Computer Reference Manual. The
translation function was modified from the sim_card.c code to provide SDS
Internal BCD codes.
The card reader delays the disconnect after the last character until the trailing
edge of the card is detected. In this simulator, this delay is accomplished
by scheduling a final service request after the last characters have been
delivered too the channel. The timing for this service has been adjusted to
handle some example SDS programs. Too long a delay causes errors in some, too short
a delay affects others.
*/
#include "sds_defs.h"
#include "sim_card.h"
#define FEEDING 00001000 /* feeding card to read station */
#define READING 00004000 /* Card at read station */
#define STATUS u3 /* status */
#define CARD_RDY(u) (sim_card_input_hopper_count(u) > 0 || \
sim_card_eof(u) == 1)
extern uint32 xfr_req;
extern int32 stop_invins, stop_invdev, stop_inviop;
extern uint8 chan_cpw[NUM_CHAN]; /* char per word */
extern uint8 chan_cnt[NUM_CHAN]; /* char count */
int32 cr_bptr = 0; /* buf ptr */
int32 cr_blnt = 0; /* buf length */
int32 cr_chr = 0; /* char no.*/
int32 cr_inst = 0; /* saved instr */
int32 cr_eor = 0; /* end of record */
uint16 cr_buffer[80]; /* card record */
DSPT cr_tplt[] = {{1,0},{0,0}}; /* template */
t_stat cr_svc(UNIT *);
t_stat cr_boot(int32, DEVICE *);
t_stat cr_reset(DEVICE *);
t_stat cr_attach(UNIT *, CONST char *);
t_stat cr_detach(UNIT *);
t_stat cr_devio(uint32 fnc, uint32 inst, uint32 *dat);
t_stat cr_show_cap (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_stat cr_readrec (UNIT *uptr);
void cr_set_err (UNIT *uptr);
DIB cr_dib = { CHAN_W, DEV_CR, XFR_CR, cr_tplt, &cr_devio };
UNIT cr_unit = {
UDATA(&cr_svc, UNIT_ATTABLE | UNIT_RO | UNIT_DISABLE | MODE_029 | MODE_CBN,0),
60
};
REG cr_reg[] = {
{ DRDATA (BPTR, cr_bptr, 18), PV_LEFT },
{ DRDATA (BLNT, cr_blnt, 18), PV_LEFT },
{ FLDATA (XFR, xfr_req, XFR_V_CR) },
{ ORDATA (INST, cr_inst, 24) },
{ DRDATA (POS, cr_unit.pos, T_ADDR_W), PV_LEFT },
{ NULL }
};
MTAB cr_mod[] = {
{MTAB_XTD | MTAB_VDV, 0, "CHANNEL", "CHANNEL",
&set_chan,&show_chan,NULL, "Device Channel"},
{MTAB_XTD | MTAB_VDV, 0, "FORMAT", "FORMAT",
&sim_card_set_fmt, &sim_card_show_fmt,
NULL,"Card Format"},
{ MTAB_XTD|MTAB_VDV, 0, "CAPACITY", NULL,
NULL, &cr_show_cap, NULL, "Card Input Status" },
{0}
};
DEVICE cr_dev = {
"CR", &cr_unit, cr_reg, cr_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &cr_reset, &cr_boot, &cr_attach,NULL,
&cr_dib, DEV_DISABLE | DEV_CARD, 0, NULL,
NULL, NULL, NULL, NULL, NULL, NULL
};
/* Returns the SDS Internal style BCD of the
hollerith code or 0x7f if error
*/
uint8 hol_to_sdsbcd(uint16 hol) {
uint8 bcd;
/* Convert 10,11,12 rows */
switch (hol & 0xe00) {
case 0x000:
if ((hol & 0x1ff) == 0)
return 060;
bcd = 000; // digits 1-9
break;
case 0x200: /* 0 */
if ((hol & 0x1ff) == 0)
return 00; // digit 0
bcd = 060; // /,S-Z
break;
case 0x400: /* 11 */
bcd = 040; // -,J-R
break;
case 0x600: /* 11-10 Punch */
bcd = 052;
break;
case 0x800: /* 12 */
bcd = 020; // +,A-I
break;
case 0xA00: /* 12-10 Punch */
bcd = 032;
break;
default: /* Double punch in 10,11,12 rows */
return 0x7f;
}
hol &= 0x1ff; /* Mask rows 0-9 */
/* Check row 8 punched */
if (hol & 0x2) {
bcd += 8;
hol &= ~0x2;
}
/* Convert rows 0-9 */
while (hol != 0 && (hol & 0x200) == 0) {
bcd++;
hol <<= 1;
}
/* Any more columns punched? */
if ((hol & 0x1ff) != 0)
return 0x7f;
return bcd;
}
/* device i/o routine */
t_stat cr_devio (uint32 fnc, uint32 inst, uint32 *dat) {
UNIT *uptr = &cr_unit; /* get unit ptr */
int32 new_ch;
int32 t;
t_stat r;
unsigned char chr;
switch (fnc) { /* case function */
case IO_CONN: /* bufer control EOM */
new_ch = I_GETEOCH (inst); /* get new chan */
if (new_ch != cr_dib.chan) /* wrong chan? */
return SCPE_IERR;
if (sim_is_active(uptr)) /* busy ?*/
CRETIOP;
/* if not reading and no card in reader and hopper has cards */
if ((uptr->STATUS & (FEEDING|READING)) == 0 &&
(sim_card_input_hopper_count(uptr) > 0)) {
uptr->STATUS = FEEDING;
cr_inst = inst;
cr_blnt = 0;
cr_bptr = 0;
xfr_req = xfr_req & ~XFR_CR; /* clr xfr flag */
sim_activate (uptr,2*uptr->wait); /* start timer */
}
else {
/* if feeding or reading in different mode */
if ((inst & 01000) != (cr_inst & 01000)) {
if (cr_inst & 01000) {
if (cr_chr & 1) { /* was binary - at 2nd 6 bits
*/
cr_bptr++; /* skip to next column*/
}
}
cr_chr = 0;
}
}
cr_inst = inst; /* save EOM with mode */
break;
case IO_EOM1: /* I/O Control EOM */
new_ch = I_GETEOCH (inst); /* get new chan */
if (new_ch != cr_dib.chan) /* wrong chan? err */
return SCPE_IERR;
if ((inst & 07700) == 02000) { /* skip remainder of card*/
sim_cancel (uptr); /* stop timer */
chan_set_flag (cr_dib.chan, CHF_EOR); /* end record */
uptr->STATUS = 0;
chan_disc (cr_dib.chan);
xfr_req = xfr_req & ~XFR_CR; /* clr xfr flag */
}
break;
case IO_DISC: /* disconnect */
xfr_req = xfr_req & ~XFR_CR; /* clr xfr flag */
sim_cancel (uptr); /* deactivate unit */
break;
case IO_SKS: /* SKS */
new_ch = I_GETSKCH (inst); /* get chan # */
if (new_ch != cr_dib.chan) /* wrong chan? */
return SCPE_IERR;
t = I_GETSKCND (inst); /* get skip cond */
switch (t) { /* case sks cond */
case 004: /* sks 1100n */
// CFT
if ((uptr->STATUS & (FEEDING|READING)) == 0 &&
(sim_card_input_hopper_count(uptr) > 0))
*dat = 1; /* skip if not EOF */
break;
case 010: /* sks 1200n */
// CRT
// hopper not empty
// no feed or read cycle is in progress
if ((uptr->STATUS & (FEEDING|READING)) == 0 &&
(sim_card_input_hopper_count(uptr) > 0))
*dat = 1; /* skip if reader ready */
break;
case 020: /* sks 1400n */
if ((uptr->STATUS & READING) && /* first column test */
(((cr_inst & 01000) && (cr_chr < 2)) ||
(cr_chr < 1)))
*dat = 1; /* skip if first column*/
break;
}
break;
case IO_READ:
xfr_req = xfr_req & ~XFR_CR;
if (cr_blnt == 0) { /* first read? */
r = cr_readrec (uptr); /* get data */
if ((r != SCPE_OK) || (cr_blnt == 0)) /* err, inv reclnt? */
return r;
}
if (cr_blnt) {
if (cr_inst & 01000) {
if (cr_chr & 1) /* binary */
chr =cr_buffer[cr_bptr++] & 077;
else
chr = (cr_buffer[cr_bptr] >> 6) & 077;
cr_chr++;
*dat = chr & 077;
}
else {
chr = hol_to_sdsbcd(cr_buffer[cr_bptr++]); /* bcd */
*dat = chr & 077;
}
}
if (cr_bptr >= cr_blnt) {
/* The card reader doesn't disconnect from the channel until the
trailing edge of the card passes the read station so we need to
schedule another service event here. But if it disconnects too
soon some programs (Fortran and 850647 (unencode) don't work right
and if it takes too long Symbol will try to connect to the LP
before it's disconnected.
*/
cr_eor = 1;
sim_cancel(uptr);
sim_activate (uptr, 50);
}
break;
case IO_WREOR:
case IO_WRITE:
CRETINS;
}
return SCPE_OK;
}
/* Service routine */
t_stat cr_svc(UNIT * uptr) {
xfr_req = xfr_req & ~XFR_CR;
if (cr_eor) {
cr_eor = 0;
sim_cancel (uptr);
chan_set_flag (cr_dib.chan, CHF_EOR);
uptr->STATUS = 0;
return SCPE_OK;
}
xfr_req = xfr_req | XFR_CR;
sim_activate (uptr, 50);
return SCPE_OK;
}
/* Read start - get next record */
t_stat cr_readrec (UNIT *uptr) {
int r;
switch(r = sim_read_card(uptr, cr_buffer)) {
case CDSE_EOF: /* parser found tape mark attach */
case CDSE_EMPTY: /* not attached or hopper empty */
case CDSE_ERROR: /* parser found error during attach */
default:
uptr->STATUS = 0; /* read failed, no card in reader */
cr_set_err(uptr);
return r;
case CDSE_OK:
uptr->STATUS = READING;
cr_bptr = 0;
cr_blnt = 80;
cr_chr = 0;
break;
}
return SCPE_OK;
}
/* Fatal error */
void cr_set_err (UNIT *uptr) {
chan_set_flag (cr_dib.chan, CHF_EOR | CHF_ERR); /* eor, error */
chan_disc (cr_dib.chan); /* disconnect */
xfr_req = xfr_req & ~XFR_CR; /* clear xfr */
sim_cancel (uptr); /* stop */
cr_bptr = 0; /* buf empty */
return;
}
t_stat cr_reset (DEVICE *dptr) {
chan_disc (cr_dib.chan); /* disconnect */
cr_bptr = cr_blnt = 0;
xfr_req = xfr_req & ~XFR_CR; /* clr xfr flag */
sim_cancel (&cr_unit); /* deactivate unit */
return SCPE_OK;
}
t_stat cr_attach (UNIT *uptr, CONST char *cptr) {
return sim_card_attach(uptr, cptr);
}
/* Boot routine - simulate FILL console command */
t_stat cr_boot (int32 unitno, DEVICE *dptr) {
extern uint32 P, M[];
cr_reset(dptr);
M[0] = 077777771; /* -7B */
M[1] = 007100000; /* LDX 0 */
M[2] = 000203606; /* EOM 3606 read card binary */
M[3] = 003200002; /* WIM 2 */
M[4] = 000100002; /* BRU 2 */
P = 1; /* start at 1 */
return SCPE_OK;
}
t_stat cr_show_cap (FILE *st, UNIT *uptr, int32 val, CONST void *desc) {
int n;
if ((n = sim_card_input_hopper_count(uptr)) == 0)
fprintf(st,"hopper empty");
else {
if (n == 1)
fprintf(st,"1 card");
else
fprintf(st,"%d cards",n);
fprintf(st," in hopper");
}
return SCPE_OK;
}

View File

@@ -1,6 +1,6 @@
/* sds_defs.h: SDS 940 simulator definitions
Copyright (c) 2001-2010, Robert M. Supnik
Copyright (c) 2001-2020, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@@ -23,6 +23,7 @@
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
09-Nov-20 RMS Added definitions for card reader/punch (Ken Rector)
22-May-10 RMS Added check for 64b definitions
25-Apr-03 RMS Revised for extended file support
*/
@@ -350,11 +351,13 @@ typedef struct sdsdib DIB;
#define DEV_MASK 077 /* device mask */
#define DEV_TTI 001 /* teletype */
#define DEV_PTR 004 /* paper tape rdr */
#define DEV_CR 006 /* card punch */
#define DEV_MT 010 /* magtape */
#define DEV_RAD 026 /* fixed head disk */
#define DEV_DSK 026 /* moving head disk */
#define DEV_TTO 041 /* teletype */
#define DEV_PTP 044 /* paper tape punch */
#define DEV_CP 046 /* card punch */
#define DEV_LPT 060 /* line printer */
#define DEV_MTS 020 /* MT scan/erase */
#define DEV_OUT 040 /* output flag */
@@ -375,6 +378,8 @@ typedef struct sdsdib DIB;
#define XFR_V_RAD 6 /* fixed hd disk */
#define XFR_V_DSK 7 /* mving hd disk */
#define XFR_V_MT0 8 /* magtape */
#define XFR_V_CR 9 /* card reader */
#define XFR_V_CP 10 /* card punch */
#define XFR_TTI (1 << XFR_V_TTI)
#define XFR_TTO (1 << XFR_V_TTO)
@@ -384,6 +389,8 @@ typedef struct sdsdib DIB;
#define XFR_RAD (1 << XFR_V_RAD)
#define XFR_DSK (1 << XFR_V_DSK)
#define XFR_MT0 (1 << XFR_V_MT0)
#define XFR_CR (1 << XFR_V_CR)
#define XFR_CP (1 << XFR_V_CP)
/* PIN/POT ordinals (0 is reserved) */
@@ -418,9 +425,13 @@ void chan_set_flag (int32 ch, uint32 fl);
void chan_set_ordy (int32 ch);
void chan_disc (int32 ch);
void chan_set_uar (int32 ch, uint32 dev);
t_stat set_chan (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat show_chan (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat set_chan (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat show_chan (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_stat chan_process (void);
t_bool chan_testact (void);
/* Translation tables */
extern const int8 odd_par[64];
#endif

View File

@@ -111,3 +111,6 @@ Bugs
36. CPU: EOD 20000 used by diagnostic (EM change is NOP)
37. CPU: SKD sets all 24b of X, not just exponent
38. CPU: reset should not clear A, B, X
39. LPT: carriage control position lost on spacing operation
40. IO: TOP disconnects the channel rather than setting CHF_EOR
41. TTY: TTO was outputing spurious extra character, even if no leader set

View File

@@ -106,7 +106,6 @@ int32 drm_ftime = 3; /* time to fetch */
int32 drm_xtime = 1; /* time to xfr */
int32 drm_stopioe = 1; /* stop on error */
DEVICE drm_dev;
t_stat drm (uint32 fnc, uint32 inst, uint32 *dat);
t_stat drm_svc (UNIT *uptr);
t_stat drm_reset (DEVICE *dptr);
@@ -238,7 +237,7 @@ if (drm_sta != DRM_SXFR) { /* fetch drum prog? */
case DRM_EIE: /* end, int if err */
if (!drm_err)
return SCPE_OK;
/* fall through */
/* fall through */
case DRM_EIU: /* end, int uncond */
int_req = int_req | INT_DRM;
return SCPE_OK;

View File

@@ -87,7 +87,6 @@ DSPT dsk_tplt[] = { /* template */
{ 0, 0 }
};
DEVICE dsk_dev;
t_stat dsk_svc (UNIT *uptr);
t_stat dsk_reset (DEVICE *dptr);
t_stat dsk_fill (uint32 dev);

View File

@@ -1,6 +1,6 @@
/* sds_io.c: SDS 940 I/O simulator
Copyright (c) 2001-2012, Robert M. Supnik
Copyright (c) 2001-2020, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@@ -23,6 +23,8 @@
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
01-Nov-2020 RMS Fixed overrun/underrun handling in single-word IO
23-Oct-2020 RMS TOP disconnects the channel rather than setting CHF_EOR
19-Mar-2012 RMS Fixed various declarations (Mark Pizzolato)
*/
@@ -149,7 +151,7 @@ extern void set_dyn_map (void);
support all widths.
*/
t_stat chan_show_reg (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat chan_show_reg (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
struct aldisp {
t_stat (*pin) (uint32 num, uint32 *dat); /* altnum, *dat */
@@ -222,11 +224,11 @@ uint32 dev_map[64][NUM_CHAN];
/* dev_dsp maps device and channel numbers to dispatch routines */
t_stat (*dev_dsp[64][NUM_CHAN])() = { {NULL} };
t_stat (*dev_dsp[64][NUM_CHAN])(uint32 fnc, uint32 dev, uint32 *dat) = { {NULL} };
/* dev3_dsp maps system device numbers to dispatch routines */
t_stat (*dev3_dsp[64])() = { NULL };
t_stat (*dev3_dsp[64])(uint32 fnc, uint32 dev, uint32 *dat) = { NULL };
/* dev_alt maps alert numbers to dispatch routines */
@@ -389,7 +391,7 @@ switch (mod) {
if (ch_dev & DEV_OUT) { /* to output dev? */
if (chan_cnt[ch] || (chan_flag[ch] & CHF_ILCE)) /* busy, DMA? */
chan_flag[ch] = chan_flag[ch] | CHF_TOP; /* TOP pending */
else return dev_wreor (ch, ch_dev); /* idle, write EOR */
else return dev_disc (ch, ch_dev); /* idle, disconnect */
} /* end else TOP */
else if (ch_dev & DEV_MT) { /* change to scan? */
chan_uar[ch] = chan_uar[ch] | DEV_MTS; /* change dev addr */
@@ -577,7 +579,7 @@ return SCPE_OK;
IORD, IORP, IOSP: ZWC interrupt
IOSD: ZWC interrupt, EOR interrupt, disconnect
Note that the channel can be disconnected if CHN_EOR is set, but must
Note that the channel can be disconnected if CHF_EOR is set, but must
not be if XFR_REQ is set */
t_stat chan_read (int32 ch)
@@ -587,20 +589,23 @@ uint32 dev = chan_uar[ch] & DEV_MASK;
uint32 tfnc = CHM_GETFNC (chan_mode[ch]);
t_stat r = SCPE_OK;
if (dev && TST_XFR (dev, ch)) { /* ready to xfr? */
if (INV_DEV (dev, ch)) CRETIOP; /* can't read? */
if ((dev != 0) && TST_XFR (dev, ch)) { /* ready to xfr? */
if (INV_DEV (dev, ch)) /* can't read? */
CRETIOP;
r = dev_dsp[dev][ch] (IO_READ, dev, &dat); /* read data */
if (r) /* error? */
if ((r != 0) || (chan_cnt[ch] > chan_cpw[ch])) /* error or overrun? */
chan_flag[ch] = chan_flag[ch] | CHF_ERR;
if (chan_flag[ch] & CHF_24B) /* 24B? */
chan_war[ch] = dat;
else if (chan_flag[ch] & CHF_12B) /* 12B? */
chan_war[ch] = ((chan_war[ch] << 12) | (dat & 07777)) & DMASK;
else chan_war[ch] = ((chan_war[ch] << 6) | (dat & 077)) & DMASK;
else { /* no, precess data */
if (chan_flag[ch] & CHF_24B) /* 24B? */
chan_war[ch] = dat;
else if (chan_flag[ch] & CHF_12B) /* 12B? */
chan_war[ch] = ((chan_war[ch] << 12) | (dat & 07777)) & DMASK;
else chan_war[ch] = ((chan_war[ch] << 6) | (dat & 077)) & DMASK;
}
if (chan_flag[ch] & CHF_SCAN) /* scanning? */
chan_cnt[ch] = chan_cpw[ch]; /* never full */
else chan_cnt[ch] = chan_cnt[ch] + 1; /* insert char */
if (chan_cnt[ch] > chan_cpw[ch]) { /* full? */
if (chan_cnt[ch] > chan_cpw[ch]) { /* full now? */
if (chan_flag[ch] & CHF_ILCE) { /* interlace on? */
chan_write_mem (ch); /* write to mem */
if (chan_wcr[ch] == 0) { /* wc zero? */
@@ -697,26 +702,26 @@ if (dev && TST_XFR (dev, ch)) { /* ready to xfr? */
chan_cnt[ch] = chan_cpw[ch] + 1; /* set cnt */
}
else { /* ilce off */
CLR_XFR (dev, ch); /* cant xfr */
if (TST_EOR (dev)) /* EOR? */
if (TST_EOR (dev)) /* EOR? */
return chan_eor (ch);
chan_flag[ch] = chan_flag[ch] | CHF_ERR; /* rate err */
return SCPE_OK;
} /* end else ilce */
} /* end if cnt */
chan_cnt[ch] = chan_cnt[ch] - 1; /* decr cnt */
if (chan_flag[ch] & CHF_24B) /* 24B? */
dat = chan_war[ch];
else if (chan_flag[ch] & CHF_12B) { /* 12B? */
dat = (chan_war[ch] >> 12) & 07777; /* get halfword */
chan_war[ch] = (chan_war[ch] << 12) & DMASK; /* remove from war */
}
else { /* 6B */
dat = (chan_war[ch] >> 18) & 077; /* get char */
chan_war[ch] = (chan_war[ch] << 6) & DMASK; /* remove from war */
}
if (chan_cnt[ch] != 0) { /* if not underrun */
chan_cnt[ch] = chan_cnt[ch] - 1; /* decr cnt */
if (chan_flag[ch] & CHF_24B) /* 24B? */
dat = chan_war[ch];
else if (chan_flag[ch] & CHF_12B) { /* 12B? */
dat = (chan_war[ch] >> 12) & 07777; /* get halfword */
chan_war[ch] = (chan_war[ch] << 12) & DMASK;/* remove from war */
}
else { /* 6B */
dat = (chan_war[ch] >> 18) & 077; /* get char */
chan_war[ch] = (chan_war[ch] << 6) & DMASK; /* remove from war */
}
} /* end no underrun */
r = dev_dsp[dev][ch] (IO_WRITE, dev, &dat); /* write */
if (r) /* error? */
if (r != 0) /* error? */
chan_flag[ch] = chan_flag[ch] | CHF_ERR;
if (chan_cnt[ch] == 0) { /* buf empty? */
if (chan_flag[ch] & CHF_ILCE) { /* ilce on? */
@@ -737,14 +742,14 @@ if (dev && TST_XFR (dev, ch)) { /* ready to xfr? */
} /* end if SD */
else if (!(tfnc && CHM_SGNL) || /* IORx or IOSP TOP? */
(chan_flag[ch] & CHF_TOP))
dev_wreor (ch, dev); /* R: write EOR */
dev_disc (ch, dev); /* R: disconnect */
chan_flag[ch] = chan_flag[ch] & ~CHF_TOP;
} /* end else comp */
} /* end if wcr */
} /* end if ilce */
else if (chan_flag[ch] & CHF_TOP) { /* off, TOP pending? */
chan_flag[ch] = chan_flag[ch] & ~CHF_TOP; /* clear TOP */
dev_wreor (ch, dev); /* write EOR */
dev_disc (ch, dev); /* disconnect */
}
else if (ion) /* no TOP, EOW intr */
int_req = int_req | int_zc[ch];
@@ -902,7 +907,7 @@ return SCPE_OK;
/* Channel assignment routines */
t_stat set_chan (UNIT *uptr, int32 val, char *sptr, void *desc)
t_stat set_chan (UNIT *uptr, int32 val, CONST char *sptr, void *desc)
{
DEVICE *dptr;
DIB *dibp;
@@ -929,7 +934,7 @@ for (i = 0; i < NUM_CHAN; i++) { /* match input */
return SCPE_ARG;
}
t_stat show_chan (FILE *st, UNIT *uptr, int32 val, void *desc)
t_stat show_chan (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
DEVICE *dptr;
DIB *dibp;
@@ -997,7 +1002,7 @@ return FALSE;
/* Display channel state */
t_stat chan_show_reg (FILE *st, UNIT *uptr, int32 val, void *desc)
t_stat chan_show_reg (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
if ((val < 0) || (val >= NUM_CHAN)) return SCPE_IERR;
fprintf (st, "UAR: %02o\n", chan_uar[val]);

View File

@@ -58,10 +58,9 @@ DSPT lpt_tplt[] = { /* template */
{ 0, 0 }
};
DEVICE lpt_dev;
t_stat lpt_svc (UNIT *uptr);
t_stat lpt_reset (DEVICE *dptr);
t_stat lpt_attach (UNIT *uptr, char *cptr);
t_stat lpt_attach (UNIT *uptr, CONST char *cptr);
t_stat lpt_crctl (UNIT *uptr, int32 ch);
t_stat lpt_space (UNIT *uptr, int32 cnt);
t_stat lpt_status (UNIT *uptr);
@@ -245,7 +244,7 @@ if (uptr->flags & UNIT_ATT) { /* attached? */
uptr->pos = ftell (uptr->fileref); /* update position */
if (ferror (uptr->fileref)) { /* I/O error? */
lpt_end_op (CHF_EOR | CHF_ERR); /* set err, disc */
perror ("LPT I/O error"); /* print msg */
sim_perror ("LPT I/O error"); /* print msg */
clearerr (uptr->fileref);
return SCPE_IOERR; /* ret error */
}
@@ -324,7 +323,7 @@ return SCPE_OK;
/* Attach routine */
t_stat lpt_attach (UNIT *uptr, char *cptr)
t_stat lpt_attach (UNIT *uptr, CONST char *cptr)
{
lpt_ccp = 0; /* top of form */
return attach_unit (uptr, cptr);

View File

@@ -78,11 +78,10 @@ DSPT mt_tplt[] = { /* template */
{ 0, 0 }
};
DEVICE mt_dev;
t_stat mt_svc (UNIT *uptr);
t_stat mt_reset (DEVICE *dptr);
t_stat mt_boot (int32 unitno, DEVICE *dptr);
t_stat mt_attach (UNIT *uptr, char *cptr);
t_stat mt_attach (UNIT *uptr, CONST char *cptr);
t_stat mt_detach (UNIT *uptr);
t_stat mt_readrec (UNIT *uptr);
t_mtrlnt mt_readbc (UNIT *uptr);
@@ -478,7 +477,7 @@ return SCPE_OK;
/* Attach and detach routines */
t_stat mt_attach (UNIT *uptr, char *cptr)
t_stat mt_attach (UNIT *uptr, CONST char *cptr)
{
t_stat r;

View File

@@ -120,11 +120,11 @@ t_stat mux (uint32 fnc, uint32 inst, uint32 *dat);
t_stat muxi_svc (UNIT *uptr);
t_stat muxo_svc (UNIT *uptr);
t_stat mux_reset (DEVICE *dptr);
t_stat mux_attach (UNIT *uptr, char *cptr);
t_stat mux_attach (UNIT *uptr, CONST char *cptr);
t_stat mux_detach (UNIT *uptr);
t_stat mux_summ (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat mux_show (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat mux_vlines (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat mux_summ (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_stat mux_show (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_stat mux_vlines (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
void mux_reset_ln (int32 ln);
void mux_scan_next (void);
@@ -479,7 +479,7 @@ return SCPE_OK;
/* Attach master unit */
t_stat mux_attach (UNIT *uptr, char *cptr)
t_stat mux_attach (UNIT *uptr, CONST char *cptr)
{
t_stat r;
int32 t;
@@ -508,7 +508,7 @@ return r;
/* Change number of lines */
t_stat mux_vlines (UNIT *uptr, int32 val, char *cptr, void *desc)
t_stat mux_vlines (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
int32 newln, i, t;
t_stat r;

View File

@@ -67,7 +67,6 @@ DSPT rad_tplt[] = { /* template */
{ 0, 0 }
};
DEVICE rad_dev;
t_stat rad_svc (UNIT *uptr);
t_stat rad_reset (DEVICE *dptr);
t_stat rad_boot (int32 unitno, DEVICE *dptr);
@@ -133,7 +132,7 @@ t_stat rad (uint32 fnc, uint32 inst, uint32 *dat)
{
int32 t, lun, new_ch;
uint32 p;
uint32 *fbuf = rad_unit.filebuf;
uint32 *fbuf = (uint32 *)rad_unit.filebuf;
switch (fnc) { /* case function */
@@ -267,7 +266,7 @@ return SCPE_OK;
t_stat rad_fill (int32 sba)
{
uint32 p = rad_da * RAD_NUMWD;
uint32 *fbuf = rad_unit.filebuf;
uint32 *fbuf = (uint32 *)rad_unit.filebuf;
int32 wa = (sba + 1) >> 1; /* whole words */
if (sba && (p < rad_unit.capac)) { /* fill needed? */

View File

@@ -1,6 +1,6 @@
/* sds_stddev.c: SDS 940 standard devices
Copyright (c) 2001-2008, Robert M. Supnik
Copyright (c) 2001-2020, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@@ -28,11 +28,13 @@
tti keyboard
tto teleprinter
23-Oct-20 RMS TTO recognizes no leader flag (Ken Rector)
29-Dec-03 RMS Added console backpressure support
25-Apr-03 RMS Revised for extended file support
*/
#include "sds_defs.h"
#include "sim_tmxr.h"
#define TT_CR 052 /* typewriter */
#define TT_TB 072
@@ -44,9 +46,10 @@ int32 ptr_sor = 0; /* start of rec */
int32 ptr_stopioe = 0; /* no stop on err */
int32 ptp_ldr = 0; /* no leader */
int32 ptp_stopioe = 1;
int32 tto_ldr = 0; /* no leader */
int32 tto_retry = 0; /* retry due to stall */
DSPT std_tplt[] = { { 1, 0 }, { 0, 0 } }; /* template */
DEVICE ptr_dev, ptp_dev;
t_stat ptr (uint32 fnc, uint32 inst, uint32 *dat);
t_stat ptr_svc (UNIT *uptr);
t_stat ptr_reset (DEVICE *dptr);
@@ -63,9 +66,9 @@ t_stat tti_reset (DEVICE *dptr);
t_stat tto (uint32 fnc, uint32 inst, uint32 *dat);
t_stat tto_svc (UNIT *uptr);
t_stat tto_reset (DEVICE *dptr);
t_stat tto_out (int32 dat);
int8 ascii_to_sds(int8 ch);
int8 sds_to_ascii(int8 ch);
extern const int8 odd_par[64];
/* PTR data structures
@@ -189,6 +192,8 @@ UNIT tto_unit = { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT };
REG tto_reg[] = {
{ ORDATA (BUF, tto_unit.buf, 6) },
{ FLDATA (XFR, xfr_req, XFR_V_TTO) },
{ FLDATA (LDR, tto_ldr, 0) },
{ FLDATA (RETRY, tto_retry, 0), REG_HRO },
{ DRDATA (POS, tto_unit.pos, T_ADDR_W), PV_LEFT },
{ DRDATA (TIME, tto_unit.wait, 24), REG_NZ + PV_LEFT },
{ NULL }
@@ -279,7 +284,7 @@ if ((temp = getc (ptr_unit.fileref)) == EOF) { /* end of file? */
sim_printf ("PTR end of file\n");
else return SCPE_OK;
}
else perror ("PTR I/O error"); /* I/O error */
else sim_perror ("PTR I/O error"); /* I/O error */
clearerr (ptr_unit.fileref);
return SCPE_IOERR;
}
@@ -413,7 +418,7 @@ if ((ptp_unit.flags & UNIT_ATT) == 0) { /* attached? */
}
if (putc (dat, ptp_unit.fileref) == EOF) { /* I/O error? */
ptp_set_err (); /* yes, disc, err */
perror ("PTP I/O error"); /* print msg */
sim_perror ("PTP I/O error"); /* print msg */
clearerr (ptp_unit.fileref);
return SCPE_IOERR;
}
@@ -504,7 +509,7 @@ if (temp & SCPE_BREAK) /* ignore break */
return SCPE_OK;
temp = temp & 0177;
tti_unit.pos = tti_unit.pos + 1;
if (ascii_to_sds(temp) >= 0) {
if (ascii_to_sds (temp) >= 0) {
tti_unit.buf = ascii_to_sds(temp); /* internal rep */
sim_putchar (temp); /* echo */
if (temp == '\r') /* lf after cr */
@@ -517,6 +522,7 @@ return SCPE_OK;
t_stat tti_reset (DEVICE *dptr)
{
tmxr_set_console_units (&tti_unit, &tto_unit);
chan_disc (tti_dib.chan); /* disconnect */
tti_unit.buf = 0; /* clear state */
xfr_req = xfr_req & ~XFR_TTI; /* clr xfr flag */
@@ -536,6 +542,9 @@ return SCPE_OK;
The typewriter output is an asynchronous streaming output device. That is,
it can never cause a channel rate error; if no data is available, it waits.
Typewriter output may be stalled, if the device is connected to a Telnet
connection, so the output routine must be able to try output repeatedly.
*/
t_stat tto (uint32 fnc, uint32 inst, uint32 *dat)
@@ -548,11 +557,15 @@ switch (fnc) { /* case function */
new_ch = I_GETEOCH (inst); /* get new chan */
if (new_ch != tto_dib.chan) /* inv conn? err */
return SCPE_IERR;
tto_ldr = (inst & CHC_NLDR)? 0: 1; /* leader? */
tto_retry = 0; /* no retry */
xfr_req = xfr_req & ~XFR_TTO; /* clr xfr flag */
sim_activate (&tto_unit, tto_unit.wait); /* activate */
break;
case IO_DISC: /* disconnect */
tto_ldr = 0; /* clr state */
tto_retry = 0;
xfr_req = xfr_req & ~XFR_TTO; /* clr xfr flag */
sim_cancel (&tto_unit); /* deactivate unit */
break;
@@ -561,7 +574,7 @@ switch (fnc) { /* case function */
xfr_req = xfr_req & ~XFR_TTO; /* clr xfr flag */
tto_unit.buf = (*dat) & 077; /* save data */
sim_activate (&tto_unit, tto_unit.wait); /* activate */
break;
return tto_out (tto_unit.buf); /* write the data */
case IO_WREOR: /* write eor */
break;
@@ -574,29 +587,47 @@ switch (fnc) { /* case function */
return SCPE_OK;
}
/* Unit service */
/* Unit service - handle leader, retry */
t_stat tto_svc (UNIT *uptr)
{
if (tto_ldr != 0) { /* need leader? */
sim_putchar (0); /* output, no stall */
tto_ldr = 0; /* no more leader */
}
if (tto_retry != 0) /* retry? */
tto_out (uptr->buf); /* try again, could stall */
if (tto_retry == 0) /* now no retry? */
chan_set_ordy (tto_dib.chan); /* tto ready */
return SCPE_OK;
}
t_stat tto_out (int32 dat)
{
int32 asc;
t_stat r;
if (uptr->buf == TT_CR) /* control chars? */
tto_retry = 0; /* assume no retry */
if (dat == TT_CR) /* control chars? */
asc = '\r';
else if (uptr->buf == TT_BS)
else if (dat == TT_BS)
asc = '\b';
else if (uptr->buf == TT_TB)
else if (dat == TT_TB)
asc = '\t';
else asc = sds_to_ascii(uptr->buf); /* translate */
if ((r = sim_putchar_s (asc)) != SCPE_OK) { /* output; error? */
sim_activate (uptr, uptr->wait); /* retry */
return ((r == SCPE_STALL)? SCPE_OK: r); /* !stall? report */
else asc = sds_to_ascii (dat); /* translate */
r = sim_putchar_s (asc); /* output */
if (r == SCPE_STALL) { /* stall? */
tto_retry = 1;
sim_activate (&tto_unit, tto_unit.wait); /* retry */
return SCPE_OK;
}
uptr->pos = uptr->pos + 1; /* inc position */
if (r != SCPE_OK) /* error? */
return r;
tto_unit.pos = tto_unit.pos + 1; /* inc position */
chan_set_ordy (tto_dib.chan); /* tto rdy */
if (asc == '\r') { /* CR? */
sim_putchar ('\n'); /* add lf */
uptr->pos = uptr->pos + 1; /* inc position */
sim_putchar ('\n'); /* add lf, no stall */
tto_unit.pos = tto_unit.pos + 1; /* inc position */
}
return SCPE_OK;
}
@@ -607,6 +638,8 @@ t_stat tto_reset (DEVICE *dptr)
{
chan_disc (tto_dib.chan); /* disconnect */
tto_unit.buf = 0; /* clear state */
tto_ldr = 0;
tto_retry = 0;
xfr_req = xfr_req & ~XFR_TTO; /* clr xfr flag */
sim_cancel (&tto_unit); /* deactivate unit */
return SCPE_OK;

View File

@@ -1,6 +1,6 @@
/* sds_sys.c: SDS 940 simulator interface
Copyright (c) 2001-2016, Robert M Supnik
Copyright (c) 2001-2020, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@@ -23,6 +23,7 @@
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
01-Nov-20 RMS Fixed sds930-to-ascii entry 060 (Ken Rector)
05-May-16 RMS Fixed ascii-to-sds940 data (Mark Pizzolato)
19-Mar-12 RMS Fixed declarations of CCT arrays (Mark Pizzolato)
*/
@@ -35,6 +36,8 @@ extern DEVICE cpu_dev;
extern DEVICE chan_dev;
extern DEVICE ptr_dev;
extern DEVICE ptp_dev;
extern DEVICE cr_dev;
extern DEVICE cp_dev;
extern DEVICE tti_dev;
extern DEVICE tto_dev;
extern DEVICE lpt_dev;
@@ -73,6 +76,8 @@ DEVICE *sim_devices[] = {
&tti_dev,
&tto_dev,
&lpt_dev,
&cr_dev,
&cp_dev,
&rtc_dev,
&drm_dev,
&rad_dev,
@@ -83,7 +88,7 @@ DEVICE *sim_devices[] = {
NULL
};
const char *sim_stop_messages[] = {
const char *sim_stop_messages[SCPE_BASE] = {
"Unknown error",
"IO device not ready",
"HALT instruction",
@@ -114,7 +119,7 @@ const int8 sds930_to_ascii[64] = {
'H', 'I', '?', '.', ')', '[', '<', '@', /* 37 = stop code */
'-', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', '!', '$', '*', ']', ';', '^', /* 57 = triangle */
'_', '/', 'S', 'T', 'U', 'V', 'W', 'X',
' ', '/', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', '?', ',', '(', '~', '\\', '#' /* 72 = rec mark */
}; /* 75 = squiggle, 77 = del */
@@ -196,7 +201,8 @@ int32 col, rpt, ptr, mask, cctbuf[CCT_LNT];
t_stat r;
extern int32 lpt_ccl, lpt_ccp;
extern uint8 lpt_cct[CCT_LNT];
char *cptr, cbuf[CBUFSIZE], gbuf[CBUFSIZE];
CONST char *cptr;
char cbuf[CBUFSIZE], gbuf[CBUFSIZE];
ptr = 0;
for ( ; (cptr = fgets (cbuf, CBUFSIZE, fileref)) != NULL; ) { /* until eof */
@@ -251,7 +257,7 @@ for (i = wd = 0; i < 4; ) {
return wd;
}
t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
t_stat sim_load (FILE *fileref, CONST char *cptr, CONST char *fnam, int flag)
{
int32 i, wd, buf[8];
int32 ldr = 1;
@@ -491,7 +497,8 @@ return;
}
/* Convert from SDS internal character code to ASCII depending upon cpu mode. */
int8 sds_to_ascii(int8 ch)
int8 sds_to_ascii (int8 ch)
{
ch &= 077;
if (cpu_mode == NML_MODE)
@@ -501,7 +508,8 @@ int8 sds_to_ascii(int8 ch)
}
/* Convert from ASCII to SDS internal character code depending upon cpu mode. */
int8 ascii_to_sds(int8 ch)
int8 ascii_to_sds (int8 ch)
{
ch &= 0177;
if (cpu_mode == NML_MODE)
@@ -632,9 +640,10 @@ return SCPE_ARG;
cptr = updated pointer to input string
*/
char *get_tag (char *cptr, t_value *tag)
CONST char *get_tag (CONST char *cptr, t_value *tag)
{
char *tptr, gbuf[CBUFSIZE];
CONST char *tptr;
char gbuf[CBUFSIZE];
t_stat r;
tptr = get_glyph (cptr, gbuf, 0); /* get next field */
@@ -657,20 +666,17 @@ return cptr; /* no change */
status = error status
*/
t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
t_stat parse_sym (CONST char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
{
int32 i, j, k, ch;
t_value d, tag;
t_stat r;
char gbuf[CBUFSIZE];
char gbuf[CBUFSIZE], cbuf[2*CBUFSIZE];
while (isspace (*cptr)) cptr++;
for (i = 1; (i < 4) && (cptr[i] != 0); i++) {
if (cptr[i] == 0) {
for (j = i + 1; j <= 4; j++)
cptr[j] = 0;
}
}
memset (cbuf, '\0', sizeof(cbuf));
strncpy (cbuf, cptr, sizeof(cbuf)-5);
cptr = cbuf;
if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */
if (cptr[0] == 0) /* must have 1 char */
return SCPE_ARG;