1
0
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:
Richard Cornwell
2018-08-20 01:00:32 -04:00
parent 7923fdedf2
commit 823456b35a
8 changed files with 2213 additions and 916 deletions

View File

@@ -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);
}

View File

@@ -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 */

View File

@@ -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";
}

View File

@@ -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;

View File

@@ -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));
}

View File

@@ -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
View 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
View 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