1
0
mirror of https://github.com/rcornwell/sims.git synced 2026-01-13 23:35:30 +00:00

ICL1900: Added support for standard I/O and console device.

This commit is contained in:
Richard Cornwell 2018-08-11 00:08:28 -04:00
parent 5439436f21
commit a809a48b56
7 changed files with 902 additions and 109 deletions

View File

@ -1087,7 +1087,8 @@ DISPLAYD = display
# Emulator source files and compile time options
#
ICL1900D = ./
ICL1900 = ${ICL1900D}icl1900_cpu.c ${ICL1900D}icl1900_sys.c
ICL1900 = ${ICL1900D}icl1900_cpu.c ${ICL1900D}icl1900_sys.c ${ICL1900D}icl1900_stdio.c \
${ICL1900D}icl1900_cty.c
ICL1900_OPT = -I.. -DUSE_SIM_CARD
#

36
ICL1900/div.c Normal file
View File

@ -0,0 +1,36 @@
#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

@ -105,12 +105,9 @@ uint8 RF; /* Function code */
uint32 RL; /* Limit register */
uint8 RG; /* General register */
uint32 RM; /* M field register */
uint32 RN; /* Current address */
uint32 RP; /* Temp register */
uint32 RS; /* Temp register */
uint32 RT; /* Temp register */
uint32 MB; /* Memory buffer */
uint32 MA; /* Memory address */
uint8 RX; /* X field register */
uint32 XR[8]; /* Index registers */
uint32 faccl; /* Floating point accumulator low */
@ -175,6 +172,8 @@ t_stat cpu_help(FILE *, DEVICE *, UNIT *, int32, const char *);
t_stat rtc_srv(UNIT * uptr);
int32 rtc_tps = 60 ;
int32 tmxr_poll = 10000;
/* CPU data structures
@ -323,13 +322,11 @@ t_stat
sim_instr(void)
{
t_stat reason;
uint32 temp;
uint32 temp2;
int x_reg;
int m;
int n;
uint32 temp; /* Hol order code being obeyed */
int m; /* Holds index register for address modification */
int n; /* Generic short term temp register */
int e1,e2; /* Temp for exponents */
int f;
int f; /* Used to hold flags */
reason = 0;
adrmask = (Mode & AM22) ? M22 : M15;
@ -513,7 +510,7 @@ obey:
RB = RB ^ FMASK;
BCarry = !BCarry;
}
temp2 = (RA & B0) != 0;
n = (RA & B0) != 0;
RA = RA + RB + BCarry;
if (RF & 04) {
if (RF & 02)
@ -524,7 +521,7 @@ obey:
} else {
int t2 = (RB & B0) != 0;
int tr = (RA & B0) != 0;
if ((temp2 && t2 && !tr) || (!temp2 && !t2 && tr))
if ((n && t2 && !tr) || (!n && !t2 && tr))
BV = 1;
BCarry = 0;
}
@ -609,9 +606,13 @@ obey:
break;
case OP_STOZ: /* Store Zero */
RA = 0;
#if 0 /* Stevenage Machines */
if (exe_mode)
XR[RX] = RA;
#endif
RB = 0;
BCarry = 0;
if (Mem_write(RS, &RA, 1)) {
if (Mem_write(RS, &RB, 1)) {
goto intr;
}
break;
@ -664,15 +665,15 @@ obey:
}
RP = RA;
RA = RB;
temp2 = RP & 1;
n = RP & 1;
RP >>= 1;
if (RF & 1) /* Multiply and Round */
RP |= B0;
RB = 0;
for(RK = 23; RK != 0; RK--) {
if (temp2)
if (n)
RB += RA;
temp2 = RP & 1;
n = RP & 1;
RP >>= 1;
if (RB & 1)
RP |= B0;
@ -681,11 +682,11 @@ obey:
RB >>= 1;
}
if (temp2) {
if (n) {
RB += (RA ^ FMASK) + 1;
}
temp2 = RP & 1; /* Check for MPR */
if (temp2 && RP & B0)
n = RP & 1; /* Check for MPR */
if (n && RP & B0)
RB++;
RP >>= 1;
if (RF == OP_MPA) {
@ -765,7 +766,7 @@ obey:
RB = XR[RX]; /* Dividend to RB/RP */
f =0;
//fprintf(stderr, "DVD: %08o %08o %08o - %3o C=%08o\n\r", RA, RP, RB, RF, RC);
if (RA == FMASK && RP == 1 && RB == 0)
if (RA == FMASK && RP == 1 && RB == 0) /* Flag special case */
f=1;
if (RA == 0) { /* Exit on zero divisor */ /* VI */
@ -774,7 +775,7 @@ obey:
break;
}
BCarry = (RP & B0) != 0;
temp = (RP | RB) == 0; /* Save zero dividend */
n = (RP | RB) == 0; /* Save zero dividend */
/* Setup for specific divide order code */ /* V11 */
if (RF & 2) { /* DVS */
@ -791,20 +792,20 @@ obey:
/* First partial remainder */ /* V12 */
if (((RB ^ RA) & B0) == 0) {
temp2 = RB + (RA ^ FMASK) + 1;
RS = RB + (RA ^ FMASK) + 1;
RK=1;
} else {
temp2 = RB + RA;
RS = RB + RA;
RK=0;
}
if (((temp2 ^ RA) & B0) != 0)
if (((RS ^ RA) & B0) != 0)
BCarry = 1;
BCarry = RK != BCarry;
RP <<= 1;
if (((temp2 ^ RA) & B0) == 0) {
if (((RS ^ RA) & B0) == 0) {
RP |= 1;
}
RB = temp2 << 1;
RB = RS << 1;
if (RP & BM1)
RB |= 1;
RB &= FMASK;
@ -813,16 +814,16 @@ obey:
/* Main divide loop */ /* V13 */
for (RK = 22; RK != 0; RK--) {
if (((temp2 ^ RA) & B0) == 0) {
temp2 = RB + (RA ^ FMASK) + 1;
if (((RS ^ RA) & B0) == 0) {
RS = RB + (RA ^ FMASK) + 1;
} else {
temp2 = RB + RA;
RS = RB + RA;
}
RP <<= 1;
if (((temp2 ^ RA) & B0) == 0) {
if (((RS ^ RA) & B0) == 0) {
RP |= 1;
}
RB = temp2 << 1;
RB = RS << 1;
if (RP & BM1)
RB |= 1;
RB &= FMASK;
@ -831,13 +832,13 @@ obey:
}
/* Final product */
if (((temp2 ^ RA) & B0) == 0) { /* V14 */
temp2 = RB + (RA ^ FMASK) + 1;
if (((RS ^ RA) & B0) == 0) { /* V14 */
RS = RB + (RA ^ FMASK) + 1;
} else {
temp2 = RB + RA;
RS = RB + RA;
}
RP <<= 1;
if (((temp2 ^ RA) & B0) == 0) {
if (((RS ^ RA) & B0) == 0) {
RP |= 1;
}
RP &= FMASK;
@ -856,9 +857,9 @@ obey:
//fprintf(stderr, "DVD5: %08o %08o %08o \n\r", RA, RP, RB);
/* Form final partial product */
if (RA & B0) {
temp2 = (RB + (RA ^ FMASK) + 1) & FMASK;
RS = (RB + (RA ^ FMASK) + 1) & FMASK;
//fprintf(stderr, "DVD5: %08o %08o %08o %08o\n\r", RA, RP, RB, RT);
if (temp2 == 0) {
if (RS == 0) {
RB = 0;
goto dvd1;
}
@ -883,7 +884,7 @@ dvd1:
BCarry = 1;
dvd2:
//fprintf(stderr, "DVD7: %08o %08o %08o \n\r", RA, RP, RB);
if (temp)
if (n)
BCarry = 0;
if (BCarry)
BV = 1;
@ -1130,15 +1131,15 @@ branch:
RK = RB & 01777;
BCarry = 0;
while (RK != 0) {
temp2 = 0;
n = 0;
switch (m) {
case 0: temp2 = (RA & B0) != 0; break;
case 0: n = (RA & B0) != 0; break;
case 1: break;
case 2:
case 3: temp = RA & B0;
}
RA <<= 1;
RA |= temp2;
RA |= n;
if ((m & 2) && temp != (RA & B0))
BV = 1;
RA &= FMASK;
@ -1175,9 +1176,9 @@ branch:
if (RB & B0)
RA |= 1;
RB &= M23;
temp2 = (RA & B0) != 0;
n = (RA & B0) != 0;
temp = (RA & BM1) != 0;
if (temp2 != temp)
if (n != temp)
BV = 1;
}
RA &= FMASK;
@ -1191,23 +1192,23 @@ branch:
case OP_SRL: /* Shift Right */
m = (RB >> 10) & 03;
RK = RB & 01777;
temp2 = RA & B0;
RT = RA & B0;
BCarry = 0;
switch(m) {
case 0: break;
case 1: temp2 = 0; break;
case 1: RT = 0; break;
case 2: break;
case 3: if (BV) {
temp2 = B0 ^ temp2;
RT = B0 ^ RT;
BV = 0;
}
}
while (RK != 0) {
if (m == 0)
temp2 = (RA & 1) ? B0 : 0;
RT = (RA & 1) ? B0 : 0;
temp = RA & 1;
RA >>= 1;
RA |= temp2;
RA |= RT;
RK--;
}
if (m > 1 && temp == 1)
@ -1220,9 +1221,9 @@ branch:
RK = RB & 01777;
RB = XR[(RX+1) & 07];
BCarry = 0;
temp2 = RA & B0;
RT = RA & B0;
if (m == 3 && RK != 0 && BV) {
temp2 = B0^temp2;
RT = B0^RT;
BV = 0;
}
while (RK != 0) {
@ -1247,7 +1248,7 @@ branch:
if (RA & 1)
RB |= B1;
RA >>= 1;
RA |= temp2;
RA |= RT;
}
RK--;
}
@ -1268,12 +1269,12 @@ branch:
RA = RB = 0;
} else if (BV) {
RT++;
temp2 = (RA & B0) ^ B0;
RP = (RA & B0) ^ B0;
if (RA & 1 && RF & 1)
RB |= B0;
RB >>= 1;
RA >>= 1;
RA |= temp2;
RA |= RP;
} else if (RA != 0 || RB != 0) {
/* Shift left until sign and B1 not same */
while ((((RA >> 1) ^ RA) & B1) == 0) {
@ -1297,8 +1298,7 @@ branch:
RB += 0400;
if (RB & B0) {
RB = RP;
temp2 = (RA & M23) +1;
if (temp2 & B0)
if (((RA & M23) + 1) & B0)
RA = RB = 0;
}
RB = (RB & MMASK) | (RT & M9);
@ -1363,6 +1363,17 @@ branch:
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 & 077;
else
@ -1530,24 +1541,27 @@ branch:
}
//fprintf(stderr, "FAD5: %08o %08o %08o %08o %08o\n\r", RA, RB, RC, faccl, facch);
/* Add the numbers */
temp2 = (faccl & B0) != 0; /* Save signs */
n = (faccl & B0) != 0; /* Save signs */
if (RA & B0)
temp2 |= 2;
n |= 2;
faccl += RA;
facch += RB;
if (facch & B0) {
facch &= M23;
faccl ++;
}
temp = (faccl & B0) != 0;
/* Sign of result */
if ((faccl & B0) != 0)
n |= 4;
//fprintf(stderr, "FAD6: %08o %08o %08o %d %d\n\r", faccl, facch, RC, temp, temp2);
if ((temp2 == 3 && temp == 0) || (temp2 == 0 && temp != 0)) {
/* Result sign not equal same sign as addens */
if (n == 3 || n == 4) {
if (faccl & 1)
facch |= B0;
faccl >>= 1;
facch >>= 1;
facch &= MMASK;
if (!temp)
if ((n & 4) == 0)
faccl |= B0; /* Set sign */
e1++;
//fprintf(stderr, "FAD6a: %08o %08o %08o %d %d\n\r", faccl, facch, RC, temp, temp2);
@ -1579,7 +1593,7 @@ fn:
faccl ++;
facch &= M23;
faccl &= FMASK;
temp2 = (faccl & B0) != 0;
// temp2 = (faccl & B0) != 0;
/* renormalize if things changed */
if ((RX & 2) == 0 && (((faccl >> 1) ^ faccl) & B1) == 0) {
e1--;
@ -1665,35 +1679,35 @@ fexp:
}
}
//fprintf(stderr, "FMP2: %08o %08o %08o %08o %08o %03o %d %o\n\r", RA, RB, RC, faccl, facch, e1, e1, f);
temp = faccl;
temp2 = facch;
RT = faccl;
RP = facch;
faccl = facch = 0; /* Clear product */
/* Do actual multiply */
for(RK = 37; RK != 0; RK--) {
/* If High order bit one, add in RB,RA */
if (temp2 & B15) {
if (RP & B15) {
facch += RB;
faccl += RA;
if (facch & B0)
faccl++;
facch &= M23;
}
/* Shift faccl,fach,temp,t right one */
if (temp & 1)
temp2 |= B0;
/* Shift faccl,fach,RT,t right one */
if (RT & 1)
RP |= B0;
if (facch & 1)
temp |= B0;
RT |= B0;
if (faccl & 1)
facch |= B0;
temp2 >>= 1;
temp >>= 1;
RP >>= 1;
RT >>= 1;
facch >>= 1;
faccl >>= 1;
//fprintf(stderr, "FMP3: %08o %08o %08o %08o %08o %08o %08o %02o\n\r", RA, RB, RC, faccl, facch, temp, temp2, RK);
//fprintf(stderr, "FMP3: %08o %08o %08o %08o %08o %08o %08o %02o\n\r", RA, RB, RC, faccl, facch, RT, RP, RK);
}
/* Check if still negative multiplican */
if (temp2 & B15) {
if (RP & B15) {
facch += RB;
faccl += RA;
if (facch & B0)
@ -1705,20 +1719,20 @@ fexp:
if ((RX & 2) == 0 && faccl == 0 && facch != 0) {
while ((faccl & B1) == 0) {
e1--;
temp2 <<= 1;
temp <<= 1;
RP <<= 1;
RT <<= 1;
facch <<= 1;
faccl <<= 1;
if (temp2 & B0)
temp |= 1;
if (temp & B0)
if (RP & B0)
RT |= 1;
if (RT & B0)
facch |= 1;
if (facch & B0)
faccl |= 1;
faccl &= FMASK;
facch &= M23;
temp &= M23;
temp2 &= M23;
RT &= M23;
RP &= M23;
}
}
/* Fix up if over flow */
@ -1806,36 +1820,36 @@ fexp:
}
RA ^= M23; /* precompliment */
RB ^= M23;
temp2 = faccl; /* Set dividend into upper half */
temp = facch;
RP = faccl; /* Set dividend into upper half */
RT = facch;
faccl = 0;
facch = 0;
n = 0;
/* DO actual divide */
for (RK=46; RK != 0; RK--) {
uint32 t0, t1;
t0 = temp + RB + 1;
t1 = temp2 + RA;
t0 = RT + RB + 1;
t1 = RP + RA;
if (t0 & B0)
t1++;
if (n || (t1 & B0)) {
temp = t0;
temp2 = t1;
RT = t0;
RP = t1;
facch |= 1;
}
facch <<= 1;
faccl <<= 1;
temp <<= 1;
temp2 <<= 1;
RT <<= 1;
RP <<= 1;
if (facch & B0)
faccl |= 1;
if (temp & B0)
temp2 |= 1;
n = (temp2 & B0) != 0;
temp &= M23;
temp2 &= M23;
if (RT & B0)
RP |= 1;
n = (RP & B0) != 0;
RT &= M23;
RP &= M23;
facch &= M23;
//fprintf(stderr, "FDV3: %08o %08o %08o %08o %08o %08o %08o %02o %08o %08o %o\n\r", RA, RB, RC, faccl, facch, temp2, temp, RK,t1, t0, n);
//fprintf(stderr, "FDV3: %08o %08o %08o %08o %08o %08o %08o %02o %08o %08o %o\n\r", RA, RB, RC, faccl, facch, RP, RT, RK,t1, t0, n);
}
/* If rounding and positive and negative result, adjust */
if (((RX & 2) == 0 || f == 0) && faccl & B0) {
@ -1908,6 +1922,12 @@ fexp:
case 0150:
case 0151:
case 0160: /* Stevenage machines */ /* Load accumulators */
case 0161: /* Stevenage machines */ /* Store accumulators */
case 0162: /* Stevenage machines */
case 0163: /* Stevenage machines */ /* Stope and Display */
case 0164: /* Stevenage machines */ /* Search List N for Word X */
case 0165: /* Stevenage machines */ /* Parity Search */
if (exe_mode) {
break;
}
@ -1916,19 +1936,26 @@ fexp:
RA = 0;
switch(RB) {
case 1: RA = SR1; break;
case 2: RA = SR2; break;
case 3: RA = SR3; break;
case 64: RA = SR64; SR64 = 0; break;
case 65: RA = SR65; SR65 = 0; 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;
}
XR[RX] = RA;
fprintf(stderr, "RD SR %o %08o\n\r", RB, 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);
//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;
break;
}
/* Fall through */
@ -1950,7 +1977,7 @@ fprintf(stderr, "WR SR %o %08o\n\r", RB, RA);
Mode &= ~(EJM|AM22|EXTRC);
Mode |= (EJM|AM22|EXTRC) & RA;
adrmask = (Mode & AM22) ? M22 : M15;
//fprintf(stderr, "Load limit: %08o D:=%08o %02o\n\r", RL, RD, Mode);
fprintf(stderr, "Load limit: %08o D:=%08o %02o\n\r", RL, RD, Mode);
#endif
if (RF & 1) /* Check if 172 or 173 order code */
break;
@ -1962,7 +1989,7 @@ fprintf(stderr, "WR SR %o %08o\n\r", RB, RA);
if ((Mode & AM22) && (RA & B3))
Mode |= 1;
Mem_read(RD+8, &RC, 0); /* Restore C register */
//fprintf(stderr, "Load PC: %08o D:=%08o z=%08o\n\r", RC, RD, RA);
fprintf(stderr, "Load PC: %08o D:=%08o z=%08o\n\r", RC, RD, RA);
if ((Mode & AM22) == 0 && (RA & B3))
Mode |= 1;
BV = (RC & B0) != 0;
@ -1976,6 +2003,15 @@ fprintf(stderr, "WR SR %o %08o\n\r", RB, RA);
/* Fall through */
case 0174: /* Send control character to peripheral */
if (exe_mode) {
RT = RB;
chan_send_cmd(RB, RA & 077, &RB);
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;
RA &= ~(077 << m);
RA |= RB;
XR[RX] = RA;
break;
}
/* Fall through */
@ -1987,7 +2023,7 @@ fprintf(stderr, "WR SR %o %08o\n\r", RB, RA);
/* Fall through */
case 0177: /* Test Datum and Limit */
if (exe_mode) {
if (RA < RG || RA > RL)
if (RA < RD || RA >= RL)
BCarry = 1;
break;
}

347
ICL1900/icl1900_cty.c Normal file
View File

@ -0,0 +1,347 @@
/* 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";
}

View File

@ -57,6 +57,8 @@ extern uint32 M[]; /* Main Memory */
extern DEBTAB dev_debug[];
extern uint32 SR64;
extern uint32 SR65;
/* Returns from device commands */
#define SCPE_BUSY (1) /* Device is active */
@ -174,6 +176,8 @@ t_opcode;
#define B1 020000000
#define B2 010000000
#define B3 004000000
#define B4 002000000
#define B5 001000000
#define B8 000100000
#define B15 000001000
#define B16 000000400
@ -190,6 +194,8 @@ t_opcode;
#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 */
struct icl_dib {
uint8 channel; /* Channel number */
@ -200,11 +206,13 @@ struct icl_dib {
typedef struct icl_dib DIB;
/* Hessitation operations */
int chan_write_char(uint8 channel, uint8 data);
int chan_read_char(uint8 channel, uint8 *data);
int chan_write_word(uint8 channel, uint32 data);
int chan_read_word(uint8 channel, uint32 *data);
int chan_end(uint8 channel);
extern void chan_send_cmd(int dev, uint32 cmd, 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);
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);

365
ICL1900/icl1900_stdio.c Normal file
View File

@ -0,0 +1,365 @@
/* 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));
}

View File

@ -46,7 +46,7 @@ int32 sim_emax = 1;
DEVICE *sim_devices[] = {
&cpu_dev,
// &cty_dev,
&cty_dev,
#if NUM_DEVS_CDR > 0
&cdr_dev,
#endif