mirror of
https://github.com/rcornwell/sims.git
synced 2026-02-27 00:59:57 +00:00
ICL1900: Fixed Divide, added LP and MT device drivers.
This commit is contained in:
@@ -34,14 +34,11 @@
|
||||
#include "sim_timer.h"
|
||||
|
||||
#define UNIT_V_MSIZE (UNIT_V_UF + 0)
|
||||
#define UNIT_MSIZE (7 << UNIT_V_MSIZE)
|
||||
#define UNIT_MSIZE (0x1ff << UNIT_V_MSIZE)
|
||||
#define MEMAMOUNT(x) (x << UNIT_V_MSIZE)
|
||||
#define UNIT_V_MODEL (UNIT_V_MSIZE + 4)
|
||||
#define UNIT_V_MODEL (UNIT_V_MSIZE + 9)
|
||||
#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
|
||||
@@ -72,28 +69,28 @@
|
||||
#define MOD4 12 /* A2 OPT */
|
||||
#define MOD4A 13 /* C2 OPT */
|
||||
#define MOD4E 14 /* C2 OPT */
|
||||
#define MOD4F 12+32
|
||||
#define MOD4S 15 /* Ax OPT */
|
||||
#define MOD5 16 /* A2 FP */
|
||||
#define MOD5A 17 /* Ax FP */
|
||||
#define MOD5E 18 /* C2 FP */
|
||||
#define MOD5F 16+32
|
||||
#define MOD5S 19 /* Ax FP */
|
||||
#define MOD6 20 /* C2 OPT */
|
||||
#define MOD6A 21 /* Ax OPT 076 131 */
|
||||
#define MOD6E 22 /* Ax OPT 076 */
|
||||
#define MOD6F 20+32
|
||||
#define MOD6S 23 /* Ax OPT */
|
||||
#define MOD7 24 /* C2 FP */
|
||||
#define MOD7A 25 /* Ax FP */
|
||||
#define MOD7E 26 /* Ax FP */
|
||||
#define MOD7F 24+32
|
||||
#define MOD7S 27 /* Ax FP */
|
||||
#define MOD8 28 /* Ax FP */
|
||||
#define MOD8A 29 /* Ax FP */
|
||||
#define MOD8S 30 /* Ax FP */
|
||||
#define MOD9 31 /* A2 FP */
|
||||
#define MODXF 32 /* C2 FP */
|
||||
#define MOD4F 15
|
||||
#define MOD4S 16 /* Ax OPT */
|
||||
#define MOD5 17 /* A2 FP */
|
||||
#define MOD5A 18 /* Ax FP */
|
||||
#define MOD5E 19 /* C2 FP */
|
||||
#define MOD5F 20
|
||||
#define MOD5S 21 /* Ax FP */
|
||||
#define MOD6 22 /* C2 OPT */
|
||||
#define MOD6A 23 /* Ax OPT 076 131 */
|
||||
#define MOD6E 24 /* Ax OPT 076 */
|
||||
#define MOD6F 25
|
||||
#define MOD6S 26 /* Ax OPT */
|
||||
#define MOD7 27 /* C2 FP */
|
||||
#define MOD7A 28 /* Ax FP */
|
||||
#define MOD7E 29 /* Ax FP */
|
||||
#define MOD7F 30
|
||||
#define MOD7S 31 /* Ax FP */
|
||||
#define MOD8 32 /* Ax FP */
|
||||
#define MOD8A 33 /* Ax FP */
|
||||
#define MOD8S 34 /* Ax FP */
|
||||
#define MOD9 35 /* A2 FP */
|
||||
#define MODXF 36 /* C2 FP */
|
||||
|
||||
|
||||
|
||||
@@ -172,8 +169,12 @@ 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_show_float(FILE * st, UNIT * uptr, int32 val,
|
||||
CONST void *desc);
|
||||
t_stat cpu_set_mult(UNIT * uptr, int32 val, CONST char *cptr,
|
||||
void *desc);
|
||||
t_stat cpu_show_mult(FILE * st, UNIT * uptr, int32 val,
|
||||
CONST 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,
|
||||
@@ -239,7 +240,7 @@ uint8 io_flags = EXT_IO;
|
||||
*/
|
||||
|
||||
UNIT cpu_unit[] =
|
||||
{{ UDATA(rtc_srv, MODEL(MOD4A)|UNIT_MULT|MEMAMOUNT(7)|UNIT_IDLE, MAXMEMSIZE ), 16667 }};
|
||||
{{ UDATA(rtc_srv, MODEL(MOD4A)|MEMAMOUNT(7)|UNIT_IDLE, MAXMEMSIZE ), 16667 }};
|
||||
|
||||
REG cpu_reg[] = {
|
||||
{ORDATAD(C, RC, 22, "Instruction code"), REG_FIT},
|
||||
@@ -253,17 +254,6 @@ REG cpu_reg[] = {
|
||||
};
|
||||
|
||||
MTAB cpu_mod[] = {
|
||||
{UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(0), NULL, "4K", &cpu_set_size},
|
||||
{UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(1), NULL, "8K", &cpu_set_size},
|
||||
{UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(3), NULL, "16K", &cpu_set_size},
|
||||
{UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(7), NULL, "32K", &cpu_set_size},
|
||||
{UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(11), NULL, "48K", &cpu_set_size},
|
||||
{UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(15), NULL, "64K", &cpu_set_size},
|
||||
{UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(23), NULL, "96K", &cpu_set_size},
|
||||
{UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(31), NULL, "128K", &cpu_set_size},
|
||||
{UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(63), NULL, "256K", &cpu_set_size},
|
||||
{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", &cpu_set_model, NULL, NULL},
|
||||
{UNIT_MODEL, MODEL(MOD1A), "1901A", "1901A", &cpu_set_model, NULL, NULL},
|
||||
@@ -296,10 +286,21 @@ MTAB cpu_mod[] = {
|
||||
{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_XTD|MTAB_VDV, 0, NULL, "NOFLOAT", &cpu_set_float, NULL, NULL, "Disable floating point"},
|
||||
{MTAB_XTD|MTAB_VDV, 1, "FLOAT", "FLOAT", &cpu_set_float, &cpu_show_float, NULL, "Enable floating point"},
|
||||
{MTAB_XTD|MTAB_VDV, 0, NULL, "NOMULT", &cpu_set_mult, NULL, NULL, "Disable hardware multiply"},
|
||||
{MTAB_XTD|MTAB_VDV, 1, "MULT", "MULT", &cpu_set_mult, &cpu_show_mult, NULL, "Enable hardware multiply"},
|
||||
{UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(0), NULL, "4K", &cpu_set_size},
|
||||
{UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(1), NULL, "8K", &cpu_set_size},
|
||||
{UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(3), NULL, "16K", &cpu_set_size},
|
||||
{UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(7), NULL, "32K", &cpu_set_size},
|
||||
{UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(11), NULL, "48K", &cpu_set_size},
|
||||
{UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(15), NULL, "64K", &cpu_set_size},
|
||||
{UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(23), NULL, "96K", &cpu_set_size},
|
||||
{UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(31), NULL, "128K", &cpu_set_size},
|
||||
{UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(63), NULL, "256K", &cpu_set_size},
|
||||
{UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(127), NULL, "512K", &cpu_set_size},
|
||||
{UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(254), NULL, "1024K", &cpu_set_size},
|
||||
{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 },
|
||||
@@ -324,10 +325,10 @@ uint8 Mem_test(uint32 addr) {
|
||||
addr &= M22;
|
||||
|
||||
if (!exe_mode) {
|
||||
if (addr < 8)
|
||||
if (addr < 8)
|
||||
return 0;
|
||||
addr = addr + RD;
|
||||
} else if (addr < 8)
|
||||
} else if (addr < 8)
|
||||
return 0;
|
||||
|
||||
if (!exe_mode && RL && (addr < RD || addr >= RL)) {
|
||||
@@ -441,13 +442,15 @@ sim_instr(void)
|
||||
|
||||
intr:
|
||||
if (!exe_mode && (SR64 | SR65) != 0) {
|
||||
if (CPU_TYPE < TYPE_C1 && !exe_mode)
|
||||
if (CPU_TYPE < TYPE_C1 && !exe_mode)
|
||||
RC += RD;
|
||||
exe_mode = 1;
|
||||
loading = 0;
|
||||
/* Store registers */
|
||||
Mem_write(RD+13, &facch, 0); /* Save F.P.U. */
|
||||
Mem_write(RD+12, &faccl, 0);
|
||||
if (cpu_flags & FLOAT) {
|
||||
Mem_write(RD+13, &facch, 0); /* Save F.P.U. */
|
||||
Mem_write(RD+12, &faccl, 0);
|
||||
}
|
||||
RA = 0; /* Build ZSTAT */
|
||||
if (cpu_flags & SV) {
|
||||
Mem_read(RD+9, &RA, 0);
|
||||
@@ -458,12 +461,14 @@ intr:
|
||||
if (BCarry)
|
||||
RA |= B1;
|
||||
} else {
|
||||
if (Zero)
|
||||
RA |= B3;
|
||||
if (OPIP | PIP)
|
||||
RA |= B2;
|
||||
if (CPU_TYPE >= TYPE_C1) {
|
||||
if (Zero)
|
||||
RA |= B3;
|
||||
if (OPIP | PIP)
|
||||
RA |= B2;
|
||||
Mem_write(RD+9, &RA, 0);
|
||||
}
|
||||
}
|
||||
Mem_write(RD+9, &RA, 0);
|
||||
RA = RC & adrmask;
|
||||
if (BV)
|
||||
RA |= B0;
|
||||
@@ -885,10 +890,7 @@ obey:
|
||||
RP = XR[(RX+1) & 7]; /* VR */
|
||||
RA = RB; /* Divisor to RA */
|
||||
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) /* Flag special case */
|
||||
f=1;
|
||||
//fprintf(stderr, "DVD0: %08o %08o %08o - %3o C=%08o\n\r", RA, RB, RP, RF, RC);
|
||||
|
||||
if (RA == 0) { /* Exit on zero divisor */ /* VI */
|
||||
BV = 1;
|
||||
@@ -897,21 +899,41 @@ obey:
|
||||
BCarry = 0;
|
||||
break;
|
||||
}
|
||||
BCarry = (RP & B0) != 0;
|
||||
n = (RP | RB) == 0; /* Save zero dividend */
|
||||
|
||||
/* Setup for specific divide order code */ /* V11 */
|
||||
if (RF & 2) { /* DVS */
|
||||
if (BCarry) {
|
||||
if (RP & B0) { /* RC22 */ /* Sign extend RB */
|
||||
RB = FMASK;
|
||||
} else {
|
||||
RB = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// {
|
||||
// long int divsor;
|
||||
// long int dividend;
|
||||
// int sign;
|
||||
//
|
||||
// dividend = (((long int)(RB)) << 23) | (long int)(RP);
|
||||
// if (RB & B0) {
|
||||
// dividend |= 0xffff800000000000;
|
||||
// }
|
||||
// sign = 1;
|
||||
// divsor = (long int)(RA);
|
||||
// if (RA & B0) {
|
||||
// divsor |= 0xffffffffff000000;
|
||||
// sign = -1;
|
||||
// }
|
||||
//fprintf(stderr, "DVD1: %08o %08o %08o %ld (%lo) / %ld (%lo) = %ld (%lo) m %ld (%lo) %o\n\r", RA, RB, RP,
|
||||
// dividend, dividend, divsor, divsor, dividend/divsor, dividend/divsor,
|
||||
// sign* (dividend%divsor), sign *(dividend % divsor), BV);
|
||||
//}
|
||||
BCarry = 0;
|
||||
if ((RB | RP) == 0)
|
||||
goto dvd_zero;
|
||||
RP <<= 1;
|
||||
RP &= FMASK;
|
||||
BCarry = 0;
|
||||
//fprintf(stderr, "DVD1: %08o %08o %08o \n\r", RA, RP, RB);
|
||||
|
||||
/* First partial remainder */ /* V12 */
|
||||
if (((RB ^ RA) & B0) == 0) {
|
||||
@@ -921,12 +943,14 @@ obey:
|
||||
RS = RB + RA;
|
||||
RK=0;
|
||||
}
|
||||
/* Check if potiential overflow */
|
||||
if (((RS ^ RA) & B0) != 0)
|
||||
BCarry = 1;
|
||||
BCarry = RK != BCarry;
|
||||
/* Shift left quotent and remainder */
|
||||
RP <<= 1;
|
||||
if (((RS ^ RA) & B0) == 0) {
|
||||
RP |= 1;
|
||||
RP |= 1; /* First quotient digit */
|
||||
}
|
||||
RB = RS << 1;
|
||||
if (RP & BM1)
|
||||
@@ -951,7 +975,7 @@ obey:
|
||||
RB |= 1;
|
||||
RB &= FMASK;
|
||||
RP &= FMASK;
|
||||
//fprintf(stderr, "DVD3: %08o %08o %08o \n\r", RA, RP, RB);
|
||||
//fprintf(stderr, "DVD3: %08o %08o %08o %08o \n\r", RA, RP, RB, RS);
|
||||
}
|
||||
|
||||
/* Final product */
|
||||
@@ -965,61 +989,58 @@ obey:
|
||||
RP |= 1;
|
||||
}
|
||||
RP &= FMASK;
|
||||
//fprintf(stderr, "DVD4: %08o %08o %08o \n\r", RA, RP, RB);
|
||||
|
||||
/* Final Remainder */
|
||||
if (RP & 1) {
|
||||
RB = (RB + (RA ^ FMASK) + 1) & FMASK;
|
||||
} else {
|
||||
RB = (RB + RA) & FMASK;
|
||||
}
|
||||
RB = RS & FMASK;
|
||||
//fprintf(stderr, "DVD4: %08o %08o %08o %08o \n\r", RA, RP, RB, RS);
|
||||
/* End correction */
|
||||
if ((RP & 1) == 0) {
|
||||
RB = (RB + RA) & FMASK;
|
||||
}
|
||||
//fprintf(stderr, "DVD5: %08o %08o %08o \n\r", RA, RP, RB);
|
||||
/* Form final partial product */
|
||||
if (RA & B0) {
|
||||
RS = (RB + (RA ^ FMASK) + 1) & FMASK;
|
||||
//fprintf(stderr, "DVD5: %08o %08o %08o %08o\n\r", RA, RP, RB, RT);
|
||||
if (RS == 0) {
|
||||
RB = 0;
|
||||
goto dvd1;
|
||||
}
|
||||
}
|
||||
if ((RF & 1) == 0) /* DVR */
|
||||
goto dvd2;
|
||||
if (RB == 0)
|
||||
goto dvd2;
|
||||
RT = RB + (RA ^ FMASK) + 1;
|
||||
//fprintf(stderr, "DVDA: %08o %08o %08o %08o \n\r", RA, RP, RB, RT);
|
||||
RA = RB;
|
||||
if ((((RT + RA) ^ RA) & B0) != 0)
|
||||
goto dvd2;
|
||||
RB = RT & FMASK;
|
||||
dvd1:
|
||||
//fprintf(stderr, "DVD6: %08o %08o %08o \n\r", RA, RP, RB);
|
||||
RT = RP;
|
||||
RP++;
|
||||
if ((RT ^ RP) & B0)
|
||||
BCarry = !BCarry;
|
||||
if (RP & BM1)
|
||||
BCarry = 1;
|
||||
dvd2:
|
||||
if ((RF & 1) == 0 || RB == 0) {
|
||||
//fprintf(stderr, "DVD7: %08o %08o %08o \n\r", RA, RP, RB);
|
||||
if (n)
|
||||
BCarry = 0;
|
||||
/* If remainder same as divisor, bump quotent zero remainder */
|
||||
if (RB == RA) {
|
||||
RT = RP;
|
||||
RP++;
|
||||
if ((RT & B0) != (RP & B0))
|
||||
BCarry = !BCarry;
|
||||
RB = 0;
|
||||
}
|
||||
} else { /* DVR */
|
||||
RT = RB + (RA ^ FMASK) + 1;
|
||||
//fprintf(stderr, "DVDA: %08o %08o %08o %08o \n\r", RA, RP, RB, RT);
|
||||
RA = RB;
|
||||
if ((((RT + RA) ^ RA) & B0) == 0) {
|
||||
RB = RT & FMASK;
|
||||
//fprintf(stderr, "DVD6: %08o %08o %08o \n\r", RA, RP, RB);
|
||||
RT = RP;
|
||||
RP++;
|
||||
if ((RT ^ RP) & B0)
|
||||
BCarry = !BCarry;
|
||||
if (RP & BM1)
|
||||
BCarry = 1;
|
||||
}
|
||||
}
|
||||
dvd_zero:
|
||||
/* Set overflow if BCarry still set */
|
||||
if (BCarry) {
|
||||
BV = 1;
|
||||
if (!exe_mode && (Mode & 7) == 4)
|
||||
SR64 |= B2;
|
||||
}
|
||||
BCarry = 0;
|
||||
if (f) {
|
||||
RB = 0;
|
||||
RP = FMASK;
|
||||
//fprintf(stderr, "DVD8: %08o %08o %08o \n\r", RA, RP, RB);
|
||||
}
|
||||
// {
|
||||
// int32 a;
|
||||
// int32 b;
|
||||
//
|
||||
// a = RB;
|
||||
// if (RB & B0)
|
||||
// a |= 0xff000000;
|
||||
// b = RP;
|
||||
// if (RP & B0)
|
||||
// b |= 0xff000000;
|
||||
//fprintf(stderr, "DVD8: q=%08o(%d) r=%08o(%d) %d %d %d\n\r", RP, b, RB, a, BV);
|
||||
//}
|
||||
XR[RX] = RB & FMASK;
|
||||
XR[(RX+1) & 7] = RP & FMASK;
|
||||
break;
|
||||
@@ -1518,7 +1539,7 @@ norm1:
|
||||
|
||||
/* Not on A*/
|
||||
case OP_SMO: /* Supplementary Modifier - BC */
|
||||
if (CPU_TYPE < TYPE_B1)
|
||||
if (CPU_TYPE < TYPE_C1)
|
||||
goto voluntary;
|
||||
if (OPIP) { /* Error */
|
||||
SR64 |= B1;
|
||||
@@ -1528,7 +1549,7 @@ norm1:
|
||||
goto intr;
|
||||
}
|
||||
PIP = 1;
|
||||
break;
|
||||
goto fetch;
|
||||
|
||||
case OP_NULL: /* No Operation */
|
||||
if (!exe_mode && RX == 7 && (Mode & 7) > 0 && (Mode & 7) < 5)
|
||||
@@ -2128,7 +2149,7 @@ fexp:
|
||||
case 0151:
|
||||
case 0160: /* Stevenage machines */ /* Load accumulators */
|
||||
case 0161: /* Stevenage machines */ /* Store accumulators */
|
||||
case 0162: /* Stevenage machines */
|
||||
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 */
|
||||
@@ -2143,7 +2164,7 @@ fexp:
|
||||
case 1: RA = SR1; break;
|
||||
case 64: RA = SR64; SR64 &= 003777777; break;
|
||||
case 65: RA = SR65; break;
|
||||
default: if (RB < 64)
|
||||
default: if (RB < 64)
|
||||
chan_nsi_status(RB, &RA);
|
||||
break;
|
||||
}
|
||||
@@ -2154,7 +2175,7 @@ fexp:
|
||||
case 0171: /* Write special register */
|
||||
if (exe_mode) {
|
||||
//fprintf(stderr, "WR SR %o %08o\n\r", RB, RA);
|
||||
if (RB < 64)
|
||||
if (RB < 64)
|
||||
chan_nsi_cmd(RB, RA);
|
||||
break;
|
||||
}
|
||||
@@ -2240,25 +2261,27 @@ voluntary:
|
||||
reason = SCPE_STOP;
|
||||
break;
|
||||
}
|
||||
if (CPU_TYPE < TYPE_C1 && !exe_mode)
|
||||
if (CPU_TYPE < TYPE_C1 && !exe_mode)
|
||||
RC += RD;
|
||||
exe_mode = 1;
|
||||
/* 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)
|
||||
RA |= B2;
|
||||
Mem_write(RD+9, &RA, 0);
|
||||
if (CPU_TYPE >= TYPE_C1) {
|
||||
RA = 0; /* Build ZSTAT */
|
||||
if (Zero)
|
||||
RA |= B3;
|
||||
if (OPIP)
|
||||
RA |= B2;
|
||||
Mem_write(RD+9, &RA, 0);
|
||||
}
|
||||
RA = RC;
|
||||
if (BV)
|
||||
RA |= B0;
|
||||
if (BCarry)
|
||||
RA |= B1;
|
||||
/* Type A & B */
|
||||
if (CPU_TYPE < TYPE_C1 && Zero)
|
||||
if (CPU_TYPE < TYPE_C1 && Zero)
|
||||
RA |= B8;
|
||||
Mem_write(RD+8, &RA, 0);
|
||||
for (n = 0; n < 8; n++)
|
||||
@@ -2382,12 +2405,8 @@ cpu_set_model(UNIT * uptr, int32 val, CONST char *cptr, void *desc)
|
||||
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 &= ~(UNIT_MODEL);
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -2398,10 +2417,6 @@ 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;
|
||||
cpu_flags &= ~FLOAT;
|
||||
if (val)
|
||||
cpu_flags |= FLOAT;
|
||||
@@ -2410,14 +2425,17 @@ cpu_set_float(UNIT * uptr, int32 val, CONST char *cptr, void *desc)
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat
|
||||
cpu_show_float(FILE *st, UNIT *uptr, int32 val, CONST void *desc)
|
||||
{
|
||||
fprintf(st, "%s", (cpu_flags & FLOAT) ? "FLOAT":"NOFLOAT");
|
||||
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;
|
||||
cpu_flags &= ~MULT;
|
||||
if (val)
|
||||
cpu_flags |= MULT;
|
||||
@@ -2425,6 +2443,13 @@ cpu_set_mult(UNIT * uptr, int32 val, CONST char *cptr, void *desc)
|
||||
return SCPE_ARG;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat
|
||||
cpu_show_mult(FILE *st, UNIT *uptr, int32 val, CONST void *desc)
|
||||
{
|
||||
fprintf(st, "%s", (cpu_flags & MULT) ? "MULT":"NOMULT");
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Handle execute history */
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ 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
|
||||
@@ -104,7 +104,7 @@ DEVICE cty_dev = {
|
||||
void cty_cmd(int dev, uint32 cmd) {
|
||||
int u = 0;
|
||||
|
||||
if (dev > 3)
|
||||
if (dev > 3)
|
||||
return;
|
||||
if (dev == 2)
|
||||
u++;
|
||||
@@ -113,8 +113,8 @@ void cty_cmd(int dev, uint32 cmd) {
|
||||
cty_unit[u].STATUS |= BUSY;
|
||||
if (!u)
|
||||
sim_activate(&cty_unit[u], cty_unit[u].wait);
|
||||
}
|
||||
else if (cmd & STOP) {
|
||||
}
|
||||
else if (cmd & STOP) {
|
||||
cty_unit[u].STATUS &= ~BUSY;
|
||||
}
|
||||
cty_unit[u].STATUS &= BUSY;
|
||||
@@ -124,7 +124,7 @@ void cty_cmd(int dev, uint32 cmd) {
|
||||
void cty_status(int dev, uint32 *resp) {
|
||||
int u = 0;
|
||||
|
||||
if (dev > 3)
|
||||
if (dev > 3)
|
||||
return;
|
||||
if (dev == 2)
|
||||
u++;
|
||||
@@ -142,7 +142,7 @@ t_stat ctyo_svc (UNIT *uptr)
|
||||
/* Check if we had a held characteter */
|
||||
if (uptr->HOLD != 0) {
|
||||
if ((r = sim_putchar_s (uptr->HOLD)) == SCPE_STALL) {
|
||||
r = SCPE_OK;
|
||||
r = SCPE_OK;
|
||||
} else {
|
||||
if (uptr->HOLD == '\r')
|
||||
uptr->HOLD = '\n';
|
||||
@@ -153,7 +153,7 @@ t_stat ctyo_svc (UNIT *uptr)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (uptr->STATUS & BUSY) {
|
||||
if (uptr->STATUS & BUSY) {
|
||||
eor = chan_output_char(GET_UADDR(uptr->flags), &ch, 0);
|
||||
switch (ch & 060) {
|
||||
case 000: ch = 0060 | (ch & 017); break;
|
||||
@@ -238,7 +238,7 @@ t_stat ctyi_svc (UNIT *uptr)
|
||||
|
||||
default:
|
||||
sim_debug(DEBUG_DATA, &cty_dev, ": key '%c'\n", ch);
|
||||
if (ch >= 0140)
|
||||
if (ch >= 0140)
|
||||
ch -= 040;
|
||||
if (ch >= 0100)
|
||||
ch -= 040;
|
||||
@@ -286,7 +286,7 @@ t_stat ctyi_svc (UNIT *uptr)
|
||||
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');
|
||||
|
||||
@@ -32,9 +32,9 @@
|
||||
#define NUM_DEVS_PTP 2
|
||||
#define NUM_DEVS_CDR 0
|
||||
#define NUM_DEVS_CDP 0
|
||||
#define NUM_DEVS_LPR 0
|
||||
#define NUM_DEVS_LPR 1
|
||||
#define NUM_DEVS_CON 0
|
||||
#define NUM_DEVS_MT 0 /* 1971 SI tape drives */
|
||||
#define NUM_DEVS_MT 4 /* 1971 SI tape drives */
|
||||
#define NUM_DEVS_MTA 8 /* 1974 NSI tape drives */
|
||||
#define NUM_DEVS_DSK 0
|
||||
#define NUM_DEVS_DTC 0
|
||||
|
||||
352
ICL1900/icl1900_lp.c
Normal file
352
ICL1900/icl1900_lp.c
Normal file
@@ -0,0 +1,352 @@
|
||||
/* icl1900_lp.c: ICL1900 Line Printer 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_LPR
|
||||
#define NUM_DEVS_LPR 0
|
||||
#endif
|
||||
|
||||
#define UNIT_V_TYPE (UNIT_V_UF + 1)
|
||||
#define UNIT_TYPE (0x1f << 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 LW_96(x) ((GET_TYPE(x) & 06) == 0)
|
||||
#define LW_120(x) ((GET_TYPE(x) & 06) == 2)
|
||||
#define LW_160(x) ((GET_TYPE(x) & 06) == 4)
|
||||
|
||||
#define CMD u3
|
||||
#define STATUS u4
|
||||
#define MOTION u5
|
||||
|
||||
#define AUTO 00100
|
||||
#define PRINT 00040
|
||||
#define SPACE 00010
|
||||
|
||||
#define TERMINATE 0001
|
||||
#define OPAT 0002
|
||||
#define ERROR 0004
|
||||
#define BUSY 0040
|
||||
#define DISC 0100
|
||||
|
||||
|
||||
#if (NUM_DEVS_LPR > 0)
|
||||
|
||||
#define T1930_1 0
|
||||
#define T1930_2 2
|
||||
#define T1931_1 1
|
||||
#define T1931_2 3
|
||||
#define T1932_1 1+8
|
||||
#define T1932_2 3+8
|
||||
#define T1933_1 1+12
|
||||
#define T1933_2 3+12
|
||||
#define T1933_3 5+12
|
||||
|
||||
#define UNIT_LPR(x) UNIT_ADDR(x)|SET_TYPE(T1931_2)|UNIT_ATTABLE|\
|
||||
UNIT_DISABLE|UNIT_TEXT
|
||||
|
||||
|
||||
void lpr_cmd (int dev, uint32 cmd, uint32 *resp);
|
||||
void lpr_nsi_cmd (int dev, uint32 cmd);
|
||||
void lpr_nsi_status (int dev, uint32 *resp);
|
||||
t_stat lpr_svc (UNIT *uptr);
|
||||
t_stat lpr_reset (DEVICE *dptr);
|
||||
t_stat lpr_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
|
||||
CONST char *lpr_description (DEVICE *dptr);
|
||||
|
||||
DIB lpr_dib = { CHAR_DEV, &lpr_cmd, &lpr_nsi_cmd, &lpr_nsi_status };
|
||||
|
||||
UNIT lpr_unit[] = {
|
||||
{ UDATA (&lpr_svc, UNIT_LPR(11), 0), 10000 },
|
||||
{ UDATA (&lpr_svc, UNIT_LPR(13), 0), 10000 },
|
||||
};
|
||||
|
||||
|
||||
MTAB lpr_mod[] = {
|
||||
{ UNIT_TYPE, SET_TYPE(T1930_1), "1930/1", "1930/1", NULL, NULL, "ICL 1930/1 NSI 1000LPM printer."},
|
||||
{ UNIT_TYPE, SET_TYPE(T1930_2), "1930/2", "1930/2", NULL, NULL, "ICL 1930/2 NSI 1000LPM printer."},
|
||||
{ UNIT_TYPE, SET_TYPE(T1931_1), "1931/1", "1931/1", NULL, NULL, "ICL 1931/1 SI 1000LPM printer."},
|
||||
{ UNIT_TYPE, SET_TYPE(T1931_2), "1931/2", "1931/2", NULL, NULL, "ICL 1931/2 SI 1000LPM printer."},
|
||||
{ UNIT_TYPE, SET_TYPE(T1932_1), "1932/1", "1932/1", NULL, NULL, "ICL 1932/1 SI 1000LPM printer."},
|
||||
{ UNIT_TYPE, SET_TYPE(T1932_2), "1932/2", "1932/2", NULL, NULL, "ICL 1932/2 SI 1000LPM printer."},
|
||||
{ UNIT_TYPE, SET_TYPE(T1933_1), "1933/1", "1933/1", NULL, NULL, "ICL 1933/1 SI 1000LPM printer."},
|
||||
{ UNIT_TYPE, SET_TYPE(T1933_2), "1933/2", "1933/2", NULL, NULL, "ICL 1933/2 SI 1000LPM printer."},
|
||||
{ UNIT_TYPE, SET_TYPE(T1933_3), "1933/3", "1933/3", NULL, NULL, "ICL 1933/3 SI 1000LPM printer."},
|
||||
{MTAB_XTD | MTAB_VUN | MTAB_VALR, 0, "DEV", "DEV", &set_chan, &get_chan, NULL, "Device Number"},
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
DEVICE lpr_dev = {
|
||||
"LP", lpr_unit, NULL, lpr_mod,
|
||||
NUM_DEVS_PTP, 8, 22, 1, 8, 22,
|
||||
NULL, NULL, &lpr_reset, NULL, &attach_unit, &detach_unit,
|
||||
&lpr_dib, DEV_DISABLE | DEV_DEBUG, 0, dev_debug,
|
||||
NULL, NULL, &lpr_help, NULL, NULL, &lpr_description
|
||||
};
|
||||
|
||||
/*
|
||||
* Command codes
|
||||
*
|
||||
* 011010 Write
|
||||
* 000010 AutoWrite
|
||||
* 010000 Send Q.
|
||||
* 010100 Send P.
|
||||
* 011110 Disconnect.
|
||||
*/
|
||||
|
||||
|
||||
void lpr_cmd(int dev, uint32 cmd, uint32 *resp) {
|
||||
int i;
|
||||
UNIT *uptr = NULL;
|
||||
|
||||
*resp = 0;
|
||||
/* Find the unit from dev */
|
||||
for (i = 0; i < lpr_dev.numunits; i++) {
|
||||
if (GET_UADDR(lpr_unit[i].flags) == dev) {
|
||||
uptr = &lpr_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;
|
||||
|
||||
if (cmd == 032 || cmd == 02) { /* Command */
|
||||
if (uptr->STATUS & BUSY) {
|
||||
*resp = 3;
|
||||
return;
|
||||
}
|
||||
uptr->CMD = (cmd == 02) ? AUTO: 0;
|
||||
uptr->STATUS = BUSY;
|
||||
sim_activate(uptr, uptr->wait);
|
||||
chan_clr_done(GET_UADDR(uptr->flags));
|
||||
*resp = 5;
|
||||
} else if (cmd == SEND_Q) {
|
||||
if ((uptr->flags & UNIT_ATT) == 0)
|
||||
*resp = 040;
|
||||
if (uptr->STATUS & 06)
|
||||
*resp = 040;
|
||||
*resp |= uptr->STATUS & TERMINATE;
|
||||
} else if (cmd == SEND_P) { /* Send P */
|
||||
if ((uptr->flags & UNIT_ATT) != 0)
|
||||
*resp = (uptr->STATUS & ERROR) | 1;
|
||||
uptr->STATUS = 0;
|
||||
chan_clr_done(GET_UADDR(uptr->flags));
|
||||
} else if (cmd == DISCO) { /* Disconnect */
|
||||
uptr->STATUS |= DISC;
|
||||
*resp = 5;
|
||||
}
|
||||
sim_debug(DEBUG_CMD, &lpr_dev, "CMD: %03o %03o %03o\n", cmd, uptr->CMD, uptr->STATUS);
|
||||
}
|
||||
|
||||
/*
|
||||
* Command codes
|
||||
*
|
||||
* xxxx01 Start print.
|
||||
* xxxx10 Stop print.
|
||||
*/
|
||||
void lpr_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(lpr_unit[i].flags) == dev) {
|
||||
uptr = &lpr_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->STATUS & BUSY)
|
||||
uptr->STATUS |= 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;
|
||||
}
|
||||
uptr->CMD |= 0;
|
||||
uptr->STATUS = BUSY;
|
||||
sim_activate(uptr, uptr->wait);
|
||||
chan_clr_done(GET_UADDR(uptr->flags));
|
||||
sim_debug(DEBUG_CMD, &lpr_dev, "CMD: %03o %03o %03o\n", cmd, uptr->CMD, uptr->STATUS);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* NSI Status bits.
|
||||
*
|
||||
* 001 End.
|
||||
* 002 Opat.
|
||||
* 004 ERROR
|
||||
* 020 ACCEPT
|
||||
* 040 BUSY
|
||||
*/
|
||||
void lpr_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(lpr_unit[i].flags) == dev) {
|
||||
uptr = &lpr_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 & 077;
|
||||
uptr->STATUS &= BUSY|DISCO ;
|
||||
chan_clr_done(GET_UADDR(uptr->flags));
|
||||
sim_debug(DEBUG_CMD, &lpr_dev, "ST: %08o %03o %03o\n", *resp, uptr->CMD, uptr->STATUS);
|
||||
}
|
||||
|
||||
|
||||
|
||||
t_stat lpr_svc (UNIT *uptr)
|
||||
{
|
||||
t_stat r;
|
||||
uint8 ch;
|
||||
int data;
|
||||
char buffer[200];
|
||||
int i;
|
||||
int len;
|
||||
int eor;
|
||||
|
||||
/* Handle a disconnect request */
|
||||
if (uptr->STATUS & DISC) {
|
||||
uptr->STATUS &= ~(BUSY|DISC);
|
||||
uptr->STATUS |= TERMINATE;
|
||||
chan_set_done(GET_UADDR(uptr->flags));
|
||||
return SCPE_OK;
|
||||
}
|
||||
/* If not busy, false schedule, just exit */
|
||||
if ((uptr->STATUS & BUSY) == 0)
|
||||
return SCPE_OK;
|
||||
|
||||
/* Check if attached */
|
||||
if ((uptr->flags & UNIT_ATT) == 0) {
|
||||
uptr->STATUS = ERROR|TERMINATE;
|
||||
chan_set_done(GET_UADDR(uptr->flags));
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
len = 96;
|
||||
if (LW_120(uptr->flags))
|
||||
len = 120;
|
||||
else if (LW_160(uptr->flags))
|
||||
len = 160;
|
||||
for (i = 0; i < len && eor == 0; i++) {
|
||||
eor = chan_output_char(GET_UADDR(uptr->flags), &ch, 0);
|
||||
sim_debug(DEBUG_DATA, &lpr_dev, "DATA: %03o\n", ch);
|
||||
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;
|
||||
}
|
||||
buffer[i] = ch;
|
||||
}
|
||||
buffer[i++] = '\r';
|
||||
buffer[i++] = '\n';
|
||||
buffer[i++] = '\0';
|
||||
|
||||
sim_fwrite(&buffer, 1, i, uptr->fileref);
|
||||
/* Check if Done */
|
||||
if (eor) {
|
||||
uptr->STATUS |= TERMINATE;
|
||||
uptr->STATUS &= ~(BUSY|DISC);
|
||||
chan_set_done(GET_UADDR(uptr->flags));
|
||||
return SCPE_OK;
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
|
||||
/* Reset */
|
||||
|
||||
t_stat lpr_reset (DEVICE *dptr)
|
||||
{
|
||||
UNIT *uptr = dptr->units;
|
||||
int unit;
|
||||
|
||||
for (unit = 0; unit < NUM_DEVS_PTP; unit++, uptr++) {
|
||||
uptr->STATUS = 0;
|
||||
chan_clr_done(GET_UADDR(uptr->flags));
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
|
||||
t_stat lpr_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 *lpr_description (DEVICE *dptr)
|
||||
{
|
||||
return "PTP";
|
||||
|
||||
}
|
||||
#endif
|
||||
584
ICL1900/icl1900_mt.c
Normal file
584
ICL1900/icl1900_mt.c
Normal file
@@ -0,0 +1,584 @@
|
||||
/* icl1900_mt.c: ICL1900 2504 mag tape drive 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
|
||||
|
||||
Magnetic tapes are represented as a series of variable records
|
||||
of the form:
|
||||
|
||||
32b byte count
|
||||
byte 0
|
||||
byte 1
|
||||
:
|
||||
byte n-2
|
||||
byte n-1
|
||||
32b byte count
|
||||
|
||||
If the byte count is odd, the record is padded with an extra byte
|
||||
of junk. File marks are represented by a byte count of 0.
|
||||
|
||||
*/
|
||||
|
||||
#include "icl1900_defs.h"
|
||||
#include "sim_tape.h"
|
||||
|
||||
#if (NUM_DEVS_MT > 0)
|
||||
#define BUFFSIZE (64 * 1024)
|
||||
#define UNIT_MT UNIT_ATTABLE | UNIT_DISABLE | UNIT_ROABLE
|
||||
|
||||
#define CMD u3 /* Command */
|
||||
#define STATUS u4
|
||||
#define POS u6 /* Position within buffer */
|
||||
|
||||
|
||||
/* Command is packed follows:
|
||||
*
|
||||
* Lower 3 bits is command.
|
||||
* Next bit is binary/BCD.
|
||||
* Next bit is disconnect flag.
|
||||
* Top 16 bits are count.
|
||||
*/
|
||||
|
||||
#define MT_CMD 077
|
||||
|
||||
#define BUF_EMPTY(u) (u->hwmark == 0xFFFFFFFF)
|
||||
#define CLR_BUF(u) u->hwmark = 0xFFFFFFFF
|
||||
|
||||
#define MT_NOP 000
|
||||
#define MT_FSF 001 /* No Qualifier */
|
||||
#define MT_BSR 002 /* Qualifier */
|
||||
#define MT_BSF 003 /* Qualifier */
|
||||
#define MT_REV_READ 011 /* Qualifier */
|
||||
#define MT_WRITEERG 012 /* Qualifier */
|
||||
#define MT_WTM 013 /* Qualifier */
|
||||
#define MT_TEST 014 /* Qualifier */
|
||||
#define MT_REW 016 /* No Qualifier */
|
||||
#define MT_READ 031 /* Qualifier */
|
||||
#define MT_WRITE 032 /* Qualifier */
|
||||
#define MT_RUN 036 /* No Qualifier */
|
||||
#define MT_BOOT 037 /* No Qualifier */
|
||||
|
||||
#define MT_QUAL 0100 /* Qualifier expected */
|
||||
#define MT_BUSY 0200 /* Device running command */
|
||||
|
||||
#define ST1_OK 00100 /* Unit OK */
|
||||
#define ST1_WARN 00200 /* Warning, EOT, BOT, TM */
|
||||
#define ST1_ERR 00400 /* Parity error, blank, no unit */
|
||||
#define ST1_CORERR 01000 /* Corrected error */
|
||||
#define ST1_LONG 02000 /* Long Block */
|
||||
#define ST1_P2 040 /* P2 Status */
|
||||
|
||||
#define ST2_ROWS 0030000 /* Number of rows read */
|
||||
#define ST2_BLNK 0040000 /* Blank Tape */
|
||||
|
||||
#define STQ_TERM 001 /* Operation terminated */
|
||||
#define STQ_WRP 002 /* Write ring present */
|
||||
#define STQ_ACCP 004 /* Handler accepted order */
|
||||
#define STQ_S1 010 /* Controller ready to accept */
|
||||
#define STQ_S2 020 /* Controller ready to accept */
|
||||
#define STQ_P1 040 /* P1 Status on */
|
||||
|
||||
|
||||
int mt_busy; /* Indicates that controller is talking to a drive */
|
||||
int mt_drive; /* Indicates last selected drive */
|
||||
uint8 mt_buffer[BUFFSIZE];
|
||||
void mt_cmd (int dev, uint32 cmd, uint32 *resp);
|
||||
t_stat mt_svc (UNIT *uptr);
|
||||
t_stat mt_reset (DEVICE *dptr);
|
||||
t_stat mt_boot (int32 unit_num, DEVICE * dptr);
|
||||
t_stat mt_attach(UNIT *, CONST char *);
|
||||
t_stat mt_detach(UNIT *);
|
||||
t_stat mt_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
|
||||
CONST char *mt_description (DEVICE *dptr);
|
||||
|
||||
DIB mt_dib = { WORD_DEV|MULT_DEV, &mt_cmd, NULL, NULL };
|
||||
|
||||
|
||||
MTAB mt_mod[] = {
|
||||
{MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL},
|
||||
{MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL},
|
||||
{MTAB_XTD | MTAB_VUN, 0, "FORMAT", "FORMAT",
|
||||
&sim_tape_set_fmt, &sim_tape_show_fmt, NULL},
|
||||
{MTAB_XTD | MTAB_VDV | MTAB_VALR, 0, "DEV", "DEV",
|
||||
&set_chan, &get_chan, NULL, "Device Number"},
|
||||
{0}
|
||||
};
|
||||
|
||||
UNIT mt_unit[] = {
|
||||
{UDATA(&mt_svc, UNIT_MT, 0) }, /* 0 */
|
||||
{UDATA(&mt_svc, UNIT_MT, 0) }, /* 1 */
|
||||
{UDATA(&mt_svc, UNIT_MT, 0) }, /* 2 */
|
||||
{UDATA(&mt_svc, UNIT_MT, 0) }, /* 3 */
|
||||
{UDATA(&mt_svc, UNIT_MT, 0) }, /* 4 */
|
||||
{UDATA(&mt_svc, UNIT_MT, 0) }, /* 5 */
|
||||
{UDATA(&mt_svc, UNIT_MT, 0) }, /* 6 */
|
||||
{UDATA(&mt_svc, UNIT_MT, 0) }, /* 7 */
|
||||
};
|
||||
|
||||
DEVICE mt_dev = {
|
||||
"MT", mt_unit, NULL, mt_mod,
|
||||
NUM_DEVS_MT, 8, 22, 1, 8, 22,
|
||||
NULL, NULL, &mt_reset, &mt_boot, &mt_attach, &mt_detach,
|
||||
&mt_dib, DEV_DISABLE | DEV_DEBUG | UNIT_ADDR(20), 0, dev_debug,
|
||||
NULL, NULL, &mt_help, NULL, NULL, &mt_description
|
||||
};
|
||||
|
||||
void mt_cmd(int dev, uint32 cmd, uint32 *resp) {
|
||||
UNIT *uptr = &mt_unit[mt_drive];
|
||||
*resp = 0;
|
||||
if (dev & 0400) {
|
||||
mt_drive = cmd & 07;
|
||||
return;
|
||||
}
|
||||
if ((uptr->flags & UNIT_ATT) == 0) {
|
||||
uptr->CMD = 0;
|
||||
return;
|
||||
}
|
||||
if (uptr->CMD & MT_QUAL) {
|
||||
*resp = 5;
|
||||
uptr->CMD &= ~MT_QUAL;
|
||||
} else {
|
||||
switch(cmd & 070) {
|
||||
case 000: if (cmd == 0) {
|
||||
*resp = 5;
|
||||
return;
|
||||
}
|
||||
uptr->CMD = cmd;
|
||||
if (cmd != 1)
|
||||
uptr->CMD |= MT_QUAL;
|
||||
break;
|
||||
case 010: uptr->CMD = cmd;
|
||||
if (cmd < 016)
|
||||
uptr->CMD |= MT_QUAL;
|
||||
break;
|
||||
case 020: if (cmd == SEND_Q) {
|
||||
if (!sim_tape_wrp(uptr))
|
||||
uptr->STATUS |= STQ_WRP;
|
||||
*resp = uptr->STATUS & 037;
|
||||
if (uptr->STATUS & 0777700)
|
||||
*resp |= STQ_P1;
|
||||
} else if (cmd == SEND_P) {
|
||||
*resp = (uptr->STATUS >> 6) & 037;
|
||||
if (uptr->STATUS & 0770000)
|
||||
*resp |= ST1_P2;
|
||||
} else if (cmd == SEND_P2) {
|
||||
*resp = (uptr->STATUS >> 12) & 037;
|
||||
}
|
||||
return;
|
||||
case 030: uptr->CMD = cmd;
|
||||
if (cmd < 036)
|
||||
uptr->CMD |= MT_QUAL;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
sim_debug(DEBUG_CMD, &mt_dev, "Cmd: unit=%d %02o\n", mt_drive, uptr->CMD);
|
||||
if (uptr->flags & MT_BUSY) {
|
||||
*resp = 3;
|
||||
return;
|
||||
}
|
||||
if ((uptr->CMD & MT_QUAL) == 0) {
|
||||
sim_debug(DEBUG_CMD, &mt_dev, "Cmd: unit=%d start %02o\n", mt_drive, uptr->CMD);
|
||||
mt_busy = 1;
|
||||
CLR_BUF(uptr);
|
||||
uptr->POS = 0;
|
||||
uptr->CMD |= MT_BUSY;
|
||||
uptr->STATUS = ST1_OK|STQ_ACCP;
|
||||
sim_activate(uptr, 100);
|
||||
}
|
||||
*resp = 5;
|
||||
}
|
||||
|
||||
t_stat mt_svc (UNIT *uptr)
|
||||
{
|
||||
DEVICE *dptr = &mt_dev;
|
||||
int unit = (uptr - dptr->units);
|
||||
int dev = GET_UADDR(dptr->flags);
|
||||
t_mtrlnt reclen;
|
||||
t_stat r;
|
||||
uint8 ch;
|
||||
uint32 word;
|
||||
int i;
|
||||
int stop;
|
||||
int eor;
|
||||
|
||||
/* If not busy, false schedule, just exit */
|
||||
if ((uptr->CMD & MT_BUSY) == 0)
|
||||
return SCPE_OK;
|
||||
switch (uptr->CMD & MT_CMD) {
|
||||
case MT_BOOT:
|
||||
case MT_READ:
|
||||
/* If empty buffer, fill */
|
||||
if (BUF_EMPTY(uptr)) {
|
||||
sim_debug(DEBUG_DETAIL, dptr, "Read unit=%d ", unit);
|
||||
if ((r = sim_tape_rdrecf(uptr, &mt_buffer[0], &reclen,
|
||||
BUFFSIZE)) != MTSE_OK) {
|
||||
sim_debug(DEBUG_DETAIL, dptr, " error %d\n", r);
|
||||
uptr->STATUS = ST1_OK|STQ_TERM;
|
||||
if (r == MTSE_TMK)
|
||||
uptr->STATUS |= ST1_WARN;
|
||||
else if (r == MTSE_WRP)
|
||||
uptr->STATUS |= ST1_ERR;
|
||||
else if (r == MTSE_EOM)
|
||||
uptr->STATUS |= ST1_WARN;
|
||||
else
|
||||
uptr->STATUS |= ST1_ERR;
|
||||
uptr->CMD = 0;
|
||||
mt_busy = 0;
|
||||
chan_set_done(dev);
|
||||
return SCPE_OK;
|
||||
}
|
||||
uptr->hwmark = reclen;
|
||||
sim_debug(DEBUG_DETAIL, dptr, "Block %d chars\n", reclen);
|
||||
}
|
||||
stop = 0;
|
||||
/* Grab three chars off buffer */
|
||||
word = 0;
|
||||
for(i = 16; i >= 0; i-=8) {
|
||||
if (uptr->POS >= uptr->hwmark) {
|
||||
/* Add in fill characters */
|
||||
if (i == 8) {
|
||||
stop = 2;
|
||||
} else if (i == 16) {
|
||||
stop = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
word |= (uint32)mt_buffer[uptr->POS++] << i;
|
||||
}
|
||||
sim_debug(DEBUG_DATA, dptr, "unit=%d read %08o\n", unit, word);
|
||||
eor = chan_input_word(dev, &word, 0);
|
||||
if (eor || uptr->POS >= uptr->hwmark) {
|
||||
uptr->STATUS = (stop << 12) | ST1_OK|STQ_TERM;
|
||||
if (uptr->POS < uptr->hwmark)
|
||||
uptr->STATUS |= ST1_LONG;
|
||||
uptr->CMD = 0;
|
||||
mt_busy = 0;
|
||||
chan_set_done(dev);
|
||||
return SCPE_OK;
|
||||
}
|
||||
sim_activate(uptr, 100);
|
||||
break;
|
||||
|
||||
case MT_WRITEERG: /* Write and Erase */
|
||||
case MT_WRITE:
|
||||
/* Check if write protected */
|
||||
if (sim_tape_wrp(uptr)) {
|
||||
uptr->STATUS = ST1_OK|STQ_TERM|ST1_ERR;
|
||||
uptr->CMD &= ~MT_BUSY;
|
||||
mt_busy = 0;
|
||||
chan_set_done(dev);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
eor = chan_output_word(dev, &word, 0);
|
||||
sim_debug(DEBUG_DATA, dptr, "unit=%d write %08o\n", unit, word);
|
||||
|
||||
/* Put three chars in buffer */
|
||||
word = 0;
|
||||
for(i = 16; i >= 0; i-=8) {
|
||||
mt_buffer[uptr->POS++] = (uint8)((word >> i) & 0xff);
|
||||
}
|
||||
uptr->hwmark = uptr->POS;
|
||||
if (eor) {
|
||||
/* Done with transfer */
|
||||
reclen = uptr->hwmark;
|
||||
sim_debug(DEBUG_DETAIL, dptr, "Write unit=%d Block %d chars\n",
|
||||
unit, reclen);
|
||||
r = sim_tape_wrrecf(uptr, &mt_buffer[0], reclen);
|
||||
uptr->STATUS = ST1_OK|STQ_TERM;
|
||||
if (r != MTSE_OK)
|
||||
uptr->STATUS |= ST1_ERR;
|
||||
uptr->CMD = 0;
|
||||
mt_busy = 0;
|
||||
chan_set_done(dev);
|
||||
return SCPE_OK;
|
||||
}
|
||||
sim_activate(uptr, 100);
|
||||
break;
|
||||
|
||||
case MT_REV_READ:
|
||||
/* If empty buffer, fill */
|
||||
if (BUF_EMPTY(uptr)) {
|
||||
if (sim_tape_bot(uptr)) {
|
||||
uptr->STATUS = ST1_OK|ST1_WARN|STQ_TERM;
|
||||
uptr->CMD = 0;
|
||||
mt_busy = 0;
|
||||
chan_set_done(dev);
|
||||
return SCPE_OK;
|
||||
}
|
||||
sim_debug(DEBUG_DETAIL, dptr, "Read rev unit=%d ", unit);
|
||||
if ((r = sim_tape_rdrecr(uptr, &mt_buffer[0], &reclen,
|
||||
BUFFSIZE)) != MTSE_OK) {
|
||||
sim_debug(DEBUG_DETAIL, dptr, " error %d\n", r);
|
||||
uptr->STATUS = ST1_OK|STQ_TERM;
|
||||
if (r == MTSE_TMK)
|
||||
uptr->STATUS |= ST1_WARN;
|
||||
else if (r == MTSE_WRP)
|
||||
uptr->STATUS |= ST1_ERR;
|
||||
else if (r == MTSE_EOM)
|
||||
uptr->STATUS |= ST1_WARN;
|
||||
else
|
||||
uptr->STATUS |= ST1_ERR;
|
||||
uptr->CMD = 0;
|
||||
mt_busy = 0;
|
||||
chan_set_done(dev);
|
||||
return SCPE_OK;
|
||||
}
|
||||
uptr->POS = reclen;
|
||||
uptr->hwmark = reclen;
|
||||
sim_debug(DEBUG_DETAIL, dptr, "Block %d chars\n", reclen);
|
||||
}
|
||||
/* Grab three chars off buffer */
|
||||
word = 0;
|
||||
for(i = 0; i <= 16; i+=8) {
|
||||
word |= (uint32)mt_buffer[--uptr->POS] << i;
|
||||
if (uptr->POS == 0) {
|
||||
stop = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
sim_debug(DEBUG_DATA, dptr, "unit=%d read %08o\n", unit, word);
|
||||
eor = chan_input_word(dev, &word, 0);
|
||||
if (eor || uptr->POS == 0) {
|
||||
uptr->STATUS = (stop << 12) | ST1_OK|STQ_TERM;
|
||||
if (uptr->POS != 0)
|
||||
uptr->STATUS |= ST1_LONG;
|
||||
uptr->CMD = 0;
|
||||
mt_busy = 0;
|
||||
chan_set_done(dev);
|
||||
return SCPE_OK;
|
||||
}
|
||||
sim_activate(uptr, 100);
|
||||
break;
|
||||
|
||||
case MT_FSF:
|
||||
switch(uptr->POS) {
|
||||
case 0:
|
||||
uptr->POS ++;
|
||||
sim_activate(uptr, 500);
|
||||
break;
|
||||
case 1:
|
||||
sim_debug(DEBUG_DETAIL, dptr, "Skip rec unit=%d ", unit);
|
||||
r = sim_tape_sprecf(uptr, &reclen);
|
||||
if (r == MTSE_TMK) {
|
||||
uptr->POS++;
|
||||
sim_debug(DEBUG_DETAIL, dptr, "MARK\n");
|
||||
sim_activate(uptr, 50);
|
||||
} else if (r == MTSE_EOM) {
|
||||
uptr->POS++;
|
||||
uptr->STATUS = ST1_WARN;
|
||||
sim_activate(uptr, 50);
|
||||
} else {
|
||||
sim_debug(DEBUG_DETAIL, dptr, "%d\n", reclen);
|
||||
sim_activate(uptr, 10 + (10 * reclen));
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
uptr->STATUS = ST1_OK|(ST1_WARN & uptr->STATUS) | STQ_TERM;
|
||||
uptr->CMD = 0;
|
||||
mt_busy = 0;
|
||||
chan_set_done(dev);
|
||||
}
|
||||
break;
|
||||
|
||||
case MT_WTM:
|
||||
if (uptr->POS == 0) {
|
||||
if (sim_tape_wrp(uptr)) {
|
||||
uptr->STATUS = ST1_OK|ST1_ERR|STQ_TERM;
|
||||
uptr->CMD = 0;
|
||||
mt_busy = 0;
|
||||
chan_set_done(dev);
|
||||
return SCPE_OK;
|
||||
}
|
||||
uptr->POS ++;
|
||||
sim_activate(uptr, 500);
|
||||
} else {
|
||||
sim_debug(DEBUG_DETAIL, dptr, "Write Mark unit=%d\n", unit);
|
||||
r = sim_tape_wrtmk(uptr);
|
||||
uptr->STATUS = ST1_OK|STQ_TERM;
|
||||
if (r != MTSE_OK)
|
||||
uptr->STATUS |= ST1_ERR;
|
||||
uptr->CMD = 0;
|
||||
mt_busy = 0;
|
||||
chan_set_done(dev);
|
||||
}
|
||||
break;
|
||||
|
||||
case MT_BSR:
|
||||
switch (uptr->POS ) {
|
||||
case 0:
|
||||
if (sim_tape_bot(uptr)) {
|
||||
uptr->STATUS = ST1_OK|ST1_WARN|STQ_TERM;
|
||||
uptr->CMD = 0;
|
||||
mt_busy = 0;
|
||||
chan_set_done(dev);
|
||||
break;
|
||||
}
|
||||
uptr->POS ++;
|
||||
sim_activate(uptr, 500);
|
||||
break;
|
||||
case 1:
|
||||
sim_debug(DEBUG_DETAIL, dptr, "Backspace rec unit=%d ", unit);
|
||||
r = sim_tape_sprecr(uptr, &reclen);
|
||||
/* We don't set EOF on BSR */
|
||||
uptr->STATUS = ST1_OK|STQ_TERM;
|
||||
if (r == MTSE_TMK || r == MTSE_BOT) {
|
||||
uptr->STATUS |= ST1_WARN;
|
||||
}
|
||||
uptr->CMD = 0;
|
||||
mt_busy = 0;
|
||||
chan_set_done(dev);
|
||||
}
|
||||
break;
|
||||
|
||||
case MT_BSF:
|
||||
switch (uptr->POS ) {
|
||||
case 0:
|
||||
if (sim_tape_bot(uptr)) {
|
||||
uptr->STATUS = ST1_OK|ST1_WARN|STQ_TERM;
|
||||
uptr->CMD = 0;
|
||||
mt_busy = 0;
|
||||
chan_set_done(dev);
|
||||
break;
|
||||
}
|
||||
uptr->POS ++;
|
||||
sim_activate(uptr, 500);
|
||||
break;
|
||||
case 1:
|
||||
sim_debug(DEBUG_DETAIL, dptr, "Backspace rec unit=%d ", unit);
|
||||
r = sim_tape_sprecr(uptr, &reclen);
|
||||
/* We don't set EOF on BSR */
|
||||
if (r == MTSE_TMK || r == MTSE_BOT) {
|
||||
uptr->POS++;
|
||||
sim_activate(uptr, 50);
|
||||
} else {
|
||||
sim_debug(DEBUG_DETAIL, dptr, "%d \n", reclen);
|
||||
sim_activate(uptr, 10 + (10 * reclen));
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
uptr->STATUS = ST1_OK|STQ_TERM;
|
||||
uptr->CMD = 0;
|
||||
mt_busy = 0;
|
||||
chan_set_done(dev);
|
||||
}
|
||||
break;
|
||||
|
||||
case MT_REW:
|
||||
if (uptr->POS == 0) {
|
||||
uptr->POS ++;
|
||||
sim_activate(uptr, 30000);
|
||||
mt_busy = 0;
|
||||
} else {
|
||||
sim_debug(DEBUG_DETAIL, dptr, "Rewind unit=%d\n", unit);
|
||||
r = sim_tape_rewind(uptr);
|
||||
uptr->CMD = 0;
|
||||
uptr->STATUS = ST1_OK|STQ_TERM;
|
||||
chan_set_done(dev);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
|
||||
/* Reset */
|
||||
|
||||
t_stat mt_reset (DEVICE *dptr)
|
||||
{
|
||||
UNIT *uptr = dptr->units;
|
||||
int unit;
|
||||
|
||||
for (unit = 0; unit < dptr->numunits; unit++, uptr++) {
|
||||
uptr->CMD = 0;
|
||||
uptr->STATUS = 0;
|
||||
if ((uptr->flags & UNIT_ATT) != 0)
|
||||
uptr->STATUS = ST1_OK;
|
||||
mt_busy = 0;
|
||||
}
|
||||
chan_clr_done(GET_UADDR(dptr->flags));
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Boot from given device */
|
||||
t_stat
|
||||
mt_boot(int32 unit_num, DEVICE * dptr)
|
||||
{
|
||||
UNIT *uptr = &dptr->units[unit_num];
|
||||
int chan = GET_UADDR(dptr->flags);
|
||||
|
||||
if ((uptr->flags & UNIT_ATT) == 0)
|
||||
return SCPE_UNATT; /* attached? */
|
||||
|
||||
M[64 + chan] = 0;
|
||||
M[256 + 4 * chan] = B2;
|
||||
M[257 + 4 * chan] = 020;
|
||||
loading = 1;
|
||||
mt_busy = 1;
|
||||
CLR_BUF(uptr);
|
||||
uptr->CMD = MT_BUSY|MT_BOOT;
|
||||
uptr->STATUS = ST1_OK|STQ_ACCP;
|
||||
sim_activate (uptr, 100);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat
|
||||
mt_attach(UNIT * uptr, CONST char *file)
|
||||
{
|
||||
t_stat r;
|
||||
DEVICE *dptr = &mt_dev;
|
||||
int unit = (uptr - dptr->units);
|
||||
|
||||
if ((r = sim_tape_attach_ex(uptr, file, 0, 0)) != SCPE_OK)
|
||||
return r;
|
||||
uptr->STATUS = ST1_OK;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat
|
||||
mt_detach(UNIT * uptr)
|
||||
{
|
||||
uptr->STATUS = 0;
|
||||
return sim_tape_detach(uptr);
|
||||
}
|
||||
|
||||
|
||||
t_stat mt_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cmt)
|
||||
{
|
||||
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 *mt_description (DEVICE *dptr)
|
||||
{
|
||||
return "MT";
|
||||
|
||||
}
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -50,7 +50,7 @@ chan_set_devs()
|
||||
devs[i] = NULL;
|
||||
|
||||
/* Add in hidden channels */
|
||||
devs[22] = &nul_dib;
|
||||
devs[22] = &nul_dib;
|
||||
devs[23] = &nul_dib;
|
||||
/* Scan all devices and assign to channel */
|
||||
for(i = 0; sim_devices[i] != NULL; i++) {
|
||||
@@ -64,7 +64,7 @@ chan_set_devs()
|
||||
continue;
|
||||
if (dibp->type & BLK_DEV) {
|
||||
int f = 1;
|
||||
|
||||
|
||||
chan = GET_UADDR(sim_devices[i]->flags);
|
||||
/* Make sure it is in range */
|
||||
if (chan < 2 || (chan + sim_devices[i]->numunits) > 36)
|
||||
@@ -76,13 +76,13 @@ chan_set_devs()
|
||||
fprintf(stderr, "Conflict between devices %d %s\n", chan+j, sim_devices[i]->name);
|
||||
f = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (f) {
|
||||
for (j = 0; j < sim_devices[i]->numunits; j++) {
|
||||
if (sim_devices[i]->units[j].flags & UNIT_DIS)
|
||||
continue;
|
||||
devs[chan+j] = dibp;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (dibp->type & MULT_DEV) {
|
||||
chan = GET_UADDR(sim_devices[i]->flags);
|
||||
@@ -136,7 +136,7 @@ set_chan(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
||||
if (dptr == NULL)
|
||||
return SCPE_IERR;
|
||||
dibp = (DIB *) dptr->ctxt;
|
||||
|
||||
|
||||
if (dibp == NULL)
|
||||
return SCPE_IERR;
|
||||
new_chan = get_uint(cptr, 10, 37, &r);
|
||||
@@ -160,7 +160,7 @@ set_chan(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
||||
for (i = 0; i < dptr->numunits; i++) {
|
||||
if (dptr->units[i].flags & UNIT_DIS)
|
||||
continue;
|
||||
if (devs[cur_chan+i] == dibp)
|
||||
if (devs[cur_chan+i] == dibp)
|
||||
devs[cur_chan] = NULL;
|
||||
}
|
||||
} else if (dibp->type & MULT_DEV) {
|
||||
@@ -181,7 +181,7 @@ set_chan(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
|
||||
if (dibp->type & BLK_DEV) {
|
||||
dptr->flags &= ~UNIT_M_ADDR;
|
||||
dptr->flags |= UNIT_ADDR(new_chan);
|
||||
@@ -210,7 +210,7 @@ set_chan(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
||||
|
||||
/* Print the channel the device is on */
|
||||
t_stat
|
||||
get_chan(FILE *st, UNIT *uptr, int32 v, CONST void *desc)
|
||||
get_chan(FILE *st, UNIT *uptr, int32 v, CONST void *desc)
|
||||
{
|
||||
DEVICE *dptr;
|
||||
DIB *dibp;
|
||||
@@ -236,7 +236,7 @@ get_chan(FILE *st, UNIT *uptr, int32 v, CONST void *desc)
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
int
|
||||
int
|
||||
get_ccw(int dev, uint32 *addr, uint8 type) {
|
||||
int cw_addr;
|
||||
uint32 cw0; /* Holding registers for current control word */
|
||||
@@ -248,7 +248,7 @@ get_ccw(int dev, uint32 *addr, uint8 type) {
|
||||
cw1 = M[cw_addr+1];
|
||||
*addr = cw1;
|
||||
if (cw0 & WORDCCW) {
|
||||
if (cw0 & BACKWARD)
|
||||
if (cw0 & BACKWARD)
|
||||
cw1 = ((cw1 + M22) & M22) | (cw1 & CMASK);
|
||||
else
|
||||
cw1 = ((cw1 + 1) & M22) | (cw1 & CMASK);
|
||||
@@ -274,7 +274,7 @@ get_ccw(int dev, uint32 *addr, uint8 type) {
|
||||
cw1 = M[cw_addr+3];
|
||||
} else if ((cw0 & GATHER) != 0) {
|
||||
int a;
|
||||
if ((cw0 & CWRECHARGE) != 0)
|
||||
if ((cw0 & CWRECHARGE) != 0)
|
||||
M[cw_addr+3] = M[cw_addr+2];
|
||||
a = M[cw_addr+3];
|
||||
cw0 = M[a & M22];
|
||||
@@ -328,7 +328,7 @@ chan_nsi_cmd(int dev, uint32 cmd) {
|
||||
|
||||
if (dibp != NULL && dibp->nsi_cmd != NULL) {
|
||||
(dibp->nsi_cmd)(dev, cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Talk to non-standard interface devices */
|
||||
@@ -339,7 +339,7 @@ chan_nsi_status(int dev, uint32 *resp) {
|
||||
*resp = 0;
|
||||
if (dibp != NULL && dibp->nsi_cmd != NULL) {
|
||||
(dibp->nsi_status)(dev, resp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -351,7 +351,7 @@ chan_send_cmd(int dev, uint32 cmd, uint32 *resp) {
|
||||
*resp = 0;
|
||||
if (dibp != NULL && dibp->si_cmd != NULL) {
|
||||
(dibp->si_cmd)(dev, cmd, resp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Transfer date between device and memory */
|
||||
@@ -384,8 +384,7 @@ chan_input_char(int dev, uint8 *data, int eor) {
|
||||
mb |= ((uint32)(*data) & 077) << c;
|
||||
if (addr < 8)
|
||||
XR[addr] = mb;
|
||||
else
|
||||
M[addr] = mb;
|
||||
M[addr] = mb;
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -437,8 +436,7 @@ chan_input_word(int dev, uint32 *data, int eor) {
|
||||
addr &= M22;
|
||||
if (addr < 8)
|
||||
XR[addr] = *data;
|
||||
else
|
||||
M[addr] = *data;
|
||||
M[addr] = *data;
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -468,7 +466,7 @@ chan_output_word(int dev, uint32 *data, int eor) {
|
||||
|
||||
void
|
||||
chan_set_done(int dev) {
|
||||
if (dev < 22)
|
||||
if (dev < 22)
|
||||
SR64 |= B2 >> dev;
|
||||
else
|
||||
SR65 |= B1 >> (dev - 23);
|
||||
@@ -476,7 +474,7 @@ chan_set_done(int dev) {
|
||||
|
||||
void
|
||||
chan_clr_done(int dev) {
|
||||
if (dev < 22)
|
||||
if (dev < 22)
|
||||
SR64 &= ~(B2 >> dev);
|
||||
else
|
||||
SR65 &= ~(B1 >> (dev - 23));
|
||||
|
||||
@@ -92,8 +92,8 @@ DEBTAB dev_debug[] = {
|
||||
};
|
||||
|
||||
|
||||
uint8 parity_table[64] = {
|
||||
/* 0 1 2 3 4 5 6 7 */
|
||||
uint8 parity_table[64] = {
|
||||
/* 0 1 2 3 4 5 6 7 */
|
||||
0000, 0100, 0100, 0000, 0100, 0000, 0000, 0100,
|
||||
0100, 0000, 0000, 0100, 0000, 0100, 0100, 0000,
|
||||
0100, 0000, 0000, 0100, 0000, 0100, 0100, 0000,
|
||||
@@ -105,7 +105,7 @@ uint8 parity_table[64] = {
|
||||
};
|
||||
|
||||
uint8 mem_to_ascii[64] = {
|
||||
/* x0 x1 x2 x3 x4 x5 x6 x7 */
|
||||
/* x0 x1 x2 x3 x4 x5 x6 x7 */
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', /* 0x */
|
||||
'8', '9', ':', ';', '<', '=', '>', '?', /* 1x */
|
||||
' ', '!', '"', '#', '\\', '%', '&', '\'', /* 2x */
|
||||
@@ -174,19 +174,17 @@ sim_load(FILE * fileref, CONST char *cptr, CONST char *fnam, int flag)
|
||||
if (buffer[j] == '\n')
|
||||
break;
|
||||
image[j] = ascii_to_mem[buffer[j]];
|
||||
if (image[j] < 0) {
|
||||
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++)
|
||||
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
|
||||
if (addr < 8)
|
||||
XR[addr++] = data;
|
||||
M[addr++] = data;
|
||||
}
|
||||
}
|
||||
@@ -199,7 +197,7 @@ else
|
||||
if (buffer[j] == '\n')
|
||||
break;
|
||||
image[j] = ascii_to_mem[buffer[j]];
|
||||
if (image[j] < 0) {
|
||||
if (image[j] < 0) {
|
||||
fprintf(stderr, "Char %c: %s", buffer[j], buffer);
|
||||
return SCPE_FMT;
|
||||
}
|
||||
@@ -211,24 +209,24 @@ else
|
||||
switch(image[3]) {
|
||||
case 0:
|
||||
checksum = 0;
|
||||
for (j = 0; j < 4; j++)
|
||||
for (j = 0; j < 4; j++)
|
||||
checksum = (checksum << 6) | image[j];
|
||||
addr = 0;
|
||||
for (; j < 8; j++)
|
||||
for (; j < 8; j++)
|
||||
addr = (addr << 6) | image[j];
|
||||
checksum += addr;
|
||||
for (i = 3; i < image[1]; i++) {
|
||||
data = 0;
|
||||
for (k = 0; k < 4; k++)
|
||||
for (k = 0; k < 4; k++)
|
||||
data = (data << 6) | image[j++];
|
||||
checksum += data;
|
||||
M[addr++] = data;
|
||||
}
|
||||
data = 0;
|
||||
for (k = 0; k < 4; k++)
|
||||
for (k = 0; k < 4; k++)
|
||||
data = (data << 6) | image[j++];
|
||||
data = FMASK & (checksum + data);
|
||||
if (data != 0)
|
||||
if (data != 0)
|
||||
fprintf(stderr, "Check %08o %08o: %s", addr, data, buffer);
|
||||
break;
|
||||
case 1:
|
||||
@@ -237,24 +235,24 @@ else
|
||||
case 2:
|
||||
case 3:
|
||||
checksum = 0;
|
||||
for (j = 0; j < 4; j++)
|
||||
for (j = 0; j < 4; j++)
|
||||
checksum = (checksum << 6) | image[j];
|
||||
addr = 0;
|
||||
for (; j < 8; j++)
|
||||
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++)
|
||||
for (k = 0; k < 4; k++)
|
||||
data = (data << 6) | image[j++];
|
||||
checksum += data;
|
||||
}
|
||||
for (k = 0; k < 4; k++)
|
||||
for (k = 0; k < 4; k++)
|
||||
data = (data << 6) | image[j++];
|
||||
data = FMASK & (checksum + data);
|
||||
if (data != 0)
|
||||
if (data != 0)
|
||||
fprintf(stderr, "Check %08o %08o: %s", addr, data, buffer);
|
||||
break;
|
||||
case 4:
|
||||
@@ -282,134 +280,134 @@ else
|
||||
|
||||
/* Opcodes */
|
||||
t_opcode ops[] = {
|
||||
"LDX", TYPE_A, /* Load to X */
|
||||
"ADX", TYPE_A, /* Add to X */
|
||||
"NGX", TYPE_A, /* Negative to X */
|
||||
"SBX", TYPE_A, /* Subtract from X */
|
||||
"LDXC", TYPE_A, /* Load into X with carry */
|
||||
"ADXC", TYPE_A, /* Add to X with carry */
|
||||
"NGXC", TYPE_A, /* Negative to X with carry */
|
||||
"SBXC", TYPE_A, /* Subtract from X with carry */
|
||||
"STO", TYPE_A, /* Store contents of X */
|
||||
"ADS", TYPE_A, /* Add X to store */
|
||||
"NGS", TYPE_A, /* Negative into Store */
|
||||
"SBS", TYPE_A, /* Subtract from store */
|
||||
"STOC", TYPE_A, /* Store contents of X with carry */
|
||||
"ADSC", TYPE_A, /* Add X to store with carry */
|
||||
"NGSC", TYPE_A, /* Negative into Store with carry */
|
||||
"SBSC", TYPE_A, /* Subtract from store with carry */
|
||||
"ANDX", TYPE_A, /* Logical AND into X */
|
||||
"ORX", TYPE_A, /* Logical OR into X */
|
||||
"ERX", TYPE_A, /* Logical XOR into X */
|
||||
"OBEY", TYPE_A, /* Obey instruction at N */
|
||||
"LDCH", TYPE_A, /* Load Character to X */
|
||||
"LDEX", TYPE_A, /* Load Exponent */
|
||||
"TXU", TYPE_A, /* Test X unequal */
|
||||
"TXL", TYPE_A, /* Test X Less */
|
||||
"ANDS", TYPE_A, /* Logical AND into store */
|
||||
"ORS", TYPE_A, /* Logical OR into store */
|
||||
"ERS", TYPE_A, /* Logical XOR into store */
|
||||
"STOZ", TYPE_A, /* Store Zero */
|
||||
"DCH", TYPE_A, /* Deposit Character to X */
|
||||
"DEX", TYPE_A, /* Deposit Exponent */
|
||||
"DSA", TYPE_A, /* Deposit Short Address */
|
||||
"DLA", TYPE_A, /* Deposit Long Address */
|
||||
"MPY", TYPE_A, /* Multiply */
|
||||
"MPR", TYPE_A, /* Multiply and Round */
|
||||
"MPA", TYPE_A, /* Multiply and Accumulate */
|
||||
"CDB", TYPE_A, /* Convert Decimal to Binary */
|
||||
"DVD", TYPE_A, /* Unrounded Double Length Divide */
|
||||
"DVR", TYPE_A, /* Rounded Double Length Divide */
|
||||
"DVS", TYPE_A, /* Single Length Divide */
|
||||
"CBD", TYPE_A, /* Convert Binary to Decimal */
|
||||
"BZE", TYPE_B, /* Branch if X is Zero */
|
||||
"BZE", TYPE_B,
|
||||
"BNZ", TYPE_B, /* Branch if X is not Zero */
|
||||
"BNZ", TYPE_B,
|
||||
"BPZ", TYPE_B, /* Branch if X is Positive or zero */
|
||||
"BPZ", TYPE_B,
|
||||
"BNG", TYPE_B, /* Branch if X is Positive or zero */
|
||||
"BNG", TYPE_B,
|
||||
"BUX", TYPE_B, /* Branch on Unit indexing */
|
||||
"BUX", TYPE_B,
|
||||
"BDX", TYPE_B, /* Branch on Double Indexing */
|
||||
"BDX", TYPE_B,
|
||||
"BCHX", TYPE_B, /* Branch on Character Indexing */
|
||||
"BCHX", TYPE_B,
|
||||
"BCT", TYPE_B, /* Branch on Count - BC */
|
||||
"BCT", TYPE_B,
|
||||
"CALL", TYPE_B, /* Call Subroutine */
|
||||
"CALL", TYPE_B,
|
||||
"EXIT", TYPE_B, /* Exit Subroutine */
|
||||
"EXIT", TYPE_B,
|
||||
NULL, TYPE_D, /* Branch unconditional */
|
||||
NULL, TYPE_D,
|
||||
"BFP", TYPE_B, /* Branch state of floating point accumulator */
|
||||
"BFP", TYPE_B,
|
||||
"LDN", TYPE_A, /* Load direct to X */
|
||||
"ADN", TYPE_A, /* Add direct to X */
|
||||
"NGN", TYPE_A, /* Negative direct to X */
|
||||
"SBN", TYPE_A, /* Subtract direct from X */
|
||||
"LDNC", TYPE_A, /* Load direct into X with carry */
|
||||
"ADNC", TYPE_A, /* Add direct to X with carry */
|
||||
"NGNC", TYPE_A, /* Negative direct to X with carry */
|
||||
"SBNC", TYPE_A, /* Subtract direct from X with carry */
|
||||
"SL", TYPE_C, /* Shift Left */
|
||||
"SLD", TYPE_C, /* Shift Left Double */
|
||||
"SR", TYPE_C, /* Shift Right */
|
||||
"SRD", TYPE_C, /* Shift Right Double */
|
||||
"NORM", TYPE_A, /* Nomarlize Single -2 +FP */
|
||||
"NORMD", TYPE_A, /* Normalize Double -2 +FP */
|
||||
"MVCH", TYPE_A, /* Move Characters - BC */
|
||||
"SMO", TYPE_A, /* Supplementary Modifier - BC */
|
||||
"ANDN", TYPE_A, /* Logical AND direct into X */
|
||||
"ORN", TYPE_A, /* Logical OR direct into X */
|
||||
"ERN", TYPE_A, /* Logical XOR direct into X */
|
||||
"NULL", TYPE_A, /* No Operation */
|
||||
"LDCT", TYPE_A, /* Load Count */
|
||||
"MODE", TYPE_A, /* Set Mode */
|
||||
"MOVE", TYPE_A, /* Copy N words */
|
||||
"SUM", TYPE_A, /* Sum N words */
|
||||
"FLOAT", TYPE_A, /* Convert Fixed to Float +FP */
|
||||
"FIX", TYPE_A, /* Convert Float to Fixed +FP */
|
||||
"FAD", TYPE_A, /* Floating Point Add +FP */
|
||||
"FSB", TYPE_A, /* Floating Point Subtract +FP */
|
||||
"FMPY", TYPE_A, /* Floating Point Multiply +FP */
|
||||
"FDVD", TYPE_A, /* Floating Point Divide +FP */
|
||||
"LFP", TYPE_A, /* Load Floating Point +FP */
|
||||
"SFP", TYPE_A, /* Store Floating Point +FP */
|
||||
"140", TYPE_A,
|
||||
"141", TYPE_A,
|
||||
"142", TYPE_A,
|
||||
"143", TYPE_A,
|
||||
"144", TYPE_A,
|
||||
"145", TYPE_A,
|
||||
"146", TYPE_A,
|
||||
"147", TYPE_A,
|
||||
"150", TYPE_A,
|
||||
"151", TYPE_A,
|
||||
"152", TYPE_A,
|
||||
"153", TYPE_A,
|
||||
"154", TYPE_A,
|
||||
"155", TYPE_A,
|
||||
"156", TYPE_A,
|
||||
"157", TYPE_A,
|
||||
"160", TYPE_A,
|
||||
"161", TYPE_A,
|
||||
"162", TYPE_A,
|
||||
"163", TYPE_A,
|
||||
"164", TYPE_A,
|
||||
"165", TYPE_A,
|
||||
"166", TYPE_A,
|
||||
"167", TYPE_A,
|
||||
"170", TYPE_A,
|
||||
"171", TYPE_A,
|
||||
"172", TYPE_A,
|
||||
"173", TYPE_A,
|
||||
"174", TYPE_A,
|
||||
"175", TYPE_A,
|
||||
"176", TYPE_A,
|
||||
"177", TYPE_A,
|
||||
"LDX", TYPE_A, /* Load to X */
|
||||
"ADX", TYPE_A, /* Add to X */
|
||||
"NGX", TYPE_A, /* Negative to X */
|
||||
"SBX", TYPE_A, /* Subtract from X */
|
||||
"LDXC", TYPE_A, /* Load into X with carry */
|
||||
"ADXC", TYPE_A, /* Add to X with carry */
|
||||
"NGXC", TYPE_A, /* Negative to X with carry */
|
||||
"SBXC", TYPE_A, /* Subtract from X with carry */
|
||||
"STO", TYPE_A, /* Store contents of X */
|
||||
"ADS", TYPE_A, /* Add X to store */
|
||||
"NGS", TYPE_A, /* Negative into Store */
|
||||
"SBS", TYPE_A, /* Subtract from store */
|
||||
"STOC", TYPE_A, /* Store contents of X with carry */
|
||||
"ADSC", TYPE_A, /* Add X to store with carry */
|
||||
"NGSC", TYPE_A, /* Negative into Store with carry */
|
||||
"SBSC", TYPE_A, /* Subtract from store with carry */
|
||||
"ANDX", TYPE_A, /* Logical AND into X */
|
||||
"ORX", TYPE_A, /* Logical OR into X */
|
||||
"ERX", TYPE_A, /* Logical XOR into X */
|
||||
"OBEY", TYPE_A, /* Obey instruction at N */
|
||||
"LDCH", TYPE_A, /* Load Character to X */
|
||||
"LDEX", TYPE_A, /* Load Exponent */
|
||||
"TXU", TYPE_A, /* Test X unequal */
|
||||
"TXL", TYPE_A, /* Test X Less */
|
||||
"ANDS", TYPE_A, /* Logical AND into store */
|
||||
"ORS", TYPE_A, /* Logical OR into store */
|
||||
"ERS", TYPE_A, /* Logical XOR into store */
|
||||
"STOZ", TYPE_A, /* Store Zero */
|
||||
"DCH", TYPE_A, /* Deposit Character to X */
|
||||
"DEX", TYPE_A, /* Deposit Exponent */
|
||||
"DSA", TYPE_A, /* Deposit Short Address */
|
||||
"DLA", TYPE_A, /* Deposit Long Address */
|
||||
"MPY", TYPE_A, /* Multiply */
|
||||
"MPR", TYPE_A, /* Multiply and Round */
|
||||
"MPA", TYPE_A, /* Multiply and Accumulate */
|
||||
"CDB", TYPE_A, /* Convert Decimal to Binary */
|
||||
"DVD", TYPE_A, /* Unrounded Double Length Divide */
|
||||
"DVR", TYPE_A, /* Rounded Double Length Divide */
|
||||
"DVS", TYPE_A, /* Single Length Divide */
|
||||
"CBD", TYPE_A, /* Convert Binary to Decimal */
|
||||
"BZE", TYPE_B, /* Branch if X is Zero */
|
||||
"BZE", TYPE_B,
|
||||
"BNZ", TYPE_B, /* Branch if X is not Zero */
|
||||
"BNZ", TYPE_B,
|
||||
"BPZ", TYPE_B, /* Branch if X is Positive or zero */
|
||||
"BPZ", TYPE_B,
|
||||
"BNG", TYPE_B, /* Branch if X is Positive or zero */
|
||||
"BNG", TYPE_B,
|
||||
"BUX", TYPE_B, /* Branch on Unit indexing */
|
||||
"BUX", TYPE_B,
|
||||
"BDX", TYPE_B, /* Branch on Double Indexing */
|
||||
"BDX", TYPE_B,
|
||||
"BCHX", TYPE_B, /* Branch on Character Indexing */
|
||||
"BCHX", TYPE_B,
|
||||
"BCT", TYPE_B, /* Branch on Count - BC */
|
||||
"BCT", TYPE_B,
|
||||
"CALL", TYPE_B, /* Call Subroutine */
|
||||
"CALL", TYPE_B,
|
||||
"EXIT", TYPE_B, /* Exit Subroutine */
|
||||
"EXIT", TYPE_B,
|
||||
NULL, TYPE_D, /* Branch unconditional */
|
||||
NULL, TYPE_D,
|
||||
"BFP", TYPE_B, /* Branch state of floating point accumulator */
|
||||
"BFP", TYPE_B,
|
||||
"LDN", TYPE_A, /* Load direct to X */
|
||||
"ADN", TYPE_A, /* Add direct to X */
|
||||
"NGN", TYPE_A, /* Negative direct to X */
|
||||
"SBN", TYPE_A, /* Subtract direct from X */
|
||||
"LDNC", TYPE_A, /* Load direct into X with carry */
|
||||
"ADNC", TYPE_A, /* Add direct to X with carry */
|
||||
"NGNC", TYPE_A, /* Negative direct to X with carry */
|
||||
"SBNC", TYPE_A, /* Subtract direct from X with carry */
|
||||
"SL", TYPE_C, /* Shift Left */
|
||||
"SLD", TYPE_C, /* Shift Left Double */
|
||||
"SR", TYPE_C, /* Shift Right */
|
||||
"SRD", TYPE_C, /* Shift Right Double */
|
||||
"NORM", TYPE_A, /* Nomarlize Single -2 +FP */
|
||||
"NORMD", TYPE_A, /* Normalize Double -2 +FP */
|
||||
"MVCH", TYPE_A, /* Move Characters - BC */
|
||||
"SMO", TYPE_A, /* Supplementary Modifier - BC */
|
||||
"ANDN", TYPE_A, /* Logical AND direct into X */
|
||||
"ORN", TYPE_A, /* Logical OR direct into X */
|
||||
"ERN", TYPE_A, /* Logical XOR direct into X */
|
||||
"NULL", TYPE_A, /* No Operation */
|
||||
"LDCT", TYPE_A, /* Load Count */
|
||||
"MODE", TYPE_A, /* Set Mode */
|
||||
"MOVE", TYPE_A, /* Copy N words */
|
||||
"SUM", TYPE_A, /* Sum N words */
|
||||
"FLOAT", TYPE_A, /* Convert Fixed to Float +FP */
|
||||
"FIX", TYPE_A, /* Convert Float to Fixed +FP */
|
||||
"FAD", TYPE_A, /* Floating Point Add +FP */
|
||||
"FSB", TYPE_A, /* Floating Point Subtract +FP */
|
||||
"FMPY", TYPE_A, /* Floating Point Multiply +FP */
|
||||
"FDVD", TYPE_A, /* Floating Point Divide +FP */
|
||||
"LFP", TYPE_A, /* Load Floating Point +FP */
|
||||
"SFP", TYPE_A, /* Store Floating Point +FP */
|
||||
"140", TYPE_A,
|
||||
"141", TYPE_A,
|
||||
"142", TYPE_A,
|
||||
"143", TYPE_A,
|
||||
"144", TYPE_A,
|
||||
"145", TYPE_A,
|
||||
"146", TYPE_A,
|
||||
"147", TYPE_A,
|
||||
"150", TYPE_A,
|
||||
"151", TYPE_A,
|
||||
"152", TYPE_A,
|
||||
"153", TYPE_A,
|
||||
"154", TYPE_A,
|
||||
"155", TYPE_A,
|
||||
"156", TYPE_A,
|
||||
"157", TYPE_A,
|
||||
"160", TYPE_A,
|
||||
"161", TYPE_A,
|
||||
"162", TYPE_A,
|
||||
"163", TYPE_A,
|
||||
"164", TYPE_A,
|
||||
"165", TYPE_A,
|
||||
"166", TYPE_A,
|
||||
"167", TYPE_A,
|
||||
"170", TYPE_A,
|
||||
"171", TYPE_A,
|
||||
"172", TYPE_A,
|
||||
"173", TYPE_A,
|
||||
"174", TYPE_A,
|
||||
"175", TYPE_A,
|
||||
"176", TYPE_A,
|
||||
"177", TYPE_A,
|
||||
};
|
||||
|
||||
char *type_d[] = { "BRN", "BVS", "BVSR", "BVC", "BVCR", "BCS", "BCC", "BVCI" };
|
||||
@@ -426,7 +424,7 @@ print_opcode(FILE * of, t_value val)
|
||||
int m;
|
||||
int n;
|
||||
t_opcode *tab;
|
||||
|
||||
|
||||
op = 0177 & (val >> 14);;
|
||||
x = 07 & (val >> 21);
|
||||
m = 03 & (val >> 12);
|
||||
@@ -496,7 +494,7 @@ fprint_sym(FILE * of, t_addr addr, t_value * val, UNIT * uptr, int32 sw)
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
int
|
||||
int
|
||||
find_opcode(char *op, int *val)
|
||||
{
|
||||
int i;
|
||||
@@ -513,10 +511,10 @@ find_opcode(char *op, int *val)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (op[i] == 0 && v <= 0177)
|
||||
if (op[i] == 0 && v <= 0177)
|
||||
return v;
|
||||
for(i = 0; i <= 0177; i++) {
|
||||
if (ops[i].name != '\0' && sim_strcasecmp(op, ops[i].name) == 0)
|
||||
if (ops[i].name != '\0' && sim_strcasecmp(op, ops[i].name) == 0)
|
||||
return i;
|
||||
}
|
||||
for(i = 0; i < 8; i++) {
|
||||
@@ -593,12 +591,12 @@ if (sw & SWMASK ('M')) {
|
||||
*val = (0177 & op) << 14;
|
||||
if (x >= 0)
|
||||
*val |= (07 & x) << 21;
|
||||
|
||||
|
||||
switch (ops[op].type) {
|
||||
case TYPE_A: /* OP x m/n or OP x /n */
|
||||
if (m > 0)
|
||||
*val |= (m & 03) << 12;
|
||||
if (*cptr == '/') {
|
||||
if (*cptr == '/') {
|
||||
cptr++;
|
||||
n = get_uint(cptr, 8, 07777, &r);
|
||||
if (r != SCPE_OK)
|
||||
@@ -610,7 +608,7 @@ if (sw & SWMASK ('M')) {
|
||||
if (m >= 0)
|
||||
return SCPE_ARG;
|
||||
*val |= (m & 03) << 12;
|
||||
if (*cptr == '/') {
|
||||
if (*cptr == '/') {
|
||||
cptr++;
|
||||
n = get_uint(cptr, 8, 077777, &r);
|
||||
if (r != SCPE_OK)
|
||||
@@ -621,7 +619,7 @@ if (sw & SWMASK ('M')) {
|
||||
case TYPE_C: /* OP x m/c+n or OP X /c+n */
|
||||
if (m > 0)
|
||||
*val |= (m & 03) << 12;
|
||||
if (*cptr == '/') {
|
||||
if (*cptr == '/') {
|
||||
cptr++;
|
||||
for (i = 0; i< 4; i++) {
|
||||
if (type_c[i] == *cptr) {
|
||||
@@ -629,7 +627,7 @@ if (sw & SWMASK ('M')) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (*cptr != '+')
|
||||
if (*cptr != '+')
|
||||
return SCPE_ARG;
|
||||
cptr++;
|
||||
n = get_uint(cptr, 8, 01777, &r);
|
||||
@@ -646,7 +644,7 @@ if (sw & SWMASK ('M')) {
|
||||
}
|
||||
if (m >= 0 || x >= 0)
|
||||
return SCPE_ARG;
|
||||
if (*cptr == '/') {
|
||||
if (*cptr == '/') {
|
||||
cptr++;
|
||||
n = get_uint(cptr, 8, 077777, &r);
|
||||
if (r != SCPE_OK)
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
* 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.
|
||||
@@ -162,7 +162,7 @@ void ptp_cmd(int dev, uint32 cmd, uint32 *resp) {
|
||||
|
||||
*resp = 0;
|
||||
/* Find the unit from dev */
|
||||
for (i = 0; i < NUM_DEVS_PTP; i++) {
|
||||
for (i = 0; i < ptp_dev.numunits; i++) {
|
||||
if (GET_UADDR(ptp_unit[i].flags) == dev) {
|
||||
uptr = &ptp_unit[i];
|
||||
break;
|
||||
@@ -183,7 +183,7 @@ void ptp_cmd(int dev, uint32 cmd, uint32 *resp) {
|
||||
cmd &= 077;
|
||||
switch(cmd & 070) {
|
||||
case 010: /* Command */
|
||||
if ((uptr->flags & UNIT_ATT) == 0)
|
||||
if ((uptr->flags & UNIT_ATT) == 0)
|
||||
break;
|
||||
if (uptr->CMD & BUSY) {
|
||||
*resp = 3;
|
||||
@@ -200,13 +200,13 @@ void ptp_cmd(int dev, uint32 cmd, uint32 *resp) {
|
||||
break;
|
||||
|
||||
case 020: if (cmd == 020) { /* Send Q */
|
||||
if ((uptr->flags & UNIT_ATT) == 0)
|
||||
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)
|
||||
if ((uptr->flags & UNIT_ATT) != 0)
|
||||
*resp = (uptr->STATUS & ERROR) | 1;
|
||||
uptr->STATUS = 0;
|
||||
chan_clr_done(GET_UADDR(uptr->flags));
|
||||
@@ -219,7 +219,7 @@ void ptp_cmd(int dev, uint32 cmd, uint32 *resp) {
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -238,7 +238,7 @@ void ptp_nsi_cmd(int dev, uint32 cmd) {
|
||||
UNIT *uptr = NULL;
|
||||
|
||||
/* Find the unit from dev */
|
||||
for (i = 0; i < NUM_DEVS_PTP; i++) {
|
||||
for (i = 0; i < ptp_dev.numunits; i++) {
|
||||
if (GET_UADDR(ptp_unit[i].flags) == dev) {
|
||||
uptr = &ptp_unit[i];
|
||||
break;
|
||||
@@ -296,7 +296,7 @@ void ptp_nsi_status(int dev, uint32 *resp) {
|
||||
|
||||
*resp = 0;
|
||||
/* Find the unit from dev */
|
||||
for (i = 0; i < NUM_DEVS_PTP; i++) {
|
||||
for (i = 0; i < ptp_dev.numunits; i++) {
|
||||
if (GET_UADDR(ptp_unit[i].flags) == dev) {
|
||||
uptr = &ptp_unit[i];
|
||||
break;
|
||||
@@ -373,7 +373,7 @@ t_stat ptp_svc (UNIT *uptr)
|
||||
if (uptr->CMD & DELTA_MODE) {
|
||||
uptr->CMD &= ~DELTA_MODE;
|
||||
data = ch;
|
||||
if (ch & 040)
|
||||
if (ch & 040)
|
||||
data |= 0174 ^ ((ch & 020) << 1);
|
||||
} else if (uptr->CMD & ALPHA_MODE) {
|
||||
data = ch & 017;
|
||||
@@ -391,7 +391,7 @@ t_stat ptp_svc (UNIT *uptr)
|
||||
case 0040: data |= 0140; break;
|
||||
case 0060: data |= 0160; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (data != 0) {
|
||||
@@ -402,7 +402,7 @@ t_stat ptp_svc (UNIT *uptr)
|
||||
ch = ch ^ (ch << 2);
|
||||
ch = ch ^ (ch << 1);
|
||||
data |= ch;
|
||||
}
|
||||
}
|
||||
fputc(data, uptr->fileref);
|
||||
uptr->pos = ftell(uptr->fileref);
|
||||
if (ferror (uptr->fileref)) {
|
||||
|
||||
@@ -93,7 +93,7 @@
|
||||
* 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.
|
||||
@@ -165,7 +165,7 @@ void ptr_cmd(int dev, uint32 cmd, uint32 *resp) {
|
||||
|
||||
*resp = 0;
|
||||
/* Find the unit from dev */
|
||||
for (i = 0; i < NUM_DEVS_PTR; i++) {
|
||||
for (i = 0; i < ptr_dev.numunits; i++) {
|
||||
if (GET_UADDR(ptr_unit[i].flags) == dev) {
|
||||
uptr = &ptr_unit[i];
|
||||
break;
|
||||
@@ -180,12 +180,12 @@ void ptr_cmd(int dev, uint32 cmd, uint32 *resp) {
|
||||
if (NSI_TYPE(uptr->flags))
|
||||
return;
|
||||
|
||||
if ((uptr->flags & UNIT_ATT) == 0)
|
||||
if ((uptr->flags & UNIT_ATT) == 0)
|
||||
return;
|
||||
cmd &= 077;
|
||||
switch(cmd & 070) {
|
||||
case 010: /* Command */
|
||||
if ((uptr->flags & UNIT_ATT) == 0)
|
||||
if ((uptr->flags & UNIT_ATT) == 0)
|
||||
break;
|
||||
if (uptr->CMD & BUSY) {
|
||||
*resp = 3;
|
||||
@@ -201,13 +201,13 @@ void ptr_cmd(int dev, uint32 cmd, uint32 *resp) {
|
||||
break;
|
||||
|
||||
case 020: if (cmd == 020) { /* Send Q */
|
||||
if ((uptr->flags & UNIT_ATT) != 0)
|
||||
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)
|
||||
if ((uptr->flags & UNIT_ATT) != 0)
|
||||
*resp = (uptr->STATUS & ERROR) | 1;
|
||||
uptr->STATUS = 0;
|
||||
chan_clr_done(GET_UADDR(uptr->flags));
|
||||
@@ -220,7 +220,7 @@ void ptr_cmd(int dev, uint32 cmd, uint32 *resp) {
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -240,7 +240,7 @@ void ptr_nsi_cmd(int dev, uint32 cmd) {
|
||||
UNIT *uptr = NULL;
|
||||
|
||||
/* Find the unit from dev */
|
||||
for (i = 0; i < NUM_DEVS_PTR; i++) {
|
||||
for (i = 0; i < ptr_dev.numunits; i++) {
|
||||
if (GET_UADDR(ptr_unit[i].flags) == dev) {
|
||||
uptr = &ptr_unit[i];
|
||||
break;
|
||||
@@ -276,7 +276,7 @@ void ptr_nsi_cmd(int dev, uint32 cmd) {
|
||||
uptr->CMD |= STOP_CHAR;
|
||||
if (cmd & 020)
|
||||
uptr->CMD |= BIN_MODE;
|
||||
if ((cmd & 040) == 0)
|
||||
if ((cmd & 040) == 0)
|
||||
uptr->CMD |= IGN_BLNK;
|
||||
uptr->CMD |= BUSY;
|
||||
uptr->STATUS = 0;
|
||||
@@ -300,7 +300,7 @@ void ptr_nsi_status(int dev, uint32 *resp) {
|
||||
|
||||
*resp = 0;
|
||||
/* Find the unit from dev */
|
||||
for (i = 0; i < NUM_DEVS_PTR; i++) {
|
||||
for (i = 0; i < ptr_dev.numunits; i++) {
|
||||
if (GET_UADDR(ptr_unit[i].flags) == dev) {
|
||||
uptr = &ptr_unit[i];
|
||||
break;
|
||||
@@ -352,7 +352,7 @@ t_stat ptr_svc (UNIT *uptr)
|
||||
if ((uptr->CMD & STOP_CHAR) != 0 && uptr->HOLD == 032)
|
||||
uptr->STATUS |= TERMINATE;
|
||||
}
|
||||
|
||||
|
||||
/* Read next charater */
|
||||
if ((uptr->flags & UNIT_ATT) == 0 ||
|
||||
feof(uptr->fileref) ||
|
||||
@@ -369,10 +369,10 @@ t_stat ptr_svc (UNIT *uptr)
|
||||
ch = data ^ (data >> 4);
|
||||
ch = ch ^ (ch >> 2);
|
||||
ch = ch ^ (ch >> 1);
|
||||
if (ch != 0)
|
||||
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 */
|
||||
@@ -423,7 +423,7 @@ t_stat ptr_svc (UNIT *uptr)
|
||||
break;
|
||||
}
|
||||
case 0100:
|
||||
if ((uptr->CMD & 1) == BETA_MODE)
|
||||
if ((uptr->CMD & 1) == BETA_MODE)
|
||||
shift = ALPHA_SHIFT;
|
||||
uptr->CMD |= ALPHA_MODE;
|
||||
ch = 040 | (data & 037);
|
||||
@@ -435,7 +435,7 @@ t_stat ptr_svc (UNIT *uptr)
|
||||
break;
|
||||
}
|
||||
case 0120:
|
||||
if ((uptr->CMD & 1) == ALPHA_MODE)
|
||||
if ((uptr->CMD & 1) == ALPHA_MODE)
|
||||
shift = BETA_SHIFT;
|
||||
uptr->CMD &= ~ALPHA_MODE;
|
||||
ch = 040 | (data & 037);
|
||||
@@ -498,7 +498,7 @@ ptr_boot(int32 unit_num, DEVICE * dptr)
|
||||
|
||||
M[64 + chan] = 0;
|
||||
M[256 + 4 * chan] = 0;
|
||||
M[257 + 4 * chan] = 020;
|
||||
M[257 + 4 * chan] = 0;
|
||||
loading = 1;
|
||||
uptr->CMD = BUSY|ALPHA_MODE|BIN_MODE|IGN_BLNK;
|
||||
sim_activate (uptr, uptr->wait);
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
#define TAPE_IRG 0200
|
||||
#define BCD_TM 017
|
||||
|
||||
|
||||
unsigned char buffer[TAPE_BUFFER_SIZE];
|
||||
char *xlat; /* Pointer to translate table */
|
||||
int eor = 0; /* Report eor */
|
||||
@@ -125,7 +125,7 @@ int read_tape(FILE *f, int *len) {
|
||||
*len = -1;
|
||||
return 1;
|
||||
}
|
||||
if (lastchar != 0xff)
|
||||
if (lastchar != 0xff)
|
||||
buffer[sz++] = lastchar;
|
||||
lastchar = 0xff;
|
||||
while(fread(&ch, sizeof(unsigned char), 1, f) == 1) {
|
||||
@@ -146,7 +146,7 @@ int read_tape(FILE *f, int *len) {
|
||||
} else {
|
||||
unsigned char xlen[4];
|
||||
int i;
|
||||
if (fread(&xlen, sizeof(unsigned char), 4, f) != 4)
|
||||
if (fread(&xlen, sizeof(unsigned char), 4, f) != 4)
|
||||
return 0;
|
||||
/* Convert to number */
|
||||
sz = xlen[0];
|
||||
@@ -269,27 +269,14 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
/* Process records of the file */
|
||||
while(read_tape(tape, &sz)) {
|
||||
if (sz == -2)
|
||||
if (sz == -2)
|
||||
break;
|
||||
if (sz == -1) {
|
||||
puts("*EOF*");
|
||||
write_mark(otape);
|
||||
} else {
|
||||
// p = buffer;
|
||||
// col = 0;
|
||||
// for(i = 0; i < sz; i++) {
|
||||
// char ch = *p++;
|
||||
// if (parity_table[ch & 077] == (ch & 0100))
|
||||
// col ++;
|
||||
// }
|
||||
// if (col == sz) {
|
||||
// p = buffer;
|
||||
// for(i = 0; i < sz; i++)
|
||||
// putchar(xlat[*p++ & 077]);
|
||||
// putchar('\n');
|
||||
// } else
|
||||
for (i = 0; i < sz; i+=3)
|
||||
printf("%08o ", (buffer[i] << 16) | (buffer[i+1] << 8) | buffer[i+2]);
|
||||
for (i = 0; i < sz; i+=3)
|
||||
printf("%08o ", (buffer[i] << 16) | (buffer[i+1] << 8) | buffer[i+2]);
|
||||
printf("\n");
|
||||
write_block(otape, sz, buffer);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user