mirror of
https://github.com/rcornwell/sims.git
synced 2026-02-04 07:33:39 +00:00
ICL1900: Major update, will now boot E4BM from paper tape.
This commit is contained in:
@@ -1,36 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define N 24
|
||||
#define B0 (1<<N)
|
||||
#define B1 (1<<(N-1))
|
||||
#define M0 ((1<<(N))-1)
|
||||
main(int argc, char *argv[]) {
|
||||
int n = N;
|
||||
int a = 0;
|
||||
int m = atoi(argv[2]);
|
||||
int q = atoi(argv[1]);
|
||||
|
||||
printf("0: n=%d B0=%08o B1=%08o M0=%08o\n", n, B0, B1, M0);
|
||||
do {
|
||||
a <<= 1;
|
||||
q <<= 1;
|
||||
if (q & B0)
|
||||
a |= 1;
|
||||
if (a & B0) {
|
||||
a = a+m;
|
||||
} else {
|
||||
a = a + (m^ M0) + 1;
|
||||
}
|
||||
a &= M0;
|
||||
q &= M0;
|
||||
if ((a& B1) == 0)
|
||||
q|= 1;
|
||||
printf("1: n=%d m=%08o a=%08o q=%08o\n", n, m, a, q);
|
||||
n--;
|
||||
} while (n != 0);
|
||||
if (a & B1)
|
||||
a = a+m;
|
||||
printf("2: n=%d m=%08o a=%08o q=%08o\n", n, m, a, q);
|
||||
}
|
||||
|
||||
@@ -37,8 +37,11 @@
|
||||
#define UNIT_MSIZE (7 << UNIT_V_MSIZE)
|
||||
#define MEMAMOUNT(x) (x << UNIT_V_MSIZE)
|
||||
#define UNIT_V_MODEL (UNIT_V_MSIZE + 4)
|
||||
#define UNIT_MODEL (0x1f << UNIT_V_MODEL)
|
||||
#define UNIT_MODEL (0x3f << UNIT_V_MODEL)
|
||||
#define MODEL(x) (UNIT_MODEL & (x << UNIT_V_MODEL))
|
||||
#define UNIT_FLOAT (0x40 << UNIT_V_MODEL)
|
||||
#define UNIT_MULT (0x100 << UNIT_V_MODEL)
|
||||
#define OPTION_MASK (0x140 << UNIT_V_MODEL)
|
||||
|
||||
|
||||
#define TMR_RTC 1
|
||||
@@ -133,6 +136,7 @@ uint32 SR3; /* Typewriter O/P */
|
||||
uint32 SR64; /* Interrupt status */
|
||||
uint32 SR65; /* Interrupt status */
|
||||
uint32 adrmask; /* Mask for addressing memory */
|
||||
uint8 loading; /* Loading bootstrap */
|
||||
|
||||
|
||||
struct InstHistory
|
||||
@@ -164,6 +168,12 @@ t_stat cpu_set_size(UNIT * uptr, int32 val, CONST char *cptr,
|
||||
void *desc);
|
||||
t_stat cpu_show_size(FILE * st, UNIT * uptr, int32 val,
|
||||
CONST void *desc);
|
||||
t_stat cpu_set_model(UNIT * uptr, int32 val, CONST char *cptr,
|
||||
void *desc);
|
||||
t_stat cpu_set_float(UNIT * uptr, int32 val, CONST char *cptr,
|
||||
void *desc);
|
||||
t_stat cpu_set_mult(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 cpu_set_hist(UNIT * uptr, int32 val, CONST char *cptr,
|
||||
@@ -176,6 +186,49 @@ int32 rtc_tps = 60 ;
|
||||
int32 tmxr_poll = 10000;
|
||||
|
||||
|
||||
|
||||
CPUMOD cpu_modtab[] = {
|
||||
{ "1901", MOD1, TYPE_A1|FLOAT_STD|FLOAT_OPT|MULT_OPT|SV, 0, 10 },
|
||||
{ "1901A", MOD1A, TYPE_A1|FLOAT_STD|FLOAT_OPT|MULT_OPT|SV, 0, 10 },
|
||||
{ "1901S", MOD1S, TYPE_A1|FLOAT_STD|FLOAT_OPT|MULT_OPT|SV, 0, 10 },
|
||||
{ "1901T", MOD1T, TYPE_A1|FLOAT_STD|FLOAT_OPT|MULT_OPT|SV, 0, 10 },
|
||||
{ "1902", MOD2, TYPE_A1|FLOAT_STD|FLOAT_OPT|MULT|SV, 0, 10 },
|
||||
{ "1902A", MOD2A, TYPE_C2|FLOAT_STD|FLOAT_OPT|MULT|SV, 0, 10 },
|
||||
{ "1902S", MOD2S, TYPE_C1|FLOAT_STD|FLOAT_OPT|MULT|SV, EXT_IO, 10 },
|
||||
{ "1902T", MOD2T, TYPE_C1|FLOAT_STD|FLOAT_OPT|MULT|SV, EXT_IO, 10 },
|
||||
{ "1903", MOD3, TYPE_A2|FLOAT_STD|FLOAT_OPT|MULT_OPT|SV, 0, 10 },
|
||||
{ "1903A", MOD3A, TYPE_C2|FLOAT_STD|FLOAT_OPT|MULT|SV, 0, 10 },
|
||||
{ "1903S", MOD3S, TYPE_C2|FLOAT_STD|FLOAT_OPT|MULT_OPT|SV, EXT_IO, 10 },
|
||||
{ "1903T", MOD3T, TYPE_A2|FLOAT_STD|FLOAT_OPT|MULT_OPT|WG, 0, 10 },
|
||||
{ "1904", MOD4, TYPE_B2|FLOAT_OPT|MULT|WG, 0, 1 },
|
||||
{ "1904A", MOD4A, TYPE_C2|FLOAT_OPT|MULT|WG, EXT_IO, 10 },
|
||||
{ "1904E", MOD4E, TYPE_C2|FLOAT_OPT|MULT|WG, EXT_IO, 10 },
|
||||
{ "1904F", MOD4F, TYPE_C2|FLOAT_OPT|MULT|WG, EXT_IO, 10 },
|
||||
{ "1904S", MOD4S, TYPE_C2|FLOAT_OPT|MULT|WG, EXT_IO, 10 },
|
||||
{ "1905", MOD5, TYPE_A2|FLOAT|MULT|WG, 0, 1 },
|
||||
{ "1905A", MOD5A, TYPE_A2|FLOAT|MULT|WG, 0, 10 },
|
||||
{ "1905E", MOD5E, TYPE_C2|FLOAT|MULT|WG, EXT_IO, 10 },
|
||||
{ "1905F", MOD5F, TYPE_C2|FLOAT|MULT|WG, EXT_IO, 10 },
|
||||
{ "1905S", MOD5S, TYPE_C2|FLOAT|MULT|WG, EXT_IO, 10 },
|
||||
{ "1906", MOD6, TYPE_A2|FLOAT|MULT|WG, 0, 10 },
|
||||
{ "1906A", MOD6A, TYPE_A2|FLOAT|MULT|WG, 0, 100 },
|
||||
{ "1906E", MOD6E, TYPE_C2|FLOAT|MULT|WG, EXT_IO, 10 },
|
||||
{ "1906F", MOD6F, TYPE_C2|FLOAT|MULT|WG, EXT_IO, 10 },
|
||||
{ "1906S", MOD6S, TYPE_C2|FLOAT|MULT|WG, EXT_IO, 100 },
|
||||
{ "1907", MOD7, TYPE_A2|FLOAT|MULT|WG, 0, 10 },
|
||||
{ "1907A", MOD7A, TYPE_A2|FLOAT|MULT|WG, 0, 10 },
|
||||
{ "1907E", MOD7E, TYPE_C2|FLOAT|MULT|WG, EXT_IO, 10 },
|
||||
{ "1907F", MOD7F, TYPE_C2|FLOAT|MULT|WG, EXT_IO, 10 },
|
||||
{ "1907S", MOD7S, TYPE_C2|FLOAT|MULT|WG, EXT_IO, 10 },
|
||||
{ "1908", MOD8, TYPE_A2|FLOAT|MULT|WG, 0, 10 },
|
||||
{ "1908A", MOD8A, TYPE_A2|FLOAT|MULT|WG, 0, 10 },
|
||||
{ "1908S", MOD8S, TYPE_C2|FLOAT|MULT|WG, EXT_IO, 10 },
|
||||
{ "1909", MOD9, TYPE_C2|FLOAT|MULT|WG, EXT_IO, 1 },
|
||||
{ NULL, 0, 0, 0, 0},
|
||||
};
|
||||
|
||||
uint16 cpu_flags = TYPE_C2|FLOAT_OPT|MULT;
|
||||
uint8 io_flags = EXT_IO;
|
||||
|
||||
/* CPU data structures
|
||||
|
||||
@@ -186,7 +239,7 @@ int32 tmxr_poll = 10000;
|
||||
*/
|
||||
|
||||
UNIT cpu_unit[] =
|
||||
{{ UDATA(rtc_srv, MEMAMOUNT(7)|UNIT_IDLE, MAXMEMSIZE ), 16667 }};
|
||||
{{ UDATA(rtc_srv, MODEL(MOD4A)|UNIT_MULT|MEMAMOUNT(7)|UNIT_IDLE, MAXMEMSIZE ), 16667 }};
|
||||
|
||||
REG cpu_reg[] = {
|
||||
{ORDATAD(C, RC, 22, "Instruction code"), REG_FIT},
|
||||
@@ -212,37 +265,41 @@ MTAB cpu_mod[] = {
|
||||
{UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(127), NULL, "512K", &cpu_set_size},
|
||||
{UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(254), NULL, "1024K", &cpu_set_size},
|
||||
/* Stevenage */
|
||||
{UNIT_MODEL, MODEL(MOD1), "1901", "1901", NULL, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD1A), "1901A", "1901A", NULL, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD1S), "1901S", "1901S", NULL, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD1T), "1901T", "1901T", NULL, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD2), "1902", "1902", NULL, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD2A), "1902A", "1902A", NULL, NULL, NULL}, /* C1 */
|
||||
{UNIT_MODEL, MODEL(MOD2S), "1902S", "1902S", NULL, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD2T), "1902T", "1902T", NULL, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD3), "1903", "1903", NULL, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD3A), "1903A", "1903A", NULL, NULL, NULL}, /* C1 */
|
||||
{UNIT_MODEL, MODEL(MOD3S), "1903S", "1903S", NULL, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD1), "1901", "1901", &cpu_set_model, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD1A), "1901A", "1901A", &cpu_set_model, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD1S), "1901S", "1901S", &cpu_set_model, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD1T), "1901T", "1901T", &cpu_set_model, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD2), "1902", "1902", &cpu_set_model, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD2A), "1902A", "1902A", &cpu_set_model, NULL, NULL}, /* C1 */
|
||||
{UNIT_MODEL, MODEL(MOD2S), "1902S", "1902S", &cpu_set_model, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD2T), "1902T", "1902T", &cpu_set_model, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD3), "1903", "1903", &cpu_set_model, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD3A), "1903A", "1903A", &cpu_set_model, NULL, NULL}, /* C1 */
|
||||
{UNIT_MODEL, MODEL(MOD3S), "1903S", "1903S", &cpu_set_model, NULL, NULL},
|
||||
/* West Gorton */
|
||||
{UNIT_MODEL, MODEL(MOD3T), "1903T", "1903T", NULL, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD4), "1904", "1904", NULL, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD4A), "1904A", "1904A", NULL, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD4E), "1904E", "1904E", NULL, NULL, NULL}, /* C */
|
||||
{UNIT_MODEL, MODEL(MOD4F), "1904F", "1904F", NULL, NULL, NULL}, /* C */
|
||||
{UNIT_MODEL, MODEL(MOD4S), "1904S", "1904S", NULL, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD5), "1905", "1905", NULL, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD5E), "1905E", "1905E", NULL, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD5F), "1905F", "1905F", NULL, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD5S), "1905S", "1905S", NULL, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD6), "1906", "1906", NULL, NULL, NULL}, /* C */
|
||||
{UNIT_MODEL, MODEL(MOD6A), "1906A", "1906A", NULL, NULL, NULL}, /* C */
|
||||
{UNIT_MODEL, MODEL(MOD6E), "1906E", "1906E", NULL, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD6F), "1906F", "1906F", NULL, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD7), "1907", "1907", NULL, NULL, NULL}, /* C */
|
||||
{UNIT_MODEL, MODEL(MOD7E), "1907E", "1907E", NULL, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD7F), "1907F", "1907F", NULL, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD8A), "1908A", "1908A", NULL, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD9), "1909", "1909", NULL, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD3T), "1903T", "1903T", &cpu_set_model, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD4), "1904", "1904", &cpu_set_model, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD4A), "1904A", "1904A", &cpu_set_model, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD4E), "1904E", "1904E", &cpu_set_model, NULL, NULL}, /* C */
|
||||
{UNIT_MODEL, MODEL(MOD4F), "1904F", "1904F", &cpu_set_model, NULL, NULL}, /* C */
|
||||
{UNIT_MODEL, MODEL(MOD4S), "1904S", "1904S", &cpu_set_model, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD5), "1905", "1905", &cpu_set_model, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD5E), "1905E", "1905E", &cpu_set_model, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD5F), "1905F", "1905F", &cpu_set_model, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD5S), "1905S", "1905S", &cpu_set_model, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD6), "1906", "1906", &cpu_set_model, NULL, NULL}, /* C */
|
||||
{UNIT_MODEL, MODEL(MOD6A), "1906A", "1906A", &cpu_set_model, NULL, NULL}, /* C */
|
||||
{UNIT_MODEL, MODEL(MOD6E), "1906E", "1906E", &cpu_set_model, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD6F), "1906F", "1906F", &cpu_set_model, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD7), "1907", "1907", &cpu_set_model, NULL, NULL}, /* C */
|
||||
{UNIT_MODEL, MODEL(MOD7E), "1907E", "1907E", &cpu_set_model, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD7F), "1907F", "1907F", &cpu_set_model, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD8A), "1908A", "1908A", &cpu_set_model, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD9), "1909", "1909", &cpu_set_model, NULL, NULL},
|
||||
{UNIT_FLOAT, 0, "NOFLOAT", "NOFLOAT", &cpu_set_float, NULL, NULL},
|
||||
{UNIT_FLOAT, UNIT_FLOAT, "FLOAT", "FLOAT", &cpu_set_float, NULL, NULL},
|
||||
{UNIT_MULT, 0, "NOMULT", "NOMULT", &cpu_set_mult, NULL, NULL},
|
||||
{UNIT_MULT, UNIT_MULT, "MULT", "MULT", &cpu_set_mult, NULL, NULL},
|
||||
{MTAB_VDV, 0, "MEMORY", NULL, NULL, &cpu_show_size},
|
||||
{MTAB_XTD|MTAB_VDV, 0, "IDLE", "IDLE", &sim_set_idle, &sim_show_idle },
|
||||
{MTAB_XTD|MTAB_VDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL },
|
||||
@@ -352,10 +409,10 @@ sim_instr(void)
|
||||
int e1,e2; /* Temp for exponents */
|
||||
int f; /* Used to hold flags */
|
||||
|
||||
reason = 0;
|
||||
adrmask = (Mode & AM22) ? M22 : M15;
|
||||
reason = chan_set_devs();
|
||||
|
||||
while (reason == 0) { /* loop until halted */
|
||||
while (reason == SCPE_OK) { /* loop until halted */
|
||||
if (sim_interval <= 0) { /* event queue? */
|
||||
reason = sim_process_event();
|
||||
if (reason != SCPE_OK) {
|
||||
@@ -370,27 +427,51 @@ sim_instr(void)
|
||||
}
|
||||
}
|
||||
|
||||
while (loading) { /* event queue? */
|
||||
reason = sim_process_event();
|
||||
if (reason != SCPE_OK) {
|
||||
break; /* process */
|
||||
}
|
||||
if ((SR64 | SR65) != 0) {
|
||||
loading = 0;
|
||||
exe_mode = 1;
|
||||
RC = 020;
|
||||
}
|
||||
}
|
||||
|
||||
intr:
|
||||
if (!exe_mode && (SR64 | SR65) != 0) {
|
||||
exe_mode = 1;
|
||||
loading = 0;
|
||||
/* Store registers */
|
||||
Mem_write(RD+13, &facch, 0); /* Save F.P.U. */
|
||||
Mem_write(RD+12, &faccl, 0);
|
||||
RA = 0; /* Build ZSTAT */
|
||||
if (Zero)
|
||||
RA |= B3;
|
||||
if (OPIP | PIP)
|
||||
RA |= B2;
|
||||
if (cpu_flags & SV) {
|
||||
Mem_read(RD+9, &RA, 0);
|
||||
RA &= 077777;
|
||||
RA |= ((Mode|DATUM) << 16);
|
||||
if (Mode & DATUM)
|
||||
RA |= 1 << 16;
|
||||
if (BCarry)
|
||||
RA |= B1;
|
||||
} else {
|
||||
if (Zero)
|
||||
RA |= B3;
|
||||
if (OPIP | PIP)
|
||||
RA |= B2;
|
||||
}
|
||||
Mem_write(RD+9, &RA, 0);
|
||||
RA = RC & adrmask;
|
||||
if (BV)
|
||||
RA |= B0;
|
||||
if (BCarry)
|
||||
RA |= B1;
|
||||
#if 0
|
||||
if ((Mode & AM22) == 0 && Zero)
|
||||
RA |= B8;
|
||||
#endif
|
||||
if (io_flags & EXT_IO) {
|
||||
if (BCarry)
|
||||
RA |= B1;
|
||||
} else {
|
||||
if (Zero)
|
||||
RA |= B8;
|
||||
}
|
||||
Mem_write(RD+8, &RA, 0);
|
||||
for (n = 0; n < 8; n++)
|
||||
Mem_write(RD+n, &XR[n], 0);
|
||||
@@ -635,10 +716,9 @@ obey:
|
||||
break;
|
||||
|
||||
case OP_STOZ: /* Store Zero */
|
||||
#if 0 /* Stevenage Machines */
|
||||
if (exe_mode)
|
||||
/* Stevenage Machines */
|
||||
if ((cpu_flags & SV) != 0 && exe_mode)
|
||||
XR[RX] = RA;
|
||||
#endif
|
||||
RB = 0;
|
||||
BCarry = 0;
|
||||
if (Mem_write(RS, &RB, 1)) {
|
||||
@@ -688,6 +768,8 @@ obey:
|
||||
case OP_MPY: /* Multiply */
|
||||
case OP_MPR: /* Multiply and Round */
|
||||
case OP_MPA: /* Multiply and Accumulate */
|
||||
if ((cpu_flags & MULT) == 0)
|
||||
goto voluntary;
|
||||
if (RA == B0 && RB == B0) {
|
||||
if (RF != OP_MPA || (XR[(RX + 1) & 7] & B0) == 0) {
|
||||
BV = 1;
|
||||
@@ -796,6 +878,8 @@ obey:
|
||||
case OP_DVD: /* Unrounded Double Length Divide */
|
||||
case OP_DVR: /* Rounded Double Length Divide */
|
||||
case OP_DVS: /* Single Length Divide */
|
||||
if ((cpu_flags & MULT) == 0)
|
||||
goto voluntary;
|
||||
RP = XR[(RX+1) & 7]; /* VR */
|
||||
RA = RB; /* Divisor to RA */
|
||||
RB = XR[RX]; /* Dividend to RB/RP */
|
||||
@@ -1003,7 +1087,7 @@ dvd2:
|
||||
case OP_BCHX: /* Branch on Character Indexing */
|
||||
case OP_BCHX1:
|
||||
BCarry = 0;
|
||||
RA += 020000000;
|
||||
RA += B1;
|
||||
n = (RA & BM1) != 0;
|
||||
if (Mode & AM22) {
|
||||
RA = ((RA + n) & M22) | (RA & CMASK);
|
||||
@@ -1083,7 +1167,7 @@ branch:
|
||||
M[262] = (temp & ~ 0177) + ((temp + 1) & 0177);
|
||||
}
|
||||
RC = RB;
|
||||
break;
|
||||
break;
|
||||
|
||||
case OP_EXIT: /* Exit Subroutine */
|
||||
case OP_EXIT1:
|
||||
@@ -1172,6 +1256,8 @@ branch:
|
||||
/* B with Floating or C */
|
||||
case OP_BFP: /* Branch state of floating point accumulator */
|
||||
case OP_BFP1:
|
||||
if ((cpu_flags & FLOAT) == 0)
|
||||
goto voluntary;
|
||||
switch (RX & 06) {
|
||||
case 0: n = (faccl | facch) != 0; break;
|
||||
case 2: n = (faccl & B0) != 0; break;
|
||||
@@ -1320,6 +1406,8 @@ branch:
|
||||
|
||||
case OP_NORM: /* Nomarlize Single -2 +FP */
|
||||
case OP_NORMD: /* Normalize Double -2 +FP */
|
||||
if ((cpu_flags & NORM_OP) == 0)
|
||||
goto voluntary;
|
||||
RT = RB;
|
||||
RB = (RF & 1) ? XR[(RX+1) & 07] & M23 : 0;
|
||||
//fprintf(stderr, "Norm0: %08o %08o %08o\n\r", RA, RB, RT);
|
||||
@@ -1394,110 +1482,125 @@ norm1:
|
||||
|
||||
/* Not on A*/
|
||||
case OP_MVCH: /* Move Characters - BC */
|
||||
RK = RB;
|
||||
RB = XR[(RX+1) & 07];
|
||||
do {
|
||||
if (Mem_read(RA, &RT, 1)) {
|
||||
goto intr;
|
||||
}
|
||||
m = (RA >> 22) & 3;
|
||||
RT = (RT >> (6 * (3 - m))) & 077;
|
||||
if (Mem_read(RB, &RS, 1)) {
|
||||
goto intr;
|
||||
}
|
||||
m = (RB >> 22) & 3;
|
||||
m = 6 * (3 - m);
|
||||
RS &= ~(077 << m);
|
||||
RS |= (RT & 077) << m;
|
||||
if (Mem_write(RB, &RS, 1)) {
|
||||
goto intr;
|
||||
}
|
||||
RA += 020000000;
|
||||
m = (RA & BM1) != 0;
|
||||
RA = ((RA + m) & M22) | (RA & CMASK);
|
||||
RB += 020000000;
|
||||
m = (RB & BM1) != 0;
|
||||
RB = ((RB + m) & M22) | (RB & CMASK);
|
||||
RK = (RK - 1) & 0777;
|
||||
} while (RK != 0);
|
||||
XR[RX] = RA;
|
||||
XR[(RX+1)&07] = RB;
|
||||
break;
|
||||
if (CPU_TYPE < TYPE_B1)
|
||||
goto voluntary;
|
||||
RK = RB;
|
||||
RB = XR[(RX+1) & 07];
|
||||
do {
|
||||
if (Mem_read(RA, &RT, 1)) {
|
||||
goto intr;
|
||||
}
|
||||
m = (RA >> 22) & 3;
|
||||
RT = (RT >> (6 * (3 - m))) & 077;
|
||||
if (Mem_read(RB, &RS, 1)) {
|
||||
goto intr;
|
||||
}
|
||||
m = (RB >> 22) & 3;
|
||||
m = 6 * (3 - m);
|
||||
RS &= ~(077 << m);
|
||||
RS |= (RT & 077) << m;
|
||||
if (Mem_write(RB, &RS, 1)) {
|
||||
goto intr;
|
||||
}
|
||||
RA += 020000000;
|
||||
m = (RA & BM1) != 0;
|
||||
RA = ((RA + m) & M22) | (RA & CMASK);
|
||||
RB += 020000000;
|
||||
m = (RB & BM1) != 0;
|
||||
RB = ((RB + m) & M22) | (RB & CMASK);
|
||||
RK = (RK - 1) & 0777;
|
||||
} while (RK != 0);
|
||||
XR[RX] = RA;
|
||||
XR[(RX+1)&07] = RB;
|
||||
break;
|
||||
|
||||
/* Not on A*/
|
||||
case OP_SMO: /* Supplementary Modifier - BC */
|
||||
if (OPIP) { /* Error */
|
||||
SR64 |= B1;
|
||||
goto intr;
|
||||
}
|
||||
if (Mem_read(RS, &RP, 1)) {
|
||||
goto intr;
|
||||
}
|
||||
PIP = 1;
|
||||
break;
|
||||
if (CPU_TYPE < TYPE_B1)
|
||||
goto voluntary;
|
||||
if (OPIP) { /* Error */
|
||||
SR64 |= B1;
|
||||
goto intr;
|
||||
}
|
||||
if (Mem_read(RS, &RP, 1)) {
|
||||
goto intr;
|
||||
}
|
||||
PIP = 1;
|
||||
break;
|
||||
|
||||
case OP_NULL: /* No Operation */
|
||||
if (!exe_mode && RX == 7 && (Mode & 7) > 0 && (Mode & 7) < 5)
|
||||
SR64 |= B2;
|
||||
break;
|
||||
case OP_NULL: /* No Operation */
|
||||
if (!exe_mode && RX == 7 && (Mode & 7) > 0 && (Mode & 7) < 5)
|
||||
SR64 |= B2;
|
||||
break;
|
||||
|
||||
case OP_LDCT: /* Load Count */
|
||||
RA = CNTMSK & (RB << 15);
|
||||
XR[RX] = RA;
|
||||
break;
|
||||
case OP_LDCT: /* Load Count */
|
||||
RA = CNTMSK & (RB << 15);
|
||||
XR[RX] = RA;
|
||||
break;
|
||||
|
||||
case OP_MODE: /* Set Mode */
|
||||
#if 0 /* Stevenage Machines */
|
||||
if (exe_mode && RX == 1)
|
||||
temp = RB; /* Set interrupt enable mode */
|
||||
else
|
||||
/* On Stevenage Machines 002 -> 020 Add Datum */
|
||||
/* On Stevenage Machines 004 -> 000 unused */
|
||||
/* On Stevenage Machines 010 -> 000 unused */
|
||||
/* On Stevenage Machines 020 -> Extended store mode */
|
||||
/* On Stevenage Machines 040 -> 000 unused */
|
||||
/* On Stevenage Machines 0100 -> Carry */
|
||||
#endif
|
||||
if (exe_mode)
|
||||
Mode = RB & 076;
|
||||
Zero = RB & 1;
|
||||
adrmask = (Mode & AM22) ? M22 : M15;
|
||||
break;
|
||||
/* Stevenage Machines */
|
||||
if ((cpu_flags & SV) != 0 && exe_mode) {
|
||||
if (RX == 0) {
|
||||
/* Remap modes settings */
|
||||
Mode = 0;
|
||||
if (RB & 02)
|
||||
Mode |= DATUM;
|
||||
if (RB & 020)
|
||||
Mode |= AM22;
|
||||
if (RB & 0100)
|
||||
Mode |= EJM;
|
||||
if (RB & 0200)
|
||||
BCarry = 1;
|
||||
} else if (RX == 1) {
|
||||
temp = RB; /* Set interrupt enable mode */
|
||||
}
|
||||
} else if (exe_mode)
|
||||
Mode = RB & 076;
|
||||
Zero = RB & 1;
|
||||
adrmask = (Mode & AM22) ? M22 : M15;
|
||||
break;
|
||||
|
||||
case OP_MOVE: /* Copy N words */
|
||||
RK = RB;
|
||||
RA &= adrmask;
|
||||
RB = XR[(RX+1) & 07] & adrmask;
|
||||
do {
|
||||
if (Mem_read(RA, &RT, 1)) {
|
||||
goto intr;
|
||||
}
|
||||
if (Mem_write(RB, &RT, 1)) {
|
||||
goto intr;
|
||||
}
|
||||
RA++;
|
||||
RB++;
|
||||
RK = (RK - 1) & 0777;
|
||||
} while (RK != 0);
|
||||
break;
|
||||
case OP_MOVE: /* Copy N words */
|
||||
if (CPU_TYPE < TYPE_B1)
|
||||
goto voluntary;
|
||||
RK = RB;
|
||||
RA &= adrmask;
|
||||
RB = XR[(RX+1) & 07] & adrmask;
|
||||
do {
|
||||
if (Mem_read(RA, &RT, 1)) {
|
||||
goto intr;
|
||||
}
|
||||
if (Mem_write(RB, &RT, 1)) {
|
||||
goto intr;
|
||||
}
|
||||
RA++;
|
||||
RB++;
|
||||
RK = (RK - 1) & 0777;
|
||||
} while (RK != 0);
|
||||
break;
|
||||
|
||||
case OP_SUM: /* Sum N words */
|
||||
RK = RB;
|
||||
RA = 0;
|
||||
RB = XR[(RX+1) & 07] & adrmask;
|
||||
do {
|
||||
if (Mem_read(RB, &RT, 1)) {
|
||||
goto intr;
|
||||
}
|
||||
RA = (RA + RT) & FMASK;
|
||||
RB++;
|
||||
RK = (RK - 1) & 0777;
|
||||
} while (RK != 0);
|
||||
XR[RX] = RA;
|
||||
break;
|
||||
case OP_SUM: /* Sum N words */
|
||||
if (CPU_TYPE < TYPE_B1)
|
||||
goto voluntary;
|
||||
RK = RB;
|
||||
RB = XR[(RX+1) & 07] & adrmask;
|
||||
RA = 0;
|
||||
do {
|
||||
if (Mem_read(RB, &RT, 1)) {
|
||||
goto intr;
|
||||
}
|
||||
RA = (RA + RT) & FMASK;
|
||||
RB++;
|
||||
RK = (RK - 1) & 0777;
|
||||
} while (RK != 0);
|
||||
XR[RX] = RA;
|
||||
break;
|
||||
|
||||
/* B or C with Floating Point */
|
||||
case OP_FLOAT: /* Convert Fixed to Float +FP */
|
||||
if ((cpu_flags & FLOAT) == 0)
|
||||
goto voluntary;
|
||||
if (Mem_read(RS, &RA, 1)) {
|
||||
goto intr;
|
||||
}
|
||||
@@ -1513,6 +1616,8 @@ norm1:
|
||||
RX = 0;
|
||||
goto fn;
|
||||
case OP_FIX: /* Convert Float to Fixed +FP */
|
||||
if ((cpu_flags & FLOAT) == 0)
|
||||
goto voluntary;
|
||||
RA = faccl;
|
||||
RB = facch & MMASK;
|
||||
e1 = 279 - (facch & M9);
|
||||
@@ -1557,6 +1662,8 @@ norm1:
|
||||
|
||||
case OP_FAD: /* Floating Point Add +FP */
|
||||
case OP_FSB: /* Floating Point Subtract +FP */
|
||||
if ((cpu_flags & FLOAT) == 0)
|
||||
goto voluntary;
|
||||
if (Mem_read(RS, &RA, 1)) { /* Read lower */
|
||||
goto intr;
|
||||
}
|
||||
@@ -1713,6 +1820,8 @@ fexp:
|
||||
break;
|
||||
|
||||
case OP_FMPY: /* Floating Point Multiply +FP */
|
||||
if ((cpu_flags & FLOAT) == 0)
|
||||
goto voluntary;
|
||||
if (Mem_read(RS, &RA, 1)) { /* Read lower */
|
||||
goto intr;
|
||||
}
|
||||
@@ -1847,6 +1956,8 @@ fexp:
|
||||
goto fn;
|
||||
|
||||
case OP_FDVD: /* Floating Point Divide +FP */
|
||||
if ((cpu_flags & FLOAT) == 0)
|
||||
goto voluntary;
|
||||
if (Mem_read(RS, &RA, 1)) { /* Read lower */
|
||||
goto intr;
|
||||
}
|
||||
@@ -1969,6 +2080,8 @@ fexp:
|
||||
goto fn;
|
||||
|
||||
case OP_LFP: /* Load Floating Point +FP */
|
||||
if ((cpu_flags & FLOAT) == 0)
|
||||
goto voluntary;
|
||||
if (RX & 1) {
|
||||
faccl = facch = fovr = 0;
|
||||
//fprintf(stderr, "LFPZ: %08o %08o %o\n\r", faccl, facch, RX);
|
||||
@@ -1989,6 +2102,8 @@ fexp:
|
||||
|
||||
case OP_SFP: /* Store Floating Point +FP */
|
||||
//fprintf(stderr, "SFP: %08o %08o %o\n\r", faccl, facch, fovr);
|
||||
if ((cpu_flags & FLOAT) == 0)
|
||||
goto voluntary;
|
||||
if (Mem_write(RB, &faccl, 1)) {
|
||||
goto intr;
|
||||
}
|
||||
@@ -2022,27 +2137,23 @@ fexp:
|
||||
if (exe_mode) {
|
||||
RA = 0;
|
||||
switch(RB) {
|
||||
case 0: /* Time of day clock */ break;
|
||||
case 1: RA = SR1; break;
|
||||
case 2: ctyi_cmd(0, &RA); break;
|
||||
case 3: ctyo_cmd(0, &RA); break;
|
||||
case 64: RA = SR64; SR64 &= 003777777; break;
|
||||
case 65: RA = SR65; break;
|
||||
default: if (RB < 64)
|
||||
chan_nsi_status(RB, &RA);
|
||||
break;
|
||||
}
|
||||
XR[RX] = RA;
|
||||
//fprintf(stderr, "RD SR %o %08o\n\r", RB, RA);
|
||||
break;
|
||||
}
|
||||
/* Fall through */
|
||||
case 0171: /* Write special register */
|
||||
if (exe_mode) {
|
||||
//fprintf(stderr, "WR SR %o %08o\n\r", RB, RA);
|
||||
RT = 0;
|
||||
switch(RB) {
|
||||
case 2: ctyi_cmd(RA, &RT); break;
|
||||
case 3: ctyo_cmd(RA, &RT); break;
|
||||
}
|
||||
XR[RX] = RT;
|
||||
|
||||
if (RB < 64)
|
||||
chan_nsi_cmd(RB, RA);
|
||||
break;
|
||||
}
|
||||
/* Fall through */
|
||||
@@ -2089,14 +2200,13 @@ fexp:
|
||||
/* Fall through */
|
||||
case 0174: /* Send control character to peripheral */
|
||||
if (exe_mode) {
|
||||
RT = RB;
|
||||
chan_send_cmd(RB, RA & 077, &RB);
|
||||
chan_send_cmd(RB, RA & 077, &RT);
|
||||
fprintf(stderr, "CMD %04o %04o %08o\n\r", RT, RB, RA);
|
||||
m = (m == 0) ? 3 : (XR[m] >> 22) & 3;
|
||||
m = 6 * (3 - m);
|
||||
RB = (RB & 077) << m;
|
||||
RT = (RT & 077) << m;
|
||||
RA &= ~(077 << m);
|
||||
RA |= RB;
|
||||
RA |= RT;
|
||||
XR[RX] = RA;
|
||||
break;
|
||||
}
|
||||
@@ -2170,6 +2280,7 @@ rtc_srv(UNIT * uptr)
|
||||
|
||||
t = sim_rtcn_calb(rtc_tps, TMR_RTC);
|
||||
sim_activate_after(uptr, 1000000/rtc_tps);
|
||||
SR64 |= B3;
|
||||
// tmxr_poll = t;
|
||||
return SCPE_OK;
|
||||
}
|
||||
@@ -2247,6 +2358,55 @@ cpu_set_size(UNIT * uptr, int32 val, CONST char *cptr, void *desc)
|
||||
M[i] = 0;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat
|
||||
cpu_set_model(UNIT * uptr, int32 val, CONST char *cptr, void *desc)
|
||||
{
|
||||
CPUMOD *ptr;
|
||||
|
||||
val >>= UNIT_V_MODEL;
|
||||
for(ptr = &cpu_modtab[0]; ptr->name != NULL; ptr++) {
|
||||
if (ptr->mod_num == val) {
|
||||
cpu_flags = ptr->cpu_flags;
|
||||
io_flags = ptr->io_flags;
|
||||
rtc_tps = ptr->ticker;
|
||||
cpu_unit[0].flags &= ~(UNIT_MODEL|UNIT_FLOAT|UNIT_MULT);
|
||||
cpu_unit[0].flags |= MODEL(val);
|
||||
if (cpu_flags & FLOAT)
|
||||
cpu_unit[0].flags |= UNIT_FLOAT;
|
||||
if (cpu_flags & MULT)
|
||||
cpu_unit[0].flags |= UNIT_MULT;
|
||||
return SCPE_OK;
|
||||
}
|
||||
}
|
||||
return SCPE_ARG;
|
||||
}
|
||||
|
||||
t_stat
|
||||
cpu_set_float(UNIT * uptr, int32 val, CONST char *cptr, void *desc)
|
||||
{
|
||||
int32 oval = val;
|
||||
if (val == 0 && (cpu_flags & (FLOAT_OPT|FLOAT)) == FLOAT)
|
||||
val = UNIT_FLOAT;
|
||||
cpu_unit[0].flags &= ~UNIT_FLOAT;
|
||||
cpu_unit[0].flags |= val;
|
||||
if (oval != val)
|
||||
return SCPE_ARG;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat
|
||||
cpu_set_mult(UNIT * uptr, int32 val, CONST char *cptr, void *desc)
|
||||
{
|
||||
int32 oval = val;
|
||||
if (val == 0 && (cpu_flags & (MULT_OPT|MULT)) == MULT)
|
||||
val = UNIT_MULT;
|
||||
cpu_unit[0].flags &= ~UNIT_MULT;
|
||||
cpu_unit[0].flags |= val;
|
||||
if (oval != val)
|
||||
return SCPE_ARG;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Handle execute history */
|
||||
|
||||
|
||||
@@ -1,347 +1,345 @@
|
||||
/* icl1900_cty.c: ICL1900 front end (console terminal) simulator
|
||||
|
||||
Copyright (c) 2018, Richard Cornwell
|
||||
|
||||
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
|
||||
RICHARD CORNWELL 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 Richard Cornwell shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Richard Cornwell
|
||||
|
||||
*/
|
||||
|
||||
#include "icl1900_defs.h"
|
||||
|
||||
extern int32 tmxr_poll;
|
||||
t_stat ctyi_svc (UNIT *uptr);
|
||||
t_stat ctyo_svc (UNIT *uptr);
|
||||
t_stat cty_reset (DEVICE *dptr);
|
||||
t_stat tty_set_mode (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
||||
t_stat cty_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
|
||||
const char *cty_description (DEVICE *dptr);
|
||||
|
||||
#define CMD u3
|
||||
#define STATUS u4
|
||||
#define HOLD u5
|
||||
|
||||
#define START 01
|
||||
#define STOP 02
|
||||
#define END 000001
|
||||
#define BUSY 000040
|
||||
#define INPUT 000100
|
||||
#define CANCEL 000200
|
||||
#define ACCEPT 000400
|
||||
#define F1 001000
|
||||
#define F2 002000
|
||||
#define F3 004000
|
||||
#define F4 010000
|
||||
#define F5 020000
|
||||
|
||||
UNIT cty_unit[] = {
|
||||
{ UDATA (&ctyo_svc, TT_MODE_7P, 0), 10000 },
|
||||
{ UDATA (&ctyi_svc, TT_MODE_7P|UNIT_IDLE, 0), 0 },
|
||||
};
|
||||
|
||||
|
||||
MTAB cty_mod[] = {
|
||||
{ TT_MODE, TT_MODE_UC, "UC", "UC", &tty_set_mode },
|
||||
{ TT_MODE, TT_MODE_7B, "7b", "7B", &tty_set_mode },
|
||||
{ TT_MODE, TT_MODE_8B, "8b", "8B", &tty_set_mode },
|
||||
{ TT_MODE, TT_MODE_7P, "7b", "7P", &tty_set_mode },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
DEVICE cty_dev = {
|
||||
"CTY", cty_unit, NULL, cty_mod,
|
||||
2, 8, 22, 1, 8, 22,
|
||||
NULL, NULL, &cty_reset,
|
||||
NULL, NULL, NULL, NULL, DEV_DEBUG, 0, dev_debug,
|
||||
NULL, NULL, &cty_help, NULL, NULL, &cty_description
|
||||
};
|
||||
|
||||
/*
|
||||
* Commands:
|
||||
* Bit 0 = start.
|
||||
* Bit 1 = stop.
|
||||
*
|
||||
* Responses:
|
||||
* Bit 0 = End of Transfer
|
||||
* Bit 5 = Busy
|
||||
* Bit 6 = Input Button Pushed.
|
||||
* Bit 7 = Cancel Button Pushed.
|
||||
* Bit 8 = Accept Button Pushed.
|
||||
* Bit 9 = F1
|
||||
* Bit 10 = F2
|
||||
* Bit 11 = F3
|
||||
* Bit 12 = F4
|
||||
* Bit 13 = F5
|
||||
*
|
||||
* 00xxxx -> 011xxxx
|
||||
* 01xxxx -> 010xxxx
|
||||
* 10xxxx -> 100xxxx
|
||||
* 11xxxx -> 101xxxx
|
||||
*
|
||||
*/
|
||||
t_stat ctyo_cmd(uint32 cmd, uint32 *resp) {
|
||||
if ((cmd & START) != 0 && (cty_unit[0].STATUS & BUSY) == 0)
|
||||
sim_activate(&cty_unit[0], cty_unit[0].wait);
|
||||
cty_unit[0].CMD |= cmd;
|
||||
*resp = cty_unit[0].STATUS;
|
||||
cty_unit[0].STATUS &= BUSY;
|
||||
chan_clr_done(3);
|
||||
}
|
||||
|
||||
t_stat ctyi_cmd(uint32 cmd, uint32 *resp) {
|
||||
cty_unit[1].CMD |= cmd;
|
||||
*resp = cty_unit[1].STATUS;
|
||||
cty_unit[1].STATUS &= BUSY;
|
||||
chan_clr_done(2);
|
||||
}
|
||||
|
||||
t_stat ctyo_svc (UNIT *uptr)
|
||||
{
|
||||
t_stat r;
|
||||
uint8 ch;
|
||||
int eor;
|
||||
|
||||
if (uptr->CMD & START) {
|
||||
uptr->STATUS &= ~END;
|
||||
uptr->STATUS |= BUSY;
|
||||
chan_clr_done(3);
|
||||
}
|
||||
if (uptr->CMD & STOP) {
|
||||
uptr->STATUS |= END;
|
||||
uptr->STATUS &= ~BUSY;
|
||||
chan_set_done(3);
|
||||
}
|
||||
uptr->CMD = 0;
|
||||
/* Check if we had a held characteter */
|
||||
if (uptr->HOLD != 0) {
|
||||
if ((r = sim_putchar_s (uptr->HOLD)) == SCPE_STALL) {
|
||||
r = SCPE_OK;
|
||||
} else {
|
||||
if (uptr->HOLD == '\r')
|
||||
uptr->HOLD = '\n';
|
||||
else
|
||||
uptr->HOLD = 0;
|
||||
}
|
||||
sim_activate (uptr, uptr->wait); /* try again */
|
||||
return r;
|
||||
}
|
||||
|
||||
if (uptr->STATUS & BUSY) {
|
||||
eor = chan_output_char(3, &ch, 0);
|
||||
switch (ch & 060) {
|
||||
case 000: ch = 0060 | (ch & 017); break;
|
||||
case 020: ch = 0040 | (ch & 017); break;
|
||||
case 040: ch = 0100 | (ch & 017); break;
|
||||
case 060: ch = 0120 | (ch & 017); break;
|
||||
}
|
||||
if (ch == 0137) {
|
||||
ch = '\r';
|
||||
uptr->HOLD = '\n';
|
||||
}
|
||||
ch = sim_tt_outcvt ( ch, TT_GET_MODE (uptr->flags)) ;
|
||||
if ((r = sim_putchar_s (ch)) == SCPE_STALL) { /* output; error? */
|
||||
uptr->HOLD = ch;
|
||||
r = SCPE_OK;
|
||||
}
|
||||
if (eor) {
|
||||
uptr->STATUS &= ~BUSY;
|
||||
uptr->STATUS |= END;
|
||||
chan_set_done(3);
|
||||
}
|
||||
sim_activate (uptr, uptr->wait); /* try again */
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat ctyi_svc (UNIT *uptr)
|
||||
{
|
||||
t_stat r;
|
||||
uint8 ch;
|
||||
int eor;
|
||||
|
||||
sim_clock_coschedule (uptr, tmxr_poll);
|
||||
|
||||
if (uptr->CMD & START) {
|
||||
uptr->STATUS &= ~END;
|
||||
uptr->STATUS |= BUSY;
|
||||
chan_clr_done(2);
|
||||
}
|
||||
if (uptr->CMD & STOP) {
|
||||
uptr->STATUS |= END;
|
||||
uptr->STATUS &= ~BUSY;
|
||||
chan_set_done(2);
|
||||
}
|
||||
uptr->CMD = 0;
|
||||
/* Handle input */
|
||||
|
||||
r = sim_poll_kbd();
|
||||
if (r & SCPE_KFLAG) {
|
||||
ch = 0177 & sim_tt_inpcvt(r & 0377, TT_GET_MODE (uptr->flags));
|
||||
if (uptr->HOLD) {
|
||||
if (ch >= '1' && ch <= '5') {
|
||||
chan_set_done(2);
|
||||
uptr->STATUS |= (F1 << (ch - '1'));
|
||||
} else {
|
||||
sim_putchar('\007');
|
||||
}
|
||||
uptr->HOLD = 0;
|
||||
return SCPE_OK;
|
||||
}
|
||||
if ((uptr->STATUS & BUSY) != 0) {
|
||||
/* Handle end of buffer */
|
||||
switch (ch) {
|
||||
case '\r':
|
||||
case '\n':
|
||||
sim_debug(DEBUG_DATA, &cty_dev, ": ent\n");
|
||||
sim_putchar('\r');
|
||||
sim_putchar('\n');
|
||||
uptr->STATUS |= ACCEPT|END;
|
||||
uptr->STATUS &= ~BUSY;
|
||||
chan_set_done(2);
|
||||
break;
|
||||
|
||||
case 033: /* function key <escape>n key */
|
||||
uptr->HOLD = 1;
|
||||
break;
|
||||
|
||||
case 030: /* ^X Post input interrupt */
|
||||
sim_debug(DEBUG_CMD, &cty_dev, ": inp\n");
|
||||
uptr->STATUS |= INPUT|END;
|
||||
uptr->STATUS &= ~BUSY;
|
||||
uptr->HOLD = 0;
|
||||
chan_set_done(2);
|
||||
break;
|
||||
|
||||
case 03: /* ^C */
|
||||
case 025: /* ^U clear line */
|
||||
uptr->STATUS |= CANCEL|END;
|
||||
uptr->STATUS &= ~BUSY;
|
||||
uptr->HOLD = 0;
|
||||
chan_set_done(2);
|
||||
break;
|
||||
|
||||
default:
|
||||
sim_debug(DEBUG_DATA, &cty_dev, ": key '%c'\n", ch);
|
||||
if (ch >= 0140)
|
||||
ch -= 040;
|
||||
if (ch >= 0100)
|
||||
ch -= 040;
|
||||
else if (ch >= 060)
|
||||
ch -= 060;
|
||||
else if (ch >= 040)
|
||||
ch -= 020;
|
||||
else {
|
||||
sim_putchar('\007');
|
||||
break;
|
||||
}
|
||||
eor = chan_input_char(2, &ch, 0);
|
||||
switch (ch & 060) {
|
||||
case 000: ch = 0060 | (ch & 017); break;
|
||||
case 020: ch = 0040 | (ch & 017); break;
|
||||
case 040: ch = 0100 | (ch & 017); break;
|
||||
case 060: ch = 0120 | (ch & 017); break;
|
||||
}
|
||||
ch = sim_tt_outcvt ( ch, TT_GET_MODE (uptr->flags)) ;
|
||||
sim_putchar (ch);
|
||||
if (eor) {
|
||||
uptr->STATUS &= ~BUSY;
|
||||
uptr->STATUS |= END;
|
||||
chan_set_done(2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* Handle end of buffer */
|
||||
switch (ch) {
|
||||
case 033: /* function key <escape>n key */
|
||||
uptr->HOLD = 1;
|
||||
break;
|
||||
|
||||
case 030: /* ^X Post input interrupt */
|
||||
sim_debug(DEBUG_CMD, &cty_dev, ": inp\n");
|
||||
uptr->STATUS |= INPUT;
|
||||
uptr->HOLD = 0;
|
||||
chan_set_done(2);
|
||||
break;
|
||||
|
||||
case 03: /* ^C */
|
||||
case 025: /* ^U clear line */
|
||||
uptr->STATUS |= CANCEL;
|
||||
uptr->HOLD = 0;
|
||||
chan_set_done(2);
|
||||
break;
|
||||
|
||||
default:
|
||||
sim_debug(DEBUG_DATA, &cty_dev, ": key '%c'\n", ch);
|
||||
sim_putchar('\007');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset */
|
||||
|
||||
t_stat cty_reset (DEVICE *dptr)
|
||||
{
|
||||
cty_unit[0].CMD = 0;
|
||||
cty_unit[1].CMD = 0;
|
||||
cty_unit[0].STATUS = 0;
|
||||
cty_unit[1].STATUS = 0;
|
||||
chan_clr_done(2);
|
||||
chan_clr_done(3);
|
||||
sim_clock_coschedule (&cty_unit[1], tmxr_poll);
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
|
||||
t_stat tty_set_mode (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
||||
{
|
||||
cty_unit[0].flags = (cty_unit[0].flags & ~TT_MODE) | val;
|
||||
cty_unit[1].flags = (cty_unit[1].flags & ~TT_MODE) | val;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat cty_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||||
{
|
||||
fprintf (st, "The additional terminals can be set to one of four modes: UC, 7P, 7B, or 8B.\n\n");
|
||||
fprintf (st, " mode input characters output characters\n\n");
|
||||
fprintf (st, " UC lower case converted lower case converted to upper case,\n");
|
||||
fprintf (st, " to upper case, high-order bit cleared,\n");
|
||||
fprintf (st, " high-order bit cleared non-printing characters suppressed\n");
|
||||
fprintf (st, " 7P high-order bit cleared high-order bit cleared,\n");
|
||||
fprintf (st, " non-printing characters suppressed\n");
|
||||
fprintf (st, " 7B high-order bit cleared high-order bit cleared\n");
|
||||
fprintf (st, " 8B no changes no changes\n\n");
|
||||
fprintf (st, "The default mode is 7P. In addition, each line can be configured to\n");
|
||||
fprintf (st, "behave as though it was attached to a dataset, or hardwired to a terminal:\n\n");
|
||||
fprint_reg_help (st, &cty_dev);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
const char *cty_description (DEVICE *dptr)
|
||||
{
|
||||
return "Console TTY Line";
|
||||
|
||||
}
|
||||
|
||||
/* icl1900_cty.c: ICL1900 front end (console terminal) simulator
|
||||
|
||||
Copyright (c) 2018, Richard Cornwell
|
||||
|
||||
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
|
||||
RICHARD CORNWELL 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 Richard Cornwell shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Richard Cornwell
|
||||
|
||||
*/
|
||||
|
||||
#include "icl1900_defs.h"
|
||||
|
||||
extern int32 tmxr_poll;
|
||||
void cty_cmd(int dev, uint32 cmd);
|
||||
void cty_status(int dev, uint32 *resp);
|
||||
t_stat ctyi_svc (UNIT *uptr);
|
||||
t_stat ctyo_svc (UNIT *uptr);
|
||||
t_stat cty_reset (DEVICE *dptr);
|
||||
t_stat tty_set_mode (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
||||
t_stat cty_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
|
||||
const char *cty_description (DEVICE *dptr);
|
||||
|
||||
DIB cty_dib = { CHAR_DEV, NULL, cty_cmd, cty_status};
|
||||
|
||||
#define CMD u3
|
||||
#define STATUS u4
|
||||
#define HOLD u5
|
||||
|
||||
#define START 01
|
||||
#define STOP 02
|
||||
#define END 000001
|
||||
#define BUSY 000040
|
||||
#define INPUT 000100
|
||||
#define CANCEL 000200
|
||||
#define ACCEPT 000400
|
||||
#define F1 001000
|
||||
#define F2 002000
|
||||
#define F3 004000
|
||||
#define F4 010000
|
||||
#define F5 020000
|
||||
|
||||
UNIT cty_unit[] = {
|
||||
{ UDATA (&ctyo_svc, UNIT_ADDR(3)|TT_MODE_7P, 0), 10000 },
|
||||
{ UDATA (&ctyi_svc, UNIT_ADDR(2)|TT_MODE_7P|UNIT_IDLE, 0), 0 },
|
||||
};
|
||||
|
||||
|
||||
MTAB cty_mod[] = {
|
||||
{ TT_MODE, TT_MODE_UC, "UC", "UC", &tty_set_mode },
|
||||
{ TT_MODE, TT_MODE_7B, "7b", "7B", &tty_set_mode },
|
||||
{ TT_MODE, TT_MODE_8B, "8b", "8B", &tty_set_mode },
|
||||
{ TT_MODE, TT_MODE_7P, "7b", "7P", &tty_set_mode },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
DEVICE cty_dev = {
|
||||
"CTY", cty_unit, NULL, cty_mod,
|
||||
2, 8, 22, 1, 8, 22,
|
||||
NULL, NULL, &cty_reset,
|
||||
NULL, NULL, NULL, &cty_dib, DEV_DEBUG, 0, dev_debug,
|
||||
NULL, NULL, &cty_help, NULL, NULL, &cty_description
|
||||
};
|
||||
|
||||
/*
|
||||
* Commands:
|
||||
* Bit 0 = start.
|
||||
* Bit 1 = stop.
|
||||
*
|
||||
* Responses:
|
||||
* Bit 0 = End of Transfer
|
||||
* Bit 5 = Busy
|
||||
* Bit 6 = Input Button Pushed.
|
||||
* Bit 7 = Cancel Button Pushed.
|
||||
* Bit 8 = Accept Button Pushed.
|
||||
* Bit 9 = F1
|
||||
* Bit 10 = F2
|
||||
* Bit 11 = F3
|
||||
* Bit 12 = F4
|
||||
* Bit 13 = F5
|
||||
*
|
||||
* 00xxxx -> 011xxxx
|
||||
* 01xxxx -> 010xxxx
|
||||
* 10xxxx -> 100xxxx
|
||||
* 11xxxx -> 101xxxx
|
||||
*
|
||||
*/
|
||||
void cty_cmd(int dev, uint32 cmd) {
|
||||
int u = 0;
|
||||
|
||||
if (dev > 3)
|
||||
return;
|
||||
if (dev == 2)
|
||||
u++;
|
||||
if (cmd & START) {
|
||||
cty_unit[u].STATUS &= ~END;
|
||||
cty_unit[u].STATUS |= BUSY;
|
||||
if (!u)
|
||||
sim_activate(&cty_unit[u], cty_unit[u].wait);
|
||||
}
|
||||
else if (cmd & STOP) {
|
||||
cty_unit[u].STATUS &= ~BUSY;
|
||||
}
|
||||
cty_unit[u].STATUS &= BUSY;
|
||||
chan_clr_done(GET_UADDR(cty_unit[u].flags));
|
||||
}
|
||||
|
||||
void cty_status(int dev, uint32 *resp) {
|
||||
int u = 0;
|
||||
|
||||
if (dev > 3)
|
||||
return;
|
||||
if (dev == 2)
|
||||
u++;
|
||||
*resp = cty_unit[u].STATUS;
|
||||
cty_unit[u].STATUS &= BUSY;
|
||||
chan_clr_done(GET_UADDR(cty_unit[u].flags));
|
||||
}
|
||||
|
||||
t_stat ctyo_svc (UNIT *uptr)
|
||||
{
|
||||
t_stat r;
|
||||
uint8 ch;
|
||||
int eor;
|
||||
|
||||
/* Check if we had a held characteter */
|
||||
if (uptr->HOLD != 0) {
|
||||
if ((r = sim_putchar_s (uptr->HOLD)) == SCPE_STALL) {
|
||||
r = SCPE_OK;
|
||||
} else {
|
||||
if (uptr->HOLD == '\r')
|
||||
uptr->HOLD = '\n';
|
||||
else
|
||||
uptr->HOLD = 0;
|
||||
}
|
||||
sim_activate (uptr, uptr->wait); /* try again */
|
||||
return r;
|
||||
}
|
||||
|
||||
if (uptr->STATUS & BUSY) {
|
||||
eor = chan_output_char(GET_UADDR(uptr->flags), &ch, 0);
|
||||
switch (ch & 060) {
|
||||
case 000: ch = 0060 | (ch & 017); break;
|
||||
case 020: ch = 0040 | (ch & 017); break;
|
||||
case 040: ch = 0100 | (ch & 017); break;
|
||||
case 060: ch = 0120 | (ch & 017); break;
|
||||
}
|
||||
if (ch == 0137) {
|
||||
ch = '\r';
|
||||
uptr->HOLD = '\n';
|
||||
}
|
||||
ch = sim_tt_outcvt ( ch, TT_GET_MODE (uptr->flags)) ;
|
||||
if ((r = sim_putchar_s (ch)) == SCPE_STALL) { /* output; error? */
|
||||
uptr->HOLD = ch;
|
||||
r = SCPE_OK;
|
||||
}
|
||||
if (eor) {
|
||||
uptr->STATUS &= ~BUSY;
|
||||
uptr->STATUS |= END;
|
||||
chan_set_done(GET_UADDR(uptr->flags));
|
||||
}
|
||||
sim_activate (uptr, uptr->wait); /* try again */
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat ctyi_svc (UNIT *uptr)
|
||||
{
|
||||
t_stat r;
|
||||
uint8 ch;
|
||||
int eor;
|
||||
|
||||
sim_clock_coschedule (uptr, tmxr_poll);
|
||||
|
||||
/* Handle input */
|
||||
|
||||
r = sim_poll_kbd();
|
||||
if (r & SCPE_KFLAG) {
|
||||
ch = 0177 & sim_tt_inpcvt(r & 0377, TT_GET_MODE (uptr->flags));
|
||||
if (uptr->HOLD) {
|
||||
if (ch >= '1' && ch <= '5') {
|
||||
chan_set_done(GET_UADDR(uptr->flags));
|
||||
uptr->STATUS |= (F1 << (ch - '1'));
|
||||
} else {
|
||||
sim_putchar('\007');
|
||||
}
|
||||
uptr->HOLD = 0;
|
||||
return SCPE_OK;
|
||||
}
|
||||
if ((uptr->STATUS & BUSY) != 0) {
|
||||
/* Handle end of buffer */
|
||||
switch (ch) {
|
||||
case '\r':
|
||||
case '\n':
|
||||
sim_debug(DEBUG_DATA, &cty_dev, ": ent\n");
|
||||
sim_putchar('\r');
|
||||
sim_putchar('\n');
|
||||
uptr->STATUS |= ACCEPT;
|
||||
uptr->STATUS &= ~BUSY;
|
||||
chan_set_done(GET_UADDR(uptr->flags));
|
||||
break;
|
||||
|
||||
case 033: /* function key <escape>n key */
|
||||
uptr->HOLD = 1;
|
||||
break;
|
||||
|
||||
case 030: /* ^X Post input interrupt */
|
||||
sim_debug(DEBUG_CMD, &cty_dev, ": inp\n");
|
||||
uptr->STATUS |= INPUT;
|
||||
uptr->STATUS &= ~BUSY;
|
||||
uptr->HOLD = 0;
|
||||
chan_set_done(GET_UADDR(uptr->flags));
|
||||
break;
|
||||
|
||||
case 03: /* ^C */
|
||||
case 025: /* ^U clear line */
|
||||
uptr->STATUS |= CANCEL;
|
||||
uptr->STATUS &= ~BUSY;
|
||||
uptr->HOLD = 0;
|
||||
chan_set_done(GET_UADDR(uptr->flags));
|
||||
break;
|
||||
|
||||
default:
|
||||
sim_debug(DEBUG_DATA, &cty_dev, ": key '%c'\n", ch);
|
||||
if (ch >= 0140)
|
||||
ch -= 040;
|
||||
if (ch >= 0100)
|
||||
ch -= 040;
|
||||
else if (ch >= 060)
|
||||
ch -= 060;
|
||||
else if (ch >= 040)
|
||||
ch -= 020;
|
||||
else {
|
||||
sim_putchar('\007');
|
||||
break;
|
||||
}
|
||||
eor = chan_input_char(GET_UADDR(uptr->flags), &ch, 0);
|
||||
switch (ch & 060) {
|
||||
case 000: ch = 0060 | (ch & 017); break;
|
||||
case 020: ch = 0040 | (ch & 017); break;
|
||||
case 040: ch = 0100 | (ch & 017); break;
|
||||
case 060: ch = 0120 | (ch & 017); break;
|
||||
}
|
||||
ch = sim_tt_outcvt ( ch, TT_GET_MODE (uptr->flags)) ;
|
||||
sim_putchar (ch);
|
||||
if (eor) {
|
||||
uptr->STATUS &= ~BUSY;
|
||||
uptr->STATUS |= END;
|
||||
chan_set_done(GET_UADDR(uptr->flags));
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* Handle end of buffer */
|
||||
switch (ch) {
|
||||
case 033: /* function key <escape>n key */
|
||||
uptr->HOLD = 1;
|
||||
break;
|
||||
|
||||
case 030: /* ^X Post input interrupt */
|
||||
sim_debug(DEBUG_CMD, &cty_dev, ": inp\n");
|
||||
uptr->STATUS |= INPUT;
|
||||
uptr->HOLD = 0;
|
||||
chan_set_done(GET_UADDR(uptr->flags));
|
||||
break;
|
||||
|
||||
case 03: /* ^C */
|
||||
case 025: /* ^U clear line */
|
||||
uptr->STATUS |= CANCEL;
|
||||
uptr->HOLD = 0;
|
||||
chan_set_done(GET_UADDR(uptr->flags));
|
||||
break;
|
||||
|
||||
default:
|
||||
sim_debug(DEBUG_DATA, &cty_dev, ": key '%c'\n", ch);
|
||||
sim_putchar('\007');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset */
|
||||
|
||||
t_stat cty_reset (DEVICE *dptr)
|
||||
{
|
||||
cty_unit[0].CMD = 0;
|
||||
cty_unit[1].CMD = 0;
|
||||
cty_unit[0].STATUS = 0;
|
||||
cty_unit[1].STATUS = 0;
|
||||
chan_clr_done(GET_UADDR(cty_unit[0].flags));
|
||||
chan_clr_done(GET_UADDR(cty_unit[1].flags));
|
||||
sim_clock_coschedule (&cty_unit[1], tmxr_poll);
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
|
||||
t_stat tty_set_mode (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
||||
{
|
||||
cty_unit[0].flags = (cty_unit[0].flags & ~TT_MODE) | val;
|
||||
cty_unit[1].flags = (cty_unit[1].flags & ~TT_MODE) | val;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat cty_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||||
{
|
||||
fprintf (st, "The additional terminals can be set to one of four modes: UC, 7P, 7B, or 8B.\n\n");
|
||||
fprintf (st, " mode input characters output characters\n\n");
|
||||
fprintf (st, " UC lower case converted lower case converted to upper case,\n");
|
||||
fprintf (st, " to upper case, high-order bit cleared,\n");
|
||||
fprintf (st, " high-order bit cleared non-printing characters suppressed\n");
|
||||
fprintf (st, " 7P high-order bit cleared high-order bit cleared,\n");
|
||||
fprintf (st, " non-printing characters suppressed\n");
|
||||
fprintf (st, " 7B high-order bit cleared high-order bit cleared\n");
|
||||
fprintf (st, " 8B no changes no changes\n\n");
|
||||
fprintf (st, "The default mode is 7P. In addition, each line can be configured to\n");
|
||||
fprintf (st, "behave as though it was attached to a dataset, or hardwired to a terminal:\n\n");
|
||||
fprint_reg_help (st, &cty_dev);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
const char *cty_description (DEVICE *dptr)
|
||||
{
|
||||
return "Console TTY Line";
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
|
||||
/* Definitions for each supported CPU */
|
||||
|
||||
#define NUM_DEVS_PTR 1
|
||||
#define NUM_DEVS_PTP 1
|
||||
#define NUM_DEVS_CDR 0
|
||||
#define NUM_DEVS_CDP 0
|
||||
#define NUM_DEVS_LPR 0
|
||||
@@ -38,6 +40,7 @@
|
||||
#define MAXMEMSIZE (4096 * 1024)
|
||||
|
||||
extern uint32 M[]; /* Main Memory */
|
||||
extern uint32 XR[8];
|
||||
|
||||
/* Memory */
|
||||
#define MEMSIZE (cpu_unit[0].capac) /* actual memory size */
|
||||
@@ -59,15 +62,50 @@ extern DEBTAB dev_debug[];
|
||||
|
||||
extern uint32 SR64;
|
||||
extern uint32 SR65;
|
||||
extern uint32 RC;
|
||||
extern uint16 cpu_flags;
|
||||
extern uint8 io_flags;
|
||||
extern uint8 loading;
|
||||
|
||||
|
||||
/* Returns from device commands */
|
||||
#define SCPE_BUSY (1) /* Device is active */
|
||||
#define SCPE_NODEV (2) /* No device exists */
|
||||
|
||||
typedef struct _cpumod
|
||||
{
|
||||
CONST char *name;
|
||||
uint8 mod_num; /* Model number */
|
||||
uint16 cpu_flags; /* Cpu option flags */
|
||||
uint8 io_flags; /* I/O type option. */
|
||||
uint16 ticker; /* Number of ticker events per second */
|
||||
} CPUMOD;
|
||||
|
||||
/* Definitions for cpu flags */
|
||||
#define CPU_TYPE (cpu_flags & 7)
|
||||
#define TYPE_A1 0000
|
||||
#define TYPE_A2 0001
|
||||
#define TYPE_B1 0002
|
||||
#define TYPE_B2 0003
|
||||
#define TYPE_C1 0004
|
||||
#define TYPE_C2 0005
|
||||
#define FLOAT_STD 0010 /* Floating point standard */
|
||||
#define FLOAT_OPT 0020 /* Floating point optional */
|
||||
#define FLOAT 0040 /* Floating point installed */
|
||||
#define STD_FLOAT 0100 /* Std Floating point only */
|
||||
#define NORM_OP 0001
|
||||
#define MULT_OPT 0200 /* Multiply/Divide optional */
|
||||
#define MULT 0400 /* Multiply/Divide installed */
|
||||
#define SV 01000 /* Stevenage Machine */
|
||||
#define WG 00000 /* West Gorton Machine */
|
||||
|
||||
/* Definitions for io_flags */
|
||||
#define EXT_IO 0001 /* I/O channels at 256 and above */
|
||||
|
||||
/* Symbol tables */
|
||||
typedef struct _opcode
|
||||
{
|
||||
const char *name;
|
||||
CONST char *name;
|
||||
uint8 type;
|
||||
}
|
||||
t_opcode;
|
||||
@@ -192,21 +230,56 @@ t_opcode;
|
||||
#define NMASK 037777400
|
||||
#define MMASK 037777000
|
||||
|
||||
#define UNIT_V_ADDR 24
|
||||
#define UNIT_M_ADDR (077 << UNIT_V_ADDR)
|
||||
#define GET_UADDR(x) ((UNIT_M_ADDR & (x)) >> UNIT_V_ADDR)
|
||||
#define UNIT_ADDR(x) (UNIT_M_ADDR & ((x) << UNIT_V_ADDR))
|
||||
|
||||
/* DIB type flags */
|
||||
#define CHAR_DEV 0 /* Device transfers via characters */
|
||||
#define WORD_DEV 1 /* Device transfers via words */
|
||||
#define SPEC_HES 2 /* Special transfer */
|
||||
#define LONG_BLK 4 /* Long block device */
|
||||
#define MULT_DEV 8 /* Channel in device flags */
|
||||
|
||||
struct icl_dib {
|
||||
uint8 channel; /* Channel number */
|
||||
uint8 type; /* Type of device */
|
||||
t_stat (*dev_cmd)(uint32 cmd, uint32 *resp); /* Start io on device */
|
||||
uint8 type; /* Type of device */
|
||||
void (*si_cmd)(int dev, uint32 cmd, uint32 *resp); /* Start io on device */
|
||||
void (*nsi_cmd)(int dev, uint32 cmd); /* Start non-standard I/O on device */
|
||||
void (*nsi_status)(int dev, uint32 *resp); /* Non-Standard I/O status */
|
||||
};
|
||||
|
||||
typedef struct icl_dib DIB;
|
||||
|
||||
/* Hessitation operations */
|
||||
/* Common commands */
|
||||
#define SEND_Q 020 /* Send status Q */
|
||||
#define SEND_P 024 /* Send status P */
|
||||
#define SEND_P2 025 /* Send status P2 */
|
||||
#define DISCO 036 /* Disconnect device */
|
||||
|
||||
/* General response code */
|
||||
#define DEV_INOP 000 /* Device inoperable */
|
||||
#define DEV_REJT 003 /* Command rejected */
|
||||
#define DEV_ACCP 005 /* Command accepted */
|
||||
|
||||
/* P Staus bits */
|
||||
#define DEV_OPT 001 /* Device operational */
|
||||
#define DEV_WARN 002 /* Device has warning */
|
||||
#define DEV_ERROR 004 /* Device has error pending */
|
||||
|
||||
/* Q Status bits */
|
||||
#define DEV_TERM 001 /* Device terminated */
|
||||
#define DEV_P_STAT 040 /* No P status */
|
||||
|
||||
/* Channel controls */
|
||||
extern t_stat chan_set_devs();
|
||||
extern t_stat set_chan(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
||||
extern t_stat get_chan(FILE *st, UNIT *uptr, int32 v, CONST void *desc);
|
||||
|
||||
/* Hesitation operations */
|
||||
extern void chan_send_cmd(int dev, uint32 cmd, uint32 *resp);
|
||||
extern void chan_nsi_cmd(int dev, uint32 cmd);
|
||||
extern void chan_nsi_status(int dev, uint32 *resp);
|
||||
extern int chan_input_char(int dev, uint8 *data, int eor);
|
||||
extern int chan_output_char(int dev, uint8 *data, int eor);
|
||||
extern int chan_input_word(int dev, uint32 *data, int eor);
|
||||
@@ -214,17 +287,17 @@ extern int chan_output_word(int dev, uint32 *data, int eor);
|
||||
extern void chan_set_done(int dev);
|
||||
extern void chan_clr_done(int dev);
|
||||
|
||||
/* Console tty device routines */
|
||||
extern t_stat ctyi_cmd(uint32 cmd, uint32 *resp);
|
||||
extern t_stat ctyo_cmd(uint32 cmd, uint32 *resp);
|
||||
|
||||
/* Generic devices common to all */
|
||||
extern DEVICE cpu_dev;
|
||||
extern UNIT cpu_unit[];
|
||||
extern REG cpu_reg[];
|
||||
|
||||
/* Global device definitions */
|
||||
extern DIB ctyi_dib;
|
||||
extern DIB ctyo_dib;
|
||||
extern DEVICE cty_dev;
|
||||
extern DEVICE ptr_dev;
|
||||
extern DEVICE ptp_dev;
|
||||
extern DEVICE cdr_dev;
|
||||
extern DEVICE cdp_dev;
|
||||
extern DEVICE lpr_dev;
|
||||
|
||||
@@ -1,365 +1,430 @@
|
||||
/* icl1900_stdio.c: ICL 1900 standard I/O devices
|
||||
|
||||
Copyright (c) 2018, Richard Cornwell
|
||||
|
||||
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
|
||||
RICHARD CORNWELL 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.
|
||||
|
||||
*/
|
||||
|
||||
#include "icl1900_defs.h"
|
||||
|
||||
/* Define style bits */
|
||||
|
||||
#define OUTPUT B0 /* Input/Output flag */
|
||||
#define BACKWARD B1 /* Forward/Backword */
|
||||
#define WORDCCW B2 /* Character/Word */
|
||||
#define MULTICHN B3 /* Single/Multi Channel */
|
||||
#define CWRECHARGE B4 /* Recharge CW when empty */
|
||||
#define GATHER B5 /* Gather */
|
||||
|
||||
|
||||
DIB *devs[32]; /* Pointer to device DIB entry */
|
||||
|
||||
/* Fake DIB entries for the CTY devices */
|
||||
DIB ctyi_dib = { 2, CHAR_DEV, ctyi_cmd};
|
||||
DIB ctyo_dib = { 3, CHAR_DEV, ctyo_cmd};
|
||||
DIB nul1_dib = { 22, 0, 0};
|
||||
DIB nul2_dib = { 23, 0, 0};
|
||||
|
||||
uint32 cw0; /* Holding registers for current control word */
|
||||
uint32 cw1;
|
||||
|
||||
t_stat
|
||||
chan_set_devs()
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Clear device table */
|
||||
for (i = 0; i < sizeof(devs)/sizeof(DIB *); i++)
|
||||
devs[i] = NULL;
|
||||
|
||||
devs[22-4] = &nul1_dib; /* Add in hidden channels */
|
||||
devs[23-4] = &nul2_dib;
|
||||
/* Scan all devices and assign to channel */
|
||||
for(i = 0; sim_devices[i] != NULL; i++) {
|
||||
DIB *dibp = (DIB *) sim_devices[i]->ctxt;
|
||||
int chan;
|
||||
|
||||
/* Check if device a channel device */
|
||||
if (dibp == NULL)
|
||||
continue;
|
||||
/* If device is disabled, don't add it */
|
||||
if (sim_devices[i]->flags & DEV_DIS)
|
||||
continue;
|
||||
chan = dibp->channel - 4;
|
||||
if (chan < 0)
|
||||
continue;
|
||||
if (devs[chan] != NULL) {
|
||||
fprintf(stderr, "Conflict between devices %d %s\n", chan, sim_devices[i]->name);
|
||||
} else {
|
||||
devs[chan] = dibp;
|
||||
}
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
|
||||
/* Set the device onto a given channel */
|
||||
t_stat
|
||||
set_chan(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
||||
{
|
||||
DEVICE *dptr;
|
||||
DIB *dibp;
|
||||
int newchan;
|
||||
t_stat r;
|
||||
|
||||
if (cptr == NULL)
|
||||
return SCPE_ARG;
|
||||
if (uptr == NULL)
|
||||
return SCPE_IERR;
|
||||
dptr = find_dev_from_unit(uptr);
|
||||
if (dptr == NULL)
|
||||
return SCPE_IERR;
|
||||
dibp = (DIB *) dptr->ctxt;
|
||||
|
||||
if (dibp == NULL)
|
||||
return SCPE_IERR;
|
||||
newchan = get_uint(cptr, 10, 37, &r);
|
||||
if (r != SCPE_OK)
|
||||
return r;
|
||||
if (newchan < 4) /* Lowest channel is 4 */
|
||||
return SCPE_ARG;
|
||||
newchan -= 4;
|
||||
if (dibp == devs[dibp->channel-4])
|
||||
devs[dibp->channel-4] = NULL;
|
||||
/* If device is disabled, set to whatever the user wants */
|
||||
if (dptr->flags & DEV_DIS) {
|
||||
dibp->channel = newchan;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
if (devs[newchan] != NULL) {
|
||||
devs[newchan] = dibp;
|
||||
dibp->channel = newchan+4;
|
||||
return SCPE_OK;
|
||||
} else {
|
||||
fprintf(stderr, "Device already on channel %d\n", newchan+4);
|
||||
devs[dibp->channel] = dibp;
|
||||
}
|
||||
return SCPE_ARG;
|
||||
}
|
||||
|
||||
/* Print the channel the device is on */
|
||||
t_stat
|
||||
get_chan(FILE *st, UNIT *uptr, int32 v, CONST void *desc)
|
||||
{
|
||||
DEVICE *dptr;
|
||||
DIB *dibp;
|
||||
int chan;
|
||||
|
||||
if (uptr == NULL)
|
||||
return SCPE_IERR;
|
||||
dptr = find_dev_from_unit(uptr);
|
||||
if (dptr == NULL)
|
||||
return SCPE_IERR;
|
||||
dibp = (DIB *) dptr->ctxt;
|
||||
if (dibp == NULL)
|
||||
return SCPE_IERR;
|
||||
fprintf(st, "Chan=%d", dibp->channel);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
int
|
||||
get_ccw(int dev, uint32 *addr, uint8 type) {
|
||||
int cw_addr = 256+4*dev;
|
||||
#if 0
|
||||
cw0 = M[64+dev];
|
||||
#endif
|
||||
cw0 = M[cw_addr];
|
||||
cw1 = M[cw_addr+1];
|
||||
*addr = cw1;
|
||||
if (cw0 & WORDCCW) {
|
||||
if (cw0 & BACKWARD)
|
||||
cw1 = ((cw1 + M22) & M22) | (cw1 & CMASK);
|
||||
else
|
||||
cw1 = ((cw1 + 1) & M22) | (cw1 & CMASK);
|
||||
} else {
|
||||
if (cw0 & BACKWARD) {
|
||||
if (cw1 & CMASK) {
|
||||
cw1 -= B1;
|
||||
} else {
|
||||
cw1 = ((cw1 - 1) & M22) | CMASK;
|
||||
}
|
||||
} else {
|
||||
if ((cw1 & CMASK) == CMASK) {
|
||||
cw1 = (cw1 + 1) & M22;
|
||||
} else {
|
||||
cw1 += B1;
|
||||
}
|
||||
}
|
||||
}
|
||||
cw0 = ((cw0 - 1) & M15) | (cw0 & CNTMSK);
|
||||
if ((cw0 & M15) == 0) {
|
||||
if ((cw0 & (CWRECHARGE|GATHER)) == (CWRECHARGE)) {
|
||||
cw0 = M[cw_addr+2];
|
||||
cw1 = M[cw_addr+3];
|
||||
} else if ((cw0 & GATHER) != 0) {
|
||||
int a;
|
||||
if ((cw0 & CWRECHARGE) != 0)
|
||||
M[cw_addr+3] = M[cw_addr+2];
|
||||
a = M[cw_addr+3];
|
||||
cw0 = M[a & M22];
|
||||
cw1 = M[(a + 1) & M22];
|
||||
M[cw_addr+3] = ((a + 2) & M22) | (a & CMASK);
|
||||
}
|
||||
M[cw_addr] = cw0;
|
||||
M[cw_addr+1] = cw1;
|
||||
return (cw0 & M15) == 0;
|
||||
}
|
||||
M[cw_addr] = cw0;
|
||||
M[cw_addr+1] = cw1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Hessitation operations */
|
||||
void
|
||||
chan_send_cmd(int dev, uint32 cmd, uint32 *resp) {
|
||||
DIB *dibp = NULL;
|
||||
int d = dev & 077;
|
||||
|
||||
if (dev >= 4 && dev <= 36)
|
||||
dibp = devs[d - 4];
|
||||
else if (dev == 3)
|
||||
dibp = &ctyo_dib;
|
||||
else if (dev == 2)
|
||||
dibp = &ctyi_dib;
|
||||
|
||||
*resp = 0;
|
||||
if (dibp != NULL && dibp->dev_cmd != NULL) {
|
||||
t_stat r;
|
||||
|
||||
r = (dibp->dev_cmd)((dev & 07700) | cmd, resp);
|
||||
}
|
||||
}
|
||||
|
||||
/* Transfer date between device and memory */
|
||||
int
|
||||
chan_input_char(int dev, uint8 *data, int eor) {
|
||||
int r;
|
||||
int c;
|
||||
DIB *dibp = NULL;
|
||||
uint32 addr;
|
||||
uint32 mb;
|
||||
|
||||
|
||||
/* Figure out DIB to find out type of device */
|
||||
if (dev >= 4 && dev <= 36)
|
||||
dibp = devs[dev - 4];
|
||||
else if (dev == 3)
|
||||
dibp = &ctyo_dib;
|
||||
else if (dev == 2)
|
||||
dibp = &ctyi_dib;
|
||||
|
||||
/* Make sure device assigne here */
|
||||
if (dibp == NULL || dibp->dev_cmd == NULL)
|
||||
return -1;
|
||||
|
||||
/* Check if right type */
|
||||
if ((dibp->type & WORD_DEV) != 0)
|
||||
return -2;
|
||||
|
||||
/* Get address of next character. */
|
||||
r = get_ccw(dev, &addr, dibp->type);
|
||||
c = (addr >> 22) & 3;
|
||||
c = 6 * (3 - c);
|
||||
mb = M[addr & M22];
|
||||
mb &= ~(077 << c);
|
||||
mb |= ((uint32)(*data) & 077) << c;
|
||||
M[addr & M22] = mb;
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
chan_output_char(int dev, uint8 *data, int eor) {
|
||||
int r;
|
||||
int c;
|
||||
DIB *dibp = NULL;
|
||||
uint32 addr;
|
||||
uint32 mb;
|
||||
|
||||
|
||||
/* Figure out DIB to find out type of device */
|
||||
if (dev >= 4 && dev <= 36)
|
||||
dibp = devs[dev - 4];
|
||||
else if (dev == 3)
|
||||
dibp = &ctyo_dib;
|
||||
else if (dev == 2)
|
||||
dibp = &ctyi_dib;
|
||||
|
||||
/* Make sure device assigne here */
|
||||
if (dibp == NULL || dibp->dev_cmd == NULL)
|
||||
return -1;
|
||||
|
||||
/* Check if right type */
|
||||
if ((dibp->type & WORD_DEV) != 0)
|
||||
return -2;
|
||||
|
||||
/* Get address of next character. */
|
||||
r = get_ccw(dev, &addr, dibp->type);
|
||||
c = (addr >> 22) & 3;
|
||||
c = 6 * (3 - c);
|
||||
mb = M[addr & M22];
|
||||
*data = (uint8)(mb >> c) & 077;
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
chan_input_word(int dev, uint32 *data, int eor) {
|
||||
int r;
|
||||
DIB *dibp = NULL;
|
||||
uint32 addr;
|
||||
|
||||
|
||||
/* Figure out DIB to find out type of device */
|
||||
if (dev >= 4 && dev <= 36)
|
||||
dibp = devs[dev - 4];
|
||||
else if (dev == 3)
|
||||
dibp = &ctyo_dib;
|
||||
else if (dev == 2)
|
||||
dibp = &ctyi_dib;
|
||||
|
||||
/* Make sure device assigne here */
|
||||
if (dibp == NULL || dibp->dev_cmd == NULL)
|
||||
return -1;
|
||||
|
||||
/* Check if right type */
|
||||
if ((dibp->type & WORD_DEV) == 0)
|
||||
return -2;
|
||||
|
||||
/* Get address of next word. */
|
||||
r = get_ccw(dev, &addr, dibp->type);
|
||||
M[addr & M22] = *data;
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
chan_output_word(int dev, uint32 *data, int eor) {
|
||||
int r;
|
||||
DIB *dibp = NULL;
|
||||
uint32 addr;
|
||||
|
||||
|
||||
/* Figure out DIB to find out type of device */
|
||||
if (dev >= 4 && dev <= 36)
|
||||
dibp = devs[dev - 4];
|
||||
else if (dev == 3)
|
||||
dibp = &ctyo_dib;
|
||||
else if (dev == 2)
|
||||
dibp = &ctyi_dib;
|
||||
|
||||
/* Make sure device assigne here */
|
||||
if (dibp == NULL || dibp->dev_cmd == NULL)
|
||||
return -1;
|
||||
|
||||
/* Check if right type */
|
||||
if ((dibp->type & WORD_DEV) == 0)
|
||||
return -2;
|
||||
|
||||
/* Get address of next word. */
|
||||
r = get_ccw(dev, &addr, dibp->type);
|
||||
*data = M[addr & M22];
|
||||
return r;
|
||||
}
|
||||
|
||||
void
|
||||
chan_set_done(int dev) {
|
||||
if (dev < 22)
|
||||
SR64 |= B2 >> dev;
|
||||
else
|
||||
SR65 |= B1 >> (dev - 24);
|
||||
}
|
||||
|
||||
void
|
||||
chan_clr_done(int dev) {
|
||||
if (dev < 22)
|
||||
SR64 &= ~(B2 >> dev);
|
||||
else
|
||||
SR65 &= ~(B1 >> (dev - 24));
|
||||
}
|
||||
|
||||
|
||||
/* icl1900_stdio.c: ICL 1900 standard I/O devices
|
||||
|
||||
Copyright (c) 2018, Richard Cornwell
|
||||
|
||||
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
|
||||
RICHARD CORNWELL 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.
|
||||
|
||||
*/
|
||||
|
||||
#include "icl1900_defs.h"
|
||||
|
||||
/* Define style bits */
|
||||
|
||||
#define OUTPUT B0 /* Input/Output flag */
|
||||
#define BACKWARD B1 /* Forward/Backword */
|
||||
#define WORDCCW B2 /* Character/Word */
|
||||
#define MULTICHN B3 /* Single/Multi Channel */
|
||||
#define CWRECHARGE B4 /* Recharge CW when empty */
|
||||
#define GATHER B5 /* Gather */
|
||||
|
||||
|
||||
DIB *devs[64]; /* Pointer to device DIB entry */
|
||||
|
||||
DIB nul_dib = { 0, NULL, NULL, NULL};
|
||||
|
||||
|
||||
t_stat
|
||||
chan_set_devs()
|
||||
{
|
||||
int i;
|
||||
int chan;
|
||||
|
||||
/* Clear device table */
|
||||
for (i = 0; i < sizeof(devs)/sizeof(DIB *); i++)
|
||||
devs[i] = NULL;
|
||||
|
||||
/* Add in hidden channels */
|
||||
devs[22] = &nul_dib;
|
||||
devs[23] = &nul_dib;
|
||||
/* Scan all devices and assign to channel */
|
||||
for(i = 0; sim_devices[i] != NULL; i++) {
|
||||
DIB *dibp = (DIB *) sim_devices[i]->ctxt;
|
||||
|
||||
/* Check if device a channel device */
|
||||
if (dibp == NULL)
|
||||
continue;
|
||||
/* If device is disabled, don't add it */
|
||||
if (sim_devices[i]->flags & DEV_DIS)
|
||||
continue;
|
||||
if (dibp->type & MULT_DEV) {
|
||||
chan = GET_UADDR(sim_devices[i]->flags);
|
||||
/* Make sure it is in range */
|
||||
if (chan < 2 || chan > 36)
|
||||
continue;
|
||||
if (devs[chan] != NULL) {
|
||||
fprintf(stderr, "Conflict between devices %d %s\n", chan, sim_devices[i]->name);
|
||||
} else {
|
||||
devs[chan] = dibp;
|
||||
}
|
||||
} else {
|
||||
UNIT *uptr = sim_devices[i]->units;
|
||||
uint32 unit;
|
||||
for (unit = 0; unit < sim_devices[i]->numunits; unit++, uptr++) {
|
||||
/* If disabled, skip it */
|
||||
if (uptr->flags & UNIT_DIS)
|
||||
continue;
|
||||
chan = GET_UADDR(uptr->flags);
|
||||
/* Make sure it is in range */
|
||||
if (chan < 2 || chan > 36)
|
||||
continue;
|
||||
if (devs[chan] != NULL) {
|
||||
fprintf(stderr, "Conflict between devices %d %s%d\n", chan, sim_devices[i]->name, unit);
|
||||
} else {
|
||||
devs[chan] = dibp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
|
||||
/* Set the device onto a given channel */
|
||||
t_stat
|
||||
set_chan(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
||||
{
|
||||
DEVICE *dptr;
|
||||
DIB *dibp;
|
||||
int new_chan;
|
||||
int cur_chan;
|
||||
t_stat r;
|
||||
|
||||
if (cptr == NULL)
|
||||
return SCPE_ARG;
|
||||
if (uptr == NULL)
|
||||
return SCPE_IERR;
|
||||
dptr = find_dev_from_unit(uptr);
|
||||
if (dptr == NULL)
|
||||
return SCPE_IERR;
|
||||
dibp = (DIB *) dptr->ctxt;
|
||||
|
||||
if (dibp == NULL)
|
||||
return SCPE_IERR;
|
||||
new_chan = get_uint(cptr, 10, 37, &r);
|
||||
if (r != SCPE_OK)
|
||||
return r;
|
||||
if (new_chan < 4) /* Lowest channel is 4 */
|
||||
return SCPE_ARG;
|
||||
/* Find channel device is current on and remove it */
|
||||
if (dibp->type & MULT_DEV) {
|
||||
cur_chan = GET_UADDR(dptr->flags);
|
||||
} else {
|
||||
cur_chan = GET_UADDR(uptr->flags);
|
||||
}
|
||||
if (dibp == devs[cur_chan])
|
||||
devs[cur_chan] = NULL;
|
||||
/* If device is disabled, set to whatever the user wants */
|
||||
if (dptr->flags & DEV_DIS) {
|
||||
if (dibp->type & MULT_DEV) {
|
||||
dptr->flags &= ~UNIT_M_ADDR;
|
||||
dptr->flags |= UNIT_ADDR(new_chan);
|
||||
} else {
|
||||
uptr->flags &= ~UNIT_M_ADDR;
|
||||
uptr->flags |= UNIT_ADDR(new_chan);
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
if (devs[new_chan] == NULL) {
|
||||
if (dibp->type & MULT_DEV) {
|
||||
dptr->flags &= ~UNIT_M_ADDR;
|
||||
dptr->flags |= UNIT_ADDR(new_chan);
|
||||
} else {
|
||||
uptr->flags &= ~UNIT_M_ADDR;
|
||||
uptr->flags |= UNIT_ADDR(new_chan);
|
||||
}
|
||||
devs[new_chan] = dibp;
|
||||
return SCPE_OK;
|
||||
} else {
|
||||
fprintf(stderr, "Device already on channel %d\n", new_chan);
|
||||
}
|
||||
return SCPE_ARG;
|
||||
}
|
||||
|
||||
/* Print the channel the device is on */
|
||||
t_stat
|
||||
get_chan(FILE *st, UNIT *uptr, int32 v, CONST void *desc)
|
||||
{
|
||||
DEVICE *dptr;
|
||||
DIB *dibp;
|
||||
int chan;
|
||||
|
||||
if (uptr == NULL)
|
||||
return SCPE_IERR;
|
||||
dptr = find_dev_from_unit(uptr);
|
||||
if (dptr == NULL)
|
||||
return SCPE_IERR;
|
||||
dibp = (DIB *) dptr->ctxt;
|
||||
if (dibp == NULL)
|
||||
return SCPE_IERR;
|
||||
if (dibp->type & MULT_DEV) {
|
||||
chan = GET_UADDR(dptr->flags);
|
||||
} else {
|
||||
chan = GET_UADDR(uptr->flags);
|
||||
}
|
||||
fprintf(st, "DEV=%d", chan);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
int
|
||||
get_ccw(int dev, uint32 *addr, uint8 type) {
|
||||
int cw_addr;
|
||||
uint32 cw0; /* Holding registers for current control word */
|
||||
uint32 cw1;
|
||||
|
||||
if (io_flags & EXT_IO) {
|
||||
cw_addr = 256+4*dev;
|
||||
cw0 = M[cw_addr];
|
||||
cw1 = M[cw_addr+1];
|
||||
*addr = cw1;
|
||||
if (cw0 & WORDCCW) {
|
||||
if (cw0 & BACKWARD)
|
||||
cw1 = ((cw1 + M22) & M22) | (cw1 & CMASK);
|
||||
else
|
||||
cw1 = ((cw1 + 1) & M22) | (cw1 & CMASK);
|
||||
} else {
|
||||
if (cw0 & BACKWARD) {
|
||||
if (cw1 & CMASK) {
|
||||
cw1 -= B1;
|
||||
} else {
|
||||
cw1 = ((cw1 - 1) & M22) | CMASK;
|
||||
}
|
||||
} else {
|
||||
if ((cw1 & CMASK) == CMASK) {
|
||||
cw1 = (cw1 + 1) & M22;
|
||||
} else {
|
||||
cw1 += B1;
|
||||
}
|
||||
}
|
||||
}
|
||||
cw0 = ((cw0 - 1) & M15) | (cw0 & CNTMSK);
|
||||
if ((cw0 & M15) == 0) {
|
||||
if ((cw0 & (CWRECHARGE|GATHER)) == (CWRECHARGE)) {
|
||||
cw0 = M[cw_addr+2];
|
||||
cw1 = M[cw_addr+3];
|
||||
} else if ((cw0 & GATHER) != 0) {
|
||||
int a;
|
||||
if ((cw0 & CWRECHARGE) != 0)
|
||||
M[cw_addr+3] = M[cw_addr+2];
|
||||
a = M[cw_addr+3];
|
||||
cw0 = M[a & M22];
|
||||
cw1 = M[(a + 1) & M22];
|
||||
M[cw_addr+3] = ((a + 2) & M22) | (a & CMASK);
|
||||
}
|
||||
M[cw_addr] = cw0;
|
||||
M[cw_addr+1] = cw1;
|
||||
return (cw0 & M15) == 0;
|
||||
}
|
||||
M[cw_addr] = cw0;
|
||||
M[cw_addr+1] = cw1;
|
||||
} else {
|
||||
cw_addr = 64+dev;
|
||||
cw0 = M[cw_addr];
|
||||
if (type & WORD_DEV) {
|
||||
*addr = cw0 & M15;
|
||||
cw0 = ((cw0 + 1) & M15) | ((cw0 + CNTMSK) & CNTMSK);
|
||||
cw1 = cw0 & CNTMSK;
|
||||
} else {
|
||||
*addr = cw0 & (CMASK|M15);
|
||||
if ((cw0 & CMASK) == CMASK) {
|
||||
cw0 = ((cw0 + 1) & M15) | (cw0 & CHCMSK);
|
||||
} else {
|
||||
cw0 += B1;
|
||||
}
|
||||
cw1 = (cw0 + CHCMSK) & CHCMSK;
|
||||
cw0 = ((CMASK|M15) & cw0) | cw1;
|
||||
}
|
||||
M[cw_addr] = cw0;
|
||||
if (cw1 == 0) {
|
||||
if (type & LONG_BLK) {
|
||||
cw1 = (M[cw_addr + 64] - 1) & FMASK;
|
||||
M[cw_addr + 64] = cw1;
|
||||
}
|
||||
if (type & SPEC_HES) {
|
||||
M[cw_addr] = M[cw_addr+1];
|
||||
return 0;
|
||||
}
|
||||
return (cw1 == 0);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Talk to non-standard interface devices */
|
||||
void
|
||||
chan_nsi_cmd(int dev, uint32 cmd) {
|
||||
DIB *dibp = devs[dev & 077];
|
||||
|
||||
if (dibp != NULL && dibp->nsi_cmd != NULL) {
|
||||
(dibp->nsi_cmd)(dev, cmd);
|
||||
}
|
||||
}
|
||||
|
||||
/* Talk to non-standard interface devices */
|
||||
void
|
||||
chan_nsi_status(int dev, uint32 *resp) {
|
||||
DIB *dibp = devs[dev & 077];
|
||||
|
||||
*resp = 0;
|
||||
if (dibp != NULL && dibp->nsi_cmd != NULL) {
|
||||
(dibp->nsi_status)(dev, resp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Hessitation operations */
|
||||
void
|
||||
chan_send_cmd(int dev, uint32 cmd, uint32 *resp) {
|
||||
DIB *dibp = devs[dev & 077];
|
||||
|
||||
*resp = 0;
|
||||
if (dibp != NULL && dibp->si_cmd != NULL) {
|
||||
(dibp->si_cmd)(dev, cmd, resp);
|
||||
}
|
||||
}
|
||||
|
||||
/* Transfer date between device and memory */
|
||||
int
|
||||
chan_input_char(int dev, uint8 *data, int eor) {
|
||||
DIB *dibp = devs[dev & 077];
|
||||
int r;
|
||||
int c;
|
||||
uint32 addr;
|
||||
uint32 mb;
|
||||
|
||||
/* Make sure device assign here */
|
||||
if (dibp == NULL)
|
||||
return -1;
|
||||
|
||||
/* Check if right type */
|
||||
if ((dibp->type & WORD_DEV) != 0)
|
||||
return -2;
|
||||
|
||||
/* Get address of next character. */
|
||||
r = get_ccw(dev, &addr, dibp->type);
|
||||
c = (addr >> 22) & 3;
|
||||
c = 6 * (3 - c);
|
||||
addr &= M22;
|
||||
if (addr < 8)
|
||||
mb = XR[addr];
|
||||
else
|
||||
mb = M[addr];
|
||||
mb &= ~(077 << c);
|
||||
mb |= ((uint32)(*data) & 077) << c;
|
||||
if (addr < 8)
|
||||
XR[addr] = mb;
|
||||
else
|
||||
M[addr] = mb;
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
chan_output_char(int dev, uint8 *data, int eor) {
|
||||
DIB *dibp = devs[dev & 077];
|
||||
int r;
|
||||
int c;
|
||||
uint32 addr;
|
||||
uint32 mb;
|
||||
|
||||
/* Make sure device assigne here */
|
||||
if (dibp == NULL)
|
||||
return -1;
|
||||
|
||||
/* Check if right type */
|
||||
if ((dibp->type & WORD_DEV) != 0)
|
||||
return -2;
|
||||
|
||||
/* Get address of next character. */
|
||||
r = get_ccw(dev, &addr, dibp->type);
|
||||
c = (addr >> 22) & 3;
|
||||
c = 6 * (3 - c);
|
||||
addr &= M22;
|
||||
if (addr < 8)
|
||||
mb = XR[addr];
|
||||
else
|
||||
mb = M[addr];
|
||||
*data = (uint8)(mb >> c) & 077;
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
chan_input_word(int dev, uint32 *data, int eor) {
|
||||
DIB *dibp = devs[dev & 077];
|
||||
int r;
|
||||
uint32 addr;
|
||||
|
||||
/* Make sure device assigne here */
|
||||
if (dibp == NULL)
|
||||
return -1;
|
||||
|
||||
/* Check if right type */
|
||||
if ((dibp->type & WORD_DEV) == 0)
|
||||
return -2;
|
||||
|
||||
/* Get address of next word. */
|
||||
r = get_ccw(dev, &addr, dibp->type);
|
||||
addr &= M22;
|
||||
if (addr < 8)
|
||||
XR[addr] = *data;
|
||||
else
|
||||
M[addr] = *data;
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
chan_output_word(int dev, uint32 *data, int eor) {
|
||||
DIB *dibp = devs[dev & 077];
|
||||
int r;
|
||||
uint32 addr;
|
||||
|
||||
/* Make sure device assigne here */
|
||||
if (dibp == NULL)
|
||||
return -1;
|
||||
|
||||
/* Check if right type */
|
||||
if ((dibp->type & WORD_DEV) == 0)
|
||||
return -2;
|
||||
|
||||
/* Get address of next word. */
|
||||
r = get_ccw(dev, &addr, dibp->type);
|
||||
addr &= M22;
|
||||
if (addr < 8)
|
||||
*data = XR[addr];
|
||||
else
|
||||
*data = M[addr];
|
||||
return r;
|
||||
}
|
||||
|
||||
void
|
||||
chan_set_done(int dev) {
|
||||
if (dev < 22)
|
||||
SR64 |= B2 >> dev;
|
||||
else
|
||||
SR65 |= B1 >> (dev - 24);
|
||||
}
|
||||
|
||||
void
|
||||
chan_clr_done(int dev) {
|
||||
if (dev < 22)
|
||||
SR64 &= ~(B2 >> dev);
|
||||
else
|
||||
SR65 &= ~(B1 >> (dev - 24));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -46,7 +46,13 @@ int32 sim_emax = 1;
|
||||
|
||||
DEVICE *sim_devices[] = {
|
||||
&cpu_dev,
|
||||
&cty_dev,
|
||||
&cty_dev, /* Must be first device after CPU */
|
||||
#if NUM_DEVS_PTR > 0
|
||||
&ptr_dev,
|
||||
#endif
|
||||
#if NUM_DEVS_PTP > 0
|
||||
&ptp_dev,
|
||||
#endif
|
||||
#if NUM_DEVS_CDR > 0
|
||||
&cdr_dev,
|
||||
#endif
|
||||
@@ -99,7 +105,7 @@ uint8 mem_to_ascii[64] = {
|
||||
/* x0 x1 x2 x3 x4 x5 x6 x7 */
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', /* 0x */
|
||||
'8', '9', ':', ';', '<', '=', '>', '?', /* 1x */
|
||||
' ', '!', '"', '#', '{', '%', '&', '\'', /* 2x */
|
||||
' ', '!', '"', '#', '\\', '%', '&', '\'', /* 2x */
|
||||
'(', ')', '*', '+', ',', '-', '.', '/', /* 3x */
|
||||
'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* 4x */
|
||||
'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', /* 5x */
|
||||
@@ -132,7 +138,7 @@ const char ascii_to_mem[128] = {
|
||||
/* P Q R S T U V W */
|
||||
060, 061, 062, 063, 064, 065, 066, 067,
|
||||
/* X Y Z [ \ ] ^ _ */
|
||||
070, 071, 072, 073, -1, 075, 076, 077,
|
||||
070, 071, 072, 073, 024, 075, 076, 077,
|
||||
/* ` a b c d e f g */
|
||||
-1, 041, 042, 043, 044, 045, 046, 047, /* 14 -1 177 */
|
||||
/* h i j k l m n o */
|
||||
@@ -155,7 +161,33 @@ sim_load(FILE * fileref, CONST char *cptr, CONST char *fnam, int flag)
|
||||
uint8 image[80];
|
||||
int checksum;
|
||||
|
||||
if (match_ext(fnam, "txt")) {
|
||||
if (match_ext(fnam, "card")) {
|
||||
|
||||
addr = 0;
|
||||
while (fgets(buffer, 100, fileref)) {
|
||||
/* Convert bits into image */
|
||||
memset(image, 0, sizeof(image));
|
||||
for (j = 0; j < 80; j++) {
|
||||
if (buffer[j] == '\n')
|
||||
break;
|
||||
image[j] = ascii_to_mem[buffer[j]];
|
||||
if (image[j] < 0) {
|
||||
fprintf(stderr, "Char %c: %s", buffer[j], buffer);
|
||||
return SCPE_FMT;
|
||||
}
|
||||
}
|
||||
for (j = 0; j < 64; ) {
|
||||
data = 0;
|
||||
for (k = 0; k < 4; k++)
|
||||
data = (data << 6) | image[j++];
|
||||
fprintf(stderr, "Addr: %06o %08o\n\r", addr, data);
|
||||
if (addr < 8)
|
||||
XR[addr++] = data;
|
||||
else
|
||||
M[addr++] = data;
|
||||
}
|
||||
}
|
||||
} else if (match_ext(fnam, "txt")) {
|
||||
|
||||
while (fgets(buffer, 100, fileref)) {
|
||||
/* Convert bits into image */
|
||||
@@ -201,9 +233,31 @@ sim_load(FILE * fileref, CONST char *cptr, CONST char *fnam, int flag)
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
checksum = 0;
|
||||
for (j = 0; j < 4; j++)
|
||||
checksum = (checksum << 6) | image[j];
|
||||
addr = 0;
|
||||
for (; j < 8; j++)
|
||||
addr = (addr << 6) | image[j];
|
||||
checksum += addr;
|
||||
RC = addr;
|
||||
data = 0;
|
||||
for (i = 3; i < image[1]; i++) {
|
||||
data = 0;
|
||||
for (k = 0; k < 4; k++)
|
||||
data = (data << 6) | image[j++];
|
||||
checksum += data;
|
||||
}
|
||||
for (k = 0; k < 4; k++)
|
||||
data = (data << 6) | image[j++];
|
||||
data = FMASK & (checksum + data);
|
||||
if (data != 0)
|
||||
fprintf(stderr, "Check %08o %08o: %s", addr, data, buffer);
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
fprintf(stderr, "%o %c%c%c%c\n", image[3],buffer[4], buffer[5], buffer[6], buffer[7]);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "B? :%s", buffer);
|
||||
|
||||
459
ICL1900/icl1900_tp.c
Normal file
459
ICL1900/icl1900_tp.c
Normal file
@@ -0,0 +1,459 @@
|
||||
/* icl1900_tp.c: ICL1900 Paper Tape Punch simulator
|
||||
|
||||
Copyright (c) 2018, Richard Cornwell
|
||||
|
||||
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
|
||||
RICHARD CORNWELL 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 Richard Cornwell shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Richard Cornwell
|
||||
|
||||
*/
|
||||
|
||||
#include "icl1900_defs.h"
|
||||
|
||||
#ifndef NUM_DEVS_PTP
|
||||
#define NUM_DEVS_PTP 0
|
||||
#endif
|
||||
|
||||
#define PP_V_MODE (UNIT_V_UF + 0)
|
||||
#define PP_M_MODE (1 << PP_V_MODE)
|
||||
#define UNIT_V_TYPE (UNIT_V_UF + 1)
|
||||
#define UNIT_TYPE (0xf << UNIT_V_TYPE)
|
||||
#define GET_TYPE(x) ((UNIT_TYPE & (x)) >> UNIT_V_TYPE)
|
||||
#define SET_TYPE(x) (UNIT_TYPE & ((x) << UNIT_V_TYPE))
|
||||
|
||||
#define NSI_TYPE(x) ((GET_TYPE(x) & 1) == 0)
|
||||
#define SI_TYPE(x) ((GET_TYPE(x) & 1) != 0)
|
||||
#define PP_MODE_7B 0
|
||||
#define PP_MODE_7P 1
|
||||
|
||||
#define CMD u3
|
||||
#define STATUS u4
|
||||
#define HOLD u5
|
||||
|
||||
#define ALPHA_MODE 0001
|
||||
#define BETA_MODE 0000
|
||||
#define BIN_MODE 0002
|
||||
#define PUN_BLNK 0004
|
||||
#define DISC 0010
|
||||
#define BUSY 0020
|
||||
#define DELTA_MODE 0040
|
||||
|
||||
#define TERMINATE 001
|
||||
#define OPAT 002
|
||||
#define ERROR 004
|
||||
#define ACCEPT 020
|
||||
|
||||
#define ALPHA_SHIFT 074
|
||||
#define BETA_SHIFT 075
|
||||
#define DELTA_SHIFT 076
|
||||
|
||||
#if (NUM_DEVS_PTP > 0)
|
||||
|
||||
#define T1925_1 0
|
||||
#define T1925_2 1
|
||||
#define T1926_1 2
|
||||
#define T1926_2 3
|
||||
|
||||
#define UNIT_PTP(x) UNIT_ADDR(x)|SET_TYPE(T1925_2)|UNIT_ATTABLE|\
|
||||
UNIT_DISABLE|UNIT_TEXT|TT_MODE_7B
|
||||
|
||||
/*
|
||||
* Character translation.
|
||||
*
|
||||
* Alpha shift 074
|
||||
* Beta shift 075
|
||||
* Delta shift 076
|
||||
*
|
||||
* p000xxxx Delta + 01xxxx
|
||||
* p001xxxx Delta + 00xxxx
|
||||
* p10111xx Delta + 1101xx
|
||||
* p11111xx Delta + 1110xx
|
||||
* p010xxxx 01xxxx
|
||||
* p011xxxx 00xxxx
|
||||
* p100xxxx Alpha + 10xxxx
|
||||
* p101xxxx Alpha + 11xxxx xxxx < 4
|
||||
* p110xxxx Beta + 10xxxx
|
||||
* p111xxxx Beta + 11xxxx xxxx < 4
|
||||
*
|
||||
* Two modes Alpha and Beta. Delta is always output.
|
||||
*
|
||||
* Graphics mode translation.
|
||||
*
|
||||
* p010xxxx 01xxxx
|
||||
* p011xxxx 00xxxx
|
||||
* p100xxxx 10xxxx
|
||||
* p101xxxx 11xxxx
|
||||
* p110xxxx 10xxxx
|
||||
* p111xxxx 11xxxx
|
||||
*
|
||||
*/
|
||||
|
||||
void ptp_cmd (int dev, uint32 cmd, uint32 *resp);
|
||||
void ptp_nsi_cmd (int dev, uint32 cmd);
|
||||
void ptp_nsi_status (int dev, uint32 *resp);
|
||||
t_stat ptp_svc (UNIT *uptr);
|
||||
t_stat ptp_reset (DEVICE *dptr);
|
||||
t_stat ptp_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
|
||||
CONST char *ptp_description (DEVICE *dptr);
|
||||
|
||||
DIB ptp_dib = { CHAR_DEV, &ptp_cmd, &ptp_nsi_cmd, &ptp_nsi_status };
|
||||
|
||||
UNIT ptp_unit[] = {
|
||||
{ UDATA (&ptp_svc, UNIT_PTP(6), 0), 10000 },
|
||||
{ UDATA (&ptp_svc, UNIT_PTP(7), 0), 10000 },
|
||||
};
|
||||
|
||||
|
||||
MTAB ptp_mod[] = {
|
||||
{ PP_M_MODE, PP_MODE_7B, "7b", "7B", NULL },
|
||||
{ PP_M_MODE, PP_MODE_7P, "7p", "7P", NULL },
|
||||
{ UNIT_TYPE, SET_TYPE(T1925_1), "1925/1", "1925/1", NULL, NULL, "ICL 1925/1 NSI 300CPM punch."},
|
||||
{ UNIT_TYPE, SET_TYPE(T1925_2), "1925/2", "1925/2", NULL, NULL, "ICL 1922/2 SI 300CPM punch."},
|
||||
{ UNIT_TYPE, SET_TYPE(T1926_1), "1926/1", "1926/1", NULL, NULL, "ICL 1926/1 NSI 1000CPM punch."},
|
||||
{ UNIT_TYPE, SET_TYPE(T1926_2), "1926/2", "1926/2", NULL, NULL, "ICL 1926/2 SI 1000CPM punch."},
|
||||
{MTAB_XTD | MTAB_VDV | MTAB_VALR, 0, "DEV", "DEV", &set_chan, &get_chan, NULL, "Device Number"},
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
DEVICE ptp_dev = {
|
||||
"TP", ptp_unit, NULL, ptp_mod,
|
||||
NUM_DEVS_PTP, 8, 22, 1, 8, 22,
|
||||
NULL, NULL, &ptp_reset, NULL, &attach_unit, &detach_unit,
|
||||
&ptp_dib, DEV_DISABLE | DEV_DEBUG, 0, dev_debug,
|
||||
NULL, NULL, &ptp_help, NULL, NULL, &ptp_description
|
||||
};
|
||||
|
||||
/*
|
||||
* Command codes
|
||||
*
|
||||
* 001xxx Write
|
||||
* 001xx0 Start in current shift
|
||||
* 001xx1 Start in alpha shift
|
||||
* 001x1x Graphics
|
||||
* 001x0x BCD.
|
||||
* 0011xx Punch Blank characters.
|
||||
* 0010xx Punch characters.
|
||||
* 010000 Send Q.
|
||||
* 010100 Send P.
|
||||
* 011110 Disconnect.
|
||||
*/
|
||||
|
||||
|
||||
void ptp_cmd(int dev, uint32 cmd, uint32 *resp) {
|
||||
int i;
|
||||
UNIT *uptr = NULL;
|
||||
|
||||
*resp = 0;
|
||||
/* Find the unit from dev */
|
||||
for (i = 0; i < NUM_DEVS_PTP; i++) {
|
||||
if (GET_UADDR(ptp_unit[i].flags) == dev) {
|
||||
uptr = &ptp_unit[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Should not happen, but just in case */
|
||||
if (uptr == NULL)
|
||||
return;
|
||||
|
||||
/* Ignore this command if not a SI device */
|
||||
if (NSI_TYPE(uptr->flags))
|
||||
return;
|
||||
|
||||
if ((uptr->flags & UNIT_ATT) == 0)
|
||||
return;
|
||||
|
||||
cmd &= 077;
|
||||
switch(cmd & 070) {
|
||||
case 010: /* Command */
|
||||
if ((uptr->flags & UNIT_ATT) == 0)
|
||||
break;
|
||||
if (uptr->CMD & BUSY) {
|
||||
*resp = 3;
|
||||
break;
|
||||
}
|
||||
if (cmd & 1)
|
||||
uptr->CMD = 0;
|
||||
uptr->CMD &= DELTA_MODE|1;
|
||||
uptr->CMD |= BUSY | (cmd & 07);
|
||||
uptr->STATUS = 0;
|
||||
sim_activate(uptr, uptr->wait);
|
||||
chan_clr_done(GET_UADDR(uptr->flags));
|
||||
*resp = 5;
|
||||
break;
|
||||
|
||||
case 020: if (cmd == 020) { /* Send Q */
|
||||
if ((uptr->flags & UNIT_ATT) == 0)
|
||||
*resp = 040;
|
||||
if (uptr->STATUS & 06)
|
||||
*resp = 040;
|
||||
*resp |= uptr->STATUS & TERMINATE;
|
||||
} else if (cmd == 024) { /* Send P */
|
||||
if ((uptr->flags & UNIT_ATT) != 0)
|
||||
*resp = (uptr->STATUS & ERROR) | 1;
|
||||
uptr->STATUS = 0;
|
||||
chan_clr_done(GET_UADDR(uptr->flags));
|
||||
}
|
||||
break;
|
||||
|
||||
case 030: if (cmd == 036) { /* Disconnect */
|
||||
uptr->CMD |= DISC;
|
||||
*resp = 5;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Command codes
|
||||
*
|
||||
* xxxx01 Start punch.
|
||||
* xxxx10 Stop punch.
|
||||
* xx1xxx Start in Previous shift, else alpha.
|
||||
* x1xxxx Graphics mode.
|
||||
* 1xxxxx Punch blanks.
|
||||
*/
|
||||
void ptp_nsi_cmd(int dev, uint32 cmd) {
|
||||
int i;
|
||||
UNIT *uptr = NULL;
|
||||
|
||||
/* Find the unit from dev */
|
||||
for (i = 0; i < NUM_DEVS_PTP; i++) {
|
||||
if (GET_UADDR(ptp_unit[i].flags) == dev) {
|
||||
uptr = &ptp_unit[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Should not happen, but just in case */
|
||||
if (uptr == NULL)
|
||||
return;
|
||||
|
||||
/* Ignore this command if not a SI device */
|
||||
if (SI_TYPE(uptr->flags))
|
||||
return;
|
||||
|
||||
|
||||
if (cmd & 02) {
|
||||
if (uptr->CMD & BUSY)
|
||||
uptr->CMD |= DISC;
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmd & 01) {
|
||||
if (uptr->CMD & BUSY || (uptr->flags & UNIT_ATT) == 0) {
|
||||
uptr->STATUS |= OPAT;
|
||||
chan_set_done(GET_UADDR(uptr->flags));
|
||||
return;
|
||||
}
|
||||
if (cmd & 010)
|
||||
uptr->CMD &= ALPHA_MODE;
|
||||
else
|
||||
uptr->CMD = ALPHA_MODE;
|
||||
if (cmd & 020)
|
||||
uptr->CMD |= BIN_MODE;
|
||||
if ((cmd & 040) == 0)
|
||||
uptr->CMD |= PUN_BLNK;
|
||||
uptr->CMD |= BUSY;
|
||||
uptr->STATUS = 0;
|
||||
sim_activate(uptr, uptr->wait);
|
||||
chan_clr_done(GET_UADDR(uptr->flags));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* NSI Status bits.
|
||||
*
|
||||
* 001 End.
|
||||
* 002 Opat.
|
||||
* 004 ERROR
|
||||
* 020 ACCEPT
|
||||
* 040 BUSY
|
||||
*/
|
||||
void ptp_nsi_status(int dev, uint32 *resp) {
|
||||
int i;
|
||||
UNIT *uptr = NULL;
|
||||
|
||||
*resp = 0;
|
||||
/* Find the unit from dev */
|
||||
for (i = 0; i < NUM_DEVS_PTP; i++) {
|
||||
if (GET_UADDR(ptp_unit[i].flags) == dev) {
|
||||
uptr = &ptp_unit[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Should not happen, but just in case */
|
||||
if (uptr == NULL)
|
||||
return;
|
||||
|
||||
/* Ignore this command if not a SI device */
|
||||
if (SI_TYPE(uptr->flags))
|
||||
return;
|
||||
|
||||
*resp = uptr->STATUS;
|
||||
if (uptr->CMD & BUSY)
|
||||
*resp |= 040;
|
||||
uptr->STATUS = 0;
|
||||
chan_clr_done(GET_UADDR(uptr->flags));
|
||||
}
|
||||
|
||||
|
||||
|
||||
t_stat ptp_svc (UNIT *uptr)
|
||||
{
|
||||
t_stat r;
|
||||
uint8 ch;
|
||||
int data;
|
||||
int eor;
|
||||
|
||||
/* Handle a disconnect request */
|
||||
if (uptr->CMD & DISC) {
|
||||
uptr->CMD &= 1;
|
||||
chan_set_done(GET_UADDR(uptr->flags));
|
||||
return SCPE_OK;
|
||||
}
|
||||
/* If not busy, false schedule, just exit */
|
||||
if ((uptr->CMD & BUSY) == 0)
|
||||
return SCPE_OK;
|
||||
|
||||
/* Check if attached */
|
||||
if ((uptr->flags & UNIT_ATT) == 0) {
|
||||
uptr->CMD &= 1;
|
||||
uptr->STATUS = TERMINATE;
|
||||
chan_set_done(GET_UADDR(uptr->flags));
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
eor = chan_output_char(GET_UADDR(uptr->flags), &ch, 0);
|
||||
if ((uptr->CMD & PUN_BLNK) != 0) {
|
||||
data = 0400;
|
||||
} else if (uptr->CMD & BIN_MODE) {
|
||||
data = ch & 017;
|
||||
switch (ch & 060) {
|
||||
case 0000: data |= 060; break;
|
||||
case 0020: data |= 040; break;
|
||||
case 0040: data |= 0100; break;
|
||||
case 0060: data |= 0120; break;
|
||||
}
|
||||
} else {
|
||||
data = 0;
|
||||
if (ch == ALPHA_SHIFT) {
|
||||
uptr->CMD &= BUSY|DISC|BIN_MODE|PUN_BLNK;
|
||||
uptr->CMD |= ALPHA_MODE;
|
||||
} else if (ch == BETA_SHIFT) {
|
||||
uptr->CMD &= BUSY|DISC|BIN_MODE|PUN_BLNK;
|
||||
uptr->CMD |= BETA_MODE;
|
||||
} else if (ch == DELTA_SHIFT) {
|
||||
uptr->CMD &= BUSY|DISC|BIN_MODE|PUN_BLNK|ALPHA_SHIFT;
|
||||
uptr->CMD |= DELTA_MODE;
|
||||
} else if (ch == 077) {
|
||||
uptr->CMD &= BUSY|DISC|BIN_MODE|PUN_BLNK|ALPHA_SHIFT;
|
||||
} else {
|
||||
if (uptr->CMD & DELTA_MODE) {
|
||||
uptr->CMD &= ~DELTA_MODE;
|
||||
data = ch;
|
||||
if (ch & 040)
|
||||
data |= 0174 ^ ((ch & 020) << 1);
|
||||
} else if (uptr->CMD & ALPHA_MODE) {
|
||||
data = ch & 017;
|
||||
switch (ch & 060) {
|
||||
case 0000: data |= 060; break;
|
||||
case 0020: data |= 040; break;
|
||||
case 0040: data |= 0100; break;
|
||||
case 0060: data |= 0120; break;
|
||||
}
|
||||
} else {
|
||||
data = ch & 017;
|
||||
switch (ch & 060) {
|
||||
case 0000: data |= 060; break;
|
||||
case 0020: data |= 040; break;
|
||||
case 0040: data |= 0140; break;
|
||||
case 0060: data |= 0160; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (data != 0) {
|
||||
/* Check parity is even */
|
||||
if ((uptr->flags & PP_M_MODE) == PP_MODE_7P) {
|
||||
data &= 0177;
|
||||
ch = data ^ (data << 4);
|
||||
ch = ch ^ (ch << 2);
|
||||
ch = ch ^ (ch << 1);
|
||||
data |= ch;
|
||||
}
|
||||
fputc(data, uptr->fileref);
|
||||
uptr->pos = ftell(uptr->fileref);
|
||||
if (ferror (uptr->fileref)) {
|
||||
uptr->STATUS |= TERMINATE|ERROR;
|
||||
uptr->CMD &= DELTA_MODE|1;
|
||||
chan_set_done(GET_UADDR(uptr->flags));
|
||||
return SCPE_OK;
|
||||
}
|
||||
}
|
||||
/* Check if Done */
|
||||
if (eor) {
|
||||
uptr->STATUS |= TERMINATE;
|
||||
uptr->CMD &= DELTA_MODE|1;
|
||||
chan_set_done(GET_UADDR(uptr->flags));
|
||||
return SCPE_OK;
|
||||
}
|
||||
sim_activate (uptr, uptr->wait); /* try again */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
|
||||
/* Reset */
|
||||
|
||||
t_stat ptp_reset (DEVICE *dptr)
|
||||
{
|
||||
UNIT *uptr = dptr->units;
|
||||
int unit;
|
||||
|
||||
for (unit = 0; unit < NUM_DEVS_PTP; unit++, uptr++) {
|
||||
uptr->CMD = ALPHA_MODE;
|
||||
uptr->STATUS = 0;
|
||||
uptr->HOLD = 0;
|
||||
chan_clr_done(GET_UADDR(uptr->flags));
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
|
||||
t_stat ptp_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||||
{
|
||||
fprintf (st, "The Paper Tape Punch can be set to one of two modes: 7P, or 7B.\n\n");
|
||||
fprintf (st, " mode \n");
|
||||
fprintf (st, " 7P Process even parity input tapes. \n");
|
||||
fprintf (st, " 7B Ignore parity of input data.\n");
|
||||
fprintf (st, "The default mode is 7B.\n");
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
CONST char *ptp_description (DEVICE *dptr)
|
||||
{
|
||||
return "PTP";
|
||||
|
||||
}
|
||||
#endif
|
||||
524
ICL1900/icl1900_tr.c
Normal file
524
ICL1900/icl1900_tr.c
Normal file
@@ -0,0 +1,524 @@
|
||||
/* icl1900_tr.c: ICL1900 Paper Tape Reader simulator
|
||||
|
||||
Copyright (c) 2018, Richard Cornwell
|
||||
|
||||
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
|
||||
RICHARD CORNWELL 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 Richard Cornwell shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Richard Cornwell
|
||||
|
||||
*/
|
||||
|
||||
#include "icl1900_defs.h"
|
||||
|
||||
#ifndef NUM_DEVS_PTR
|
||||
#define NUM_DEVS_PTR 0
|
||||
#endif
|
||||
|
||||
#define PP_V_MODE (UNIT_V_UF + 0)
|
||||
#define PP_M_MODE (1 << PP_V_MODE)
|
||||
#define UNIT_V_TYPE (UNIT_V_UF + 1)
|
||||
#define UNIT_TYPE (0xf << UNIT_V_TYPE)
|
||||
#define GET_TYPE(x) ((UNIT_TYPE & (x)) >> UNIT_V_TYPE)
|
||||
#define SET_TYPE(x) (UNIT_TYPE & ((x) << UNIT_V_TYPE))
|
||||
|
||||
#define NSI_TYPE(x) ((GET_TYPE(x) & 1) == 0)
|
||||
#define SI_TYPE(x) ((GET_TYPE(x) & 1) != 0)
|
||||
#define PP_MODE_7B 0
|
||||
#define PP_MODE_7P 1
|
||||
|
||||
|
||||
#define CMD u3
|
||||
#define STATUS u4
|
||||
#define HOLD u5
|
||||
|
||||
#define ALPHA_MODE 0001
|
||||
#define BETA_MODE 0000
|
||||
#define BIN_MODE 0002
|
||||
#define IGN_BLNK 0004
|
||||
#define DISC 0010
|
||||
#define BUSY 0020
|
||||
#define DELTA_MODE 0040
|
||||
#define STOP_CHAR 0100
|
||||
|
||||
#define TERMINATE 001
|
||||
#define OPAT 002
|
||||
#define ERROR 004
|
||||
#define ACCEPT 020
|
||||
|
||||
#define ALPHA_SHIFT 074
|
||||
#define BETA_SHIFT 075
|
||||
#define DELTA_SHIFT 076
|
||||
|
||||
#if (NUM_DEVS_PTR > 0)
|
||||
|
||||
#define T1915_1 0
|
||||
#define T1915_2 1
|
||||
#define T1916_1 2
|
||||
#define T1916_2 3
|
||||
|
||||
#define UNIT_PTR(x) UNIT_ADDR(x)|SET_TYPE(T1915_2)|UNIT_ATTABLE|\
|
||||
UNIT_DISABLE|UNIT_TEXT|UNIT_RO|TT_MODE_7B
|
||||
|
||||
/*
|
||||
* Character translation.
|
||||
*
|
||||
* Alpha shift 074
|
||||
* Beta shift 075
|
||||
* Delta shift 076
|
||||
*
|
||||
* p000xxxx Delta + 01xxxx
|
||||
* p001xxxx Delta + 00xxxx
|
||||
* p10111xx Delta + 1101xx
|
||||
* p11111xx Delta + 1110xx
|
||||
* p010xxxx 01xxxx
|
||||
* p011xxxx 00xxxx
|
||||
* p100xxxx Alpha + 10xxxx
|
||||
* p101xxxx Alpha + 11xxxx xxxx < 4
|
||||
* p110xxxx Beta + 10xxxx
|
||||
* p111xxxx Beta + 11xxxx xxxx < 4
|
||||
*
|
||||
* Two modes Alpha and Beta. Delta is always output.
|
||||
*
|
||||
* Graphics mode translation.
|
||||
*
|
||||
* p010xxxx 01xxxx
|
||||
* p011xxxx 00xxxx
|
||||
* p100xxxx 10xxxx
|
||||
* p101xxxx 11xxxx
|
||||
* p110xxxx 10xxxx
|
||||
* p111xxxx 11xxxx
|
||||
*
|
||||
*/
|
||||
|
||||
void ptr_cmd (int dev, uint32 cmd, uint32 *resp);
|
||||
void ptr_nsi_cmd (int dev, uint32 cmd);
|
||||
void ptr_nsi_status (int dev, uint32 *resp);
|
||||
t_stat ptr_svc (UNIT *uptr);
|
||||
t_stat ptr_reset (DEVICE *dptr);
|
||||
t_stat ptr_boot (int32 unit_num, DEVICE * dptr);
|
||||
t_stat ptr_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
|
||||
CONST char *ptr_description (DEVICE *dptr);
|
||||
|
||||
DIB ptr_dib = { CHAR_DEV, &ptr_cmd, &ptr_nsi_cmd, &ptr_nsi_status };
|
||||
|
||||
UNIT ptr_unit[] = {
|
||||
{ UDATA (&ptr_svc, UNIT_PTR(4), 0), 10000 },
|
||||
{ UDATA (&ptr_svc, UNIT_PTR(5), 0), 10000 },
|
||||
};
|
||||
|
||||
|
||||
MTAB ptr_mod[] = {
|
||||
{ PP_M_MODE, PP_MODE_7B, "7b", "7B", NULL },
|
||||
{ PP_M_MODE, PP_MODE_7P, "7p", "7P", NULL },
|
||||
{ UNIT_TYPE, SET_TYPE(T1915_1), "1915/1", "1915/1", NULL, NULL, "ICL 1915/1 NSI 300CPM reader."},
|
||||
{ UNIT_TYPE, SET_TYPE(T1915_2), "1915/2", "1915/2", NULL, NULL, "ICL 1912/2 SI 300CPM reader."},
|
||||
{ UNIT_TYPE, SET_TYPE(T1916_1), "1916/1", "1916/1", NULL, NULL, "ICL 1916/1 NSI 1000CPM reader."},
|
||||
{ UNIT_TYPE, SET_TYPE(T1916_2), "1916/2", "1916/2", NULL, NULL, "ICL 1916/2 SI 1000CPM reader."},
|
||||
{MTAB_XTD | MTAB_VDV | MTAB_VALR, 0, "DEV", "DEV", &set_chan, &get_chan, NULL, "Device Number"},
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
DEVICE ptr_dev = {
|
||||
"TR", ptr_unit, NULL, ptr_mod,
|
||||
NUM_DEVS_PTR, 8, 22, 1, 8, 22,
|
||||
NULL, NULL, &ptr_reset, &ptr_boot, &attach_unit, &detach_unit,
|
||||
&ptr_dib, DEV_DISABLE | DEV_DEBUG, 0, dev_debug,
|
||||
NULL, NULL, &ptr_help, NULL, NULL, &ptr_description
|
||||
};
|
||||
|
||||
/*
|
||||
* Command codes
|
||||
*
|
||||
* 001xxx Read
|
||||
* 001xx0 Start in current shift
|
||||
* 001xx1 Start in alpha shift
|
||||
* 001x1x Graphics
|
||||
* 001x0x BCD.
|
||||
* 0011xx Ignore blank tape and erase
|
||||
* 0010xx Read Blank and erase
|
||||
* 010000 Send Q.
|
||||
* 010100 Send P.
|
||||
* 011110 Disconnect.
|
||||
*/
|
||||
|
||||
|
||||
void ptr_cmd(int dev, uint32 cmd, uint32 *resp) {
|
||||
int i;
|
||||
UNIT *uptr = NULL;
|
||||
|
||||
*resp = 0;
|
||||
/* Find the unit from dev */
|
||||
for (i = 0; i < NUM_DEVS_PTR; i++) {
|
||||
if (GET_UADDR(ptr_unit[i].flags) == dev) {
|
||||
uptr = &ptr_unit[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Should not happen, but just in case */
|
||||
if (uptr == NULL)
|
||||
return;
|
||||
|
||||
/* Ignore this command if not a SI device */
|
||||
if (NSI_TYPE(uptr->flags))
|
||||
return;
|
||||
|
||||
if ((uptr->flags & UNIT_ATT) == 0)
|
||||
return;
|
||||
cmd &= 077;
|
||||
switch(cmd & 070) {
|
||||
case 010: /* Command */
|
||||
if ((uptr->flags & UNIT_ATT) == 0)
|
||||
break;
|
||||
if (uptr->CMD & BUSY) {
|
||||
*resp = 3;
|
||||
break;
|
||||
}
|
||||
sim_debug(DEBUG_CMD, &ptr_dev, "CMD: %03o %03o %03o\n", cmd, uptr->CMD, uptr->STATUS);
|
||||
uptr->CMD &= 1;
|
||||
uptr->CMD |= BUSY| (cmd & 07);
|
||||
uptr->STATUS = 0;
|
||||
sim_activate(uptr, uptr->wait);
|
||||
chan_clr_done(GET_UADDR(uptr->flags));
|
||||
*resp = 5;
|
||||
break;
|
||||
|
||||
case 020: if (cmd == 020) { /* Send Q */
|
||||
if ((uptr->flags & UNIT_ATT) != 0)
|
||||
*resp = 040;
|
||||
if (uptr->STATUS & 06)
|
||||
*resp = 040;
|
||||
*resp |= uptr->STATUS & TERMINATE;
|
||||
} else if (cmd == 024) { /* Send P */
|
||||
if ((uptr->flags & UNIT_ATT) != 0)
|
||||
*resp = (uptr->STATUS & ERROR) | 1;
|
||||
uptr->STATUS = 0;
|
||||
chan_clr_done(GET_UADDR(uptr->flags));
|
||||
}
|
||||
break;
|
||||
|
||||
case 030: if (cmd == 036) { /* Disconnect */
|
||||
uptr->CMD |= DISC;
|
||||
*resp = 5;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Command codes
|
||||
*
|
||||
* xxxx01 Start reader.
|
||||
* xxxx10 Stop reader.
|
||||
* xxx1xx Stop on return, else only stop on count.
|
||||
* xx1xxx Start in Previous shift, else alpha.
|
||||
* x1xxxx Graphics mode.
|
||||
* 1xxxxx All characters.
|
||||
*/
|
||||
void ptr_nsi_cmd(int dev, uint32 cmd) {
|
||||
int i;
|
||||
UNIT *uptr = NULL;
|
||||
|
||||
/* Find the unit from dev */
|
||||
for (i = 0; i < NUM_DEVS_PTR; i++) {
|
||||
if (GET_UADDR(ptr_unit[i].flags) == dev) {
|
||||
uptr = &ptr_unit[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Should not happen, but just in case */
|
||||
if (uptr == NULL)
|
||||
return;
|
||||
|
||||
/* Ignore this command if not a SI device */
|
||||
if (SI_TYPE(uptr->flags))
|
||||
return;
|
||||
|
||||
|
||||
if (cmd & 02) {
|
||||
if (uptr->CMD & BUSY)
|
||||
uptr->CMD |= DISC;
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmd & 01) {
|
||||
if (uptr->CMD & BUSY || (uptr->flags & UNIT_ATT) == 0) {
|
||||
uptr->STATUS |= OPAT;
|
||||
chan_set_done(GET_UADDR(uptr->flags));
|
||||
return;
|
||||
}
|
||||
if (cmd & 010)
|
||||
uptr->CMD &= ALPHA_MODE;
|
||||
else
|
||||
uptr->CMD = ALPHA_MODE;
|
||||
if (cmd & 004)
|
||||
uptr->CMD |= STOP_CHAR;
|
||||
if (cmd & 020)
|
||||
uptr->CMD |= BIN_MODE;
|
||||
if ((cmd & 040) == 0)
|
||||
uptr->CMD |= IGN_BLNK;
|
||||
uptr->CMD |= BUSY;
|
||||
uptr->STATUS = 0;
|
||||
sim_activate(uptr, uptr->wait);
|
||||
chan_clr_done(GET_UADDR(uptr->flags));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* NSI Status bits.
|
||||
*
|
||||
* 001 End.
|
||||
* 002 Opat.
|
||||
* 004 ERROR
|
||||
* 020 ACCEPT
|
||||
* 040 BUSY
|
||||
*/
|
||||
void ptr_nsi_status(int dev, uint32 *resp) {
|
||||
int i;
|
||||
UNIT *uptr = NULL;
|
||||
|
||||
*resp = 0;
|
||||
/* Find the unit from dev */
|
||||
for (i = 0; i < NUM_DEVS_PTR; i++) {
|
||||
if (GET_UADDR(ptr_unit[i].flags) == dev) {
|
||||
uptr = &ptr_unit[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Should not happen, but just in case */
|
||||
if (uptr == NULL)
|
||||
return;
|
||||
|
||||
/* Ignore this command if not a SI device */
|
||||
if (SI_TYPE(uptr->flags))
|
||||
return;
|
||||
|
||||
*resp = uptr->STATUS;
|
||||
if (uptr->CMD & BUSY)
|
||||
*resp |= 040;
|
||||
uptr->STATUS = 0;
|
||||
chan_clr_done(GET_UADDR(uptr->flags));
|
||||
}
|
||||
|
||||
t_stat ptr_svc (UNIT *uptr)
|
||||
{
|
||||
t_stat r;
|
||||
uint8 ch;
|
||||
uint8 shift = 0;
|
||||
int data;
|
||||
int eor;
|
||||
|
||||
/* Handle a disconnect request */
|
||||
if (uptr->CMD & DISC) {
|
||||
uptr->CMD &= 1;
|
||||
chan_set_done(GET_UADDR(uptr->flags));
|
||||
return SCPE_OK;
|
||||
}
|
||||
/* If not busy, false schedule, just exit */
|
||||
if ((uptr->CMD & BUSY) == 0)
|
||||
return SCPE_OK;
|
||||
if (uptr->HOLD != 0) {
|
||||
ch = uptr->HOLD & 077;
|
||||
uptr->HOLD = 0;
|
||||
eor = chan_input_char(GET_UADDR(uptr->flags), &ch, 0);
|
||||
if (eor) {
|
||||
uptr->CMD &= 1;
|
||||
chan_set_done(GET_UADDR(uptr->flags));
|
||||
uptr->STATUS = TERMINATE;
|
||||
return SCPE_OK;
|
||||
}
|
||||
if ((uptr->CMD & STOP_CHAR) != 0 && uptr->HOLD == 032)
|
||||
uptr->STATUS |= TERMINATE;
|
||||
}
|
||||
|
||||
/* Read next charater */
|
||||
if ((uptr->flags & UNIT_ATT) == 0 ||
|
||||
feof(uptr->fileref) ||
|
||||
(data = getc (uptr->fileref)) == EOF) {
|
||||
uptr->CMD &= 1;
|
||||
chan_set_done(GET_UADDR(uptr->flags));
|
||||
uptr->STATUS = TERMINATE;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
sim_debug(DEBUG_DATA, &ptr_dev, "data: %03o\n", data);
|
||||
/* Check parity is even */
|
||||
if ((uptr->flags & PP_M_MODE) == PP_MODE_7P) {
|
||||
ch = data ^ (data >> 4);
|
||||
ch = ch ^ (ch >> 2);
|
||||
ch = ch ^ (ch >> 1);
|
||||
if (ch != 0)
|
||||
uptr->STATUS = TERMINATE | ERROR;
|
||||
chan_set_done(GET_UADDR(uptr->flags));
|
||||
}
|
||||
data &= 0177;
|
||||
if ((data == 0 || data == 0177) && (uptr->CMD & IGN_BLNK) != 0) {
|
||||
sim_activate (uptr, uptr->wait); /* try again */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
if (uptr->CMD & BIN_MODE) {
|
||||
switch (data & 0160) {
|
||||
case 0000:
|
||||
case 0020: /* Terminate */
|
||||
uptr->STATUS |= TERMINATE;
|
||||
chan_set_done(GET_UADDR(uptr->flags));
|
||||
uptr->CMD &= 1;
|
||||
return SCPE_OK;
|
||||
case 0040:
|
||||
ch = 020 | (data & 017);
|
||||
break;
|
||||
case 0060:
|
||||
ch = 000 | (data & 017);
|
||||
break;
|
||||
case 0100:
|
||||
case 0140:
|
||||
ch = 040 | (data & 017);
|
||||
break;
|
||||
case 0120:
|
||||
case 0160:
|
||||
ch = 060 | (data & 017);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (data & 0160) {
|
||||
case 0000:
|
||||
case 0020:
|
||||
if ((uptr->CMD & STOP_CHAR) != 0 && data == 012)
|
||||
uptr->STATUS |= TERMINATE;
|
||||
shift = DELTA_SHIFT;
|
||||
break;
|
||||
case 0040:
|
||||
ch = 020 | (data & 017);
|
||||
break;
|
||||
case 0060:
|
||||
ch = 000 | (data & 017);
|
||||
break;
|
||||
case 0140:
|
||||
if ((data & 017) > 013) {
|
||||
shift = DELTA_SHIFT;
|
||||
ch = 070 | (data & 03);
|
||||
break;
|
||||
}
|
||||
case 0100:
|
||||
if ((uptr->CMD & 1) == BETA_MODE)
|
||||
shift = ALPHA_SHIFT;
|
||||
uptr->CMD |= ALPHA_MODE;
|
||||
ch = 040 | (data & 037);
|
||||
break;
|
||||
case 0160:
|
||||
if ((data & 017) > 013) {
|
||||
shift = DELTA_SHIFT;
|
||||
ch = 064 | (data & 03);
|
||||
break;
|
||||
}
|
||||
case 0120:
|
||||
if ((uptr->CMD & 1) == ALPHA_MODE)
|
||||
shift = BETA_SHIFT;
|
||||
uptr->CMD &= ~ALPHA_MODE;
|
||||
ch = 040 | (data & 037);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Check if error */
|
||||
if (shift != 0) {
|
||||
eor = chan_input_char(GET_UADDR(uptr->flags), &shift, 0);
|
||||
if (eor) {
|
||||
uptr->STATUS |= TERMINATE;
|
||||
chan_set_done(GET_UADDR(uptr->flags));
|
||||
uptr->CMD &= 1;
|
||||
uptr->HOLD = 0100 | ch;
|
||||
return SCPE_OK;
|
||||
}
|
||||
}
|
||||
eor = chan_input_char(GET_UADDR(uptr->flags), &ch, 0);
|
||||
if (eor) {
|
||||
uptr->STATUS |= TERMINATE;
|
||||
chan_set_done(GET_UADDR(uptr->flags));
|
||||
uptr->CMD &= 1;
|
||||
return SCPE_OK;
|
||||
}
|
||||
if (uptr->STATUS & TERMINATE) {
|
||||
chan_set_done(GET_UADDR(uptr->flags));
|
||||
uptr->CMD &= 1;
|
||||
return SCPE_OK;
|
||||
}
|
||||
sim_activate (uptr, uptr->wait); /* try again */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
|
||||
/* Reset */
|
||||
|
||||
t_stat ptr_reset (DEVICE *dptr)
|
||||
{
|
||||
UNIT *uptr = dptr->units;
|
||||
int unit;
|
||||
|
||||
for (unit = 0; unit < NUM_DEVS_PTR; unit++, uptr++) {
|
||||
uptr->CMD = ALPHA_MODE;
|
||||
uptr->STATUS = 0;
|
||||
uptr->HOLD = 0;
|
||||
chan_clr_done(GET_UADDR(uptr->flags));
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Boot from given device */
|
||||
t_stat
|
||||
ptr_boot(int32 unit_num, DEVICE * dptr)
|
||||
{
|
||||
UNIT *uptr = &dptr->units[unit_num];
|
||||
int chan = GET_UADDR(uptr->flags);
|
||||
|
||||
if ((uptr->flags & UNIT_ATT) == 0)
|
||||
return SCPE_UNATT; /* attached? */
|
||||
|
||||
M[64 + chan] = 0;
|
||||
M[256 + 4 * chan] = 0;
|
||||
M[257 + 4 * chan] = 020;
|
||||
loading = 1;
|
||||
uptr->CMD = BUSY|ALPHA_MODE|BIN_MODE|IGN_BLNK;
|
||||
sim_activate (uptr, uptr->wait);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
|
||||
t_stat ptr_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||||
{
|
||||
fprintf (st, "The Paper Tape Reader can be set to one of twp modes: 7P, or 7B.\n\n");
|
||||
fprintf (st, " mode \n");
|
||||
fprintf (st, " 7P Process even parity input tapes. \n");
|
||||
fprintf (st, " 7B Ignore parity of input data.\n");
|
||||
fprintf (st, "The default mode is 7B.\n");
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
CONST char *ptr_description (DEVICE *dptr)
|
||||
{
|
||||
return "PTR";
|
||||
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user