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:
committed by
Mark Pizzolato
parent
541d1c3c90
commit
79878eb6ed
318
SDS/sds_cp.c
Normal file
318
SDS/sds_cp.c
Normal 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;
|
||||
}
|
||||
154
SDS/sds_cpu.c
154
SDS/sds_cpu.c
@@ -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
381
SDS/sds_cr.c
Normal 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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
75
SDS/sds_io.c
75
SDS/sds_io.c
@@ -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]);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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? */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user