I1620: Update various CPU issues

- Changed to commit PC on certain stops
- Added SET CPU RELEASE command
- Undefined indicators don't throw an error (Dave Wise)
- Added Model I mode to allow record marks in adds (Dave Wise)
- Allowed undocumented indicator 8 (Dave Wise)
- Added option for Model I diagnostic mode (Dave Wise)

# Conflicts:
#	I1620/i1620_cpu.c
This commit is contained in:
Mark Pizzolato 2017-05-21 21:47:30 -07:00
parent d72ab3ce51
commit c4c8043215
2 changed files with 74 additions and 17 deletions

View file

@ -26,6 +26,11 @@
This CPU module incorporates code and comments from the 1620 simulator by This CPU module incorporates code and comments from the 1620 simulator by
Geoff Kuenning, with his permission. Geoff Kuenning, with his permission.
20-May-17 RMS Changed to commit PC on certain stops
Added SET CPU RELEASE command
Undefined indicators don't throw an error (Dave Wise)
19-May-17 RMS Added Model I mode to allow record marks in adds (Dave Wise)
18-May-17 RMS Allowed undocumented indicator 8 (Dave Wise)
13-Mar-17 RMS Added error test on device addr (COVERITY) 13-Mar-17 RMS Added error test on device addr (COVERITY)
07-May-15 RMS Added missing TFL instruction (Tom McBride) 07-May-15 RMS Added missing TFL instruction (Tom McBride)
28-Mar-15 RMS Revised to use sim_printf 28-Mar-15 RMS Revised to use sim_printf
@ -120,6 +125,7 @@ typedef struct {
uint8 M[MAXMEMSIZE] = { 0 }; /* main memory */ uint8 M[MAXMEMSIZE] = { 0 }; /* main memory */
uint32 saved_PC = 0; /* saved PC */ uint32 saved_PC = 0; /* saved PC */
uint32 actual_PC = 0; /* actual PC at halt */
uint32 IR2 = 1; /* inst reg 2 */ uint32 IR2 = 1; /* inst reg 2 */
uint32 PAR = 0; /* P address */ uint32 PAR = 0; /* P address */
uint32 QAR = 0; /* Q address */ uint32 QAR = 0; /* Q address */
@ -147,6 +153,7 @@ t_stat cpu_set_model (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat cpu_set_size (UNIT *uptr, int32 val, CONST char *cptr, void *desc); t_stat cpu_set_size (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat cpu_set_save (UNIT *uptr, int32 val, CONST char *cptr, void *desc); t_stat cpu_set_save (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat cpu_set_table (UNIT *uptr, int32 val, CONST char *cptr, void *desc); t_stat cpu_set_table (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat cpu_set_release (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat cpu_set_hist (UNIT *uptr, int32 val, CONST char *cptr, void *desc); t_stat cpu_set_hist (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, CONST void *desc); t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
@ -203,6 +210,7 @@ UNIT cpu_unit = { UDATA (NULL, UNIT_FIX+UNIT_BCD+MI_STD, MAXMEMSIZE) };
REG cpu_reg[] = { REG cpu_reg[] = {
{ DRDATA (PC, saved_PC, 16), PV_LEFT }, { DRDATA (PC, saved_PC, 16), PV_LEFT },
{ DRDATA (APC, actual_PC, 16), PV_LEFT + REG_HRO },
{ DRDATA (IR2, IR2, 16), PV_LEFT }, { DRDATA (IR2, IR2, 16), PV_LEFT },
{ DRDATA (PR1, PR1, 16), PV_LEFT }, { DRDATA (PR1, PR1, 16), PV_LEFT },
{ DRDATA (PAR, PAR, 16), PV_LEFT + REG_RO }, { DRDATA (PAR, PAR, 16), PV_LEFT + REG_RO },
@ -237,6 +245,8 @@ MTAB cpu_mod[] = {
{ IF_EDT, 0, "no EDT", "NOEDT", &cpu_set_opt1 }, { IF_EDT, 0, "no EDT", "NOEDT", &cpu_set_opt1 },
{ IF_DIV, IF_DIV, "DIV", "DIV", &cpu_set_opt1 }, { IF_DIV, IF_DIV, "DIV", "DIV", &cpu_set_opt1 },
{ IF_DIV, 0, "no DIV", "NODIV", &cpu_set_opt1 }, { IF_DIV, 0, "no DIV", "NODIV", &cpu_set_opt1 },
{ IF_RMOK, IF_RMOK, "RM allowed", "RMOK", &cpu_set_opt1 },
{ IF_RMOK, 0, "RM disallowed", "NORMOK", &cpu_set_opt1 },
{ IF_FP, IF_FP, "FP", "FP", NULL }, { IF_FP, IF_FP, "FP", "FP", NULL },
{ IF_FP, 0, "no FP", "NOFP", NULL }, { IF_FP, 0, "no FP", "NOFP", NULL },
{ IF_BIN, IF_BIN, "BIN", "BIN", &cpu_set_opt2 }, { IF_BIN, IF_BIN, "BIN", "BIN", &cpu_set_opt2 },
@ -252,6 +262,8 @@ MTAB cpu_mod[] = {
{ UNIT_MSIZE, 0, NULL, "TABLE", &cpu_set_table }, { UNIT_MSIZE, 0, NULL, "TABLE", &cpu_set_table },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY", { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY",
&cpu_set_hist, &cpu_show_hist }, &cpu_set_hist, &cpu_show_hist },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, NULL, "RELEASE",
&cpu_set_release, NULL },
{ 0 } { 0 }
}; };
@ -407,10 +419,12 @@ const uint8 k_valid_p[NUM_IO] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}; };
/* Indicator table: -1 = illegal, +1 = resets when tested */ /* Indicator table: -1 = undefined, +1 = resets when tested */
/* Indicator 8 is MAR CHECK, for maintenance use only */
/* Undefined indicators always read as 0 */
const int32 ind_table[NUM_IND] = { const int32 ind_table[NUM_IND] = {
-1, 0, 0, 0, 0, -1, 1, 1, -1, 1, /* 00 - 09 */ -1, 0, 0, 0, 0, -1, 1, 1, 0, 1, /* 00 - 09 */
-1, 0, 0, 0, 1, 1, 1, 1, -1, 0, /* 10 - 19 */ -1, 0, 0, 0, 1, 1, 1, 1, -1, 0, /* 10 - 19 */
-1, -1, -1, -1, -1, 0, -1, -1, -1, -1, /* 20 - 29 */ -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, /* 20 - 29 */
0, 0, 0, 1, 1, 0, 1, 1, 1, 0, /* 30 - 39 */ 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, /* 30 - 39 */
@ -469,6 +483,12 @@ const uint8 std_mul_table[MUL_TABLE_LEN] = {
5, 4, 4, 5, 3, 6, 2, 7, 1, 8 5, 4, 4, 5, 3, 6, 2, 7, 1, 8
}; };
/* Table of stop codes that commit PC before returning to SCP */
static t_stat commit_pc[] = {
STOP_HALT, SCPE_STOP, STOP_NOCD, SCPE_EOF, SCPE_IOERR, 0
};
#define BRANCH(x) PCQ_ENTRY; PC = (x) #define BRANCH(x) PCQ_ENTRY; PC = (x)
#define GET_IDXADDR(x) ((idxb? IDX_B: IDX_A) + ((x) * ADDR_LEN) + (ADDR_LEN - 1)) #define GET_IDXADDR(x) ((idxb? IDX_B: IDX_A) + ((x) * ADDR_LEN) + (ADDR_LEN - 1))
@ -486,11 +506,11 @@ if ((cpu_unit.flags & IF_IA) == 0)
if ((cpu_unit.flags & IF_IDX) == 0) if ((cpu_unit.flags & IF_IDX) == 0)
idxe = idxb = 0; idxe = idxb = 0;
upd_ind (); /* update indicators */ upd_ind (); /* update indicators */
reason = 0; reason = SCPE_OK;
/* Main instruction fetch/decode loop */ /* Main instruction fetch/decode loop */
while (reason == 0) { /* loop until halted */ while (reason == SCPE_OK) { /* loop until halted */
saved_PC = PC; /* commit prev instr */ saved_PC = PC; /* commit prev instr */
if (sim_interval <= 0) { /* check clock queue */ if (sim_interval <= 0) { /* check clock queue */
@ -554,7 +574,7 @@ while (reason == 0) { /* loop until halted */
hst[hst_p].inst[i] = M[(PC + i) % MEMSIZE]; hst[hst_p].inst[i] = M[(PC + i) % MEMSIZE];
} }
PC = PC + INST_LEN; /* advance PC */ PC = ADDR_A (PC, INST_LEN); /* advance PC */
switch (op) { /* case on op */ switch (op) { /* case on op */
/* Transmit digit - P,Q are valid */ /* Transmit digit - P,Q are valid */
@ -685,7 +705,7 @@ while (reason == 0) { /* loop until halted */
case OP_BNI: case OP_BNI:
upd_ind (); /* update indicators */ upd_ind (); /* update indicators */
t = get_2d (ADDR_A (saved_PC, I_BR)); /* get ind number */ t = get_2d (ADDR_A (saved_PC, I_BR)); /* get ind number */
if ((t < 0) || (ind_table[t] < 0)) { /* not valid? */ if (t < 0) { /* not valid? */
reason = STOP_INVIND; /* stop */ reason = STOP_INVIND; /* stop */
break; break;
} }
@ -1037,7 +1057,6 @@ while (reason == 0) { /* loop until halted */
/* Halt */ /* Halt */
case OP_H: case OP_H:
saved_PC = PC; /* commit inst */
reason = STOP_HALT; /* stop */ reason = STOP_HALT; /* stop */
break; break;
@ -1056,6 +1075,11 @@ while (reason == 0) { /* loop until halted */
/* Simulation halted */ /* Simulation halted */
for (i = 0; commit_pc[i] != 0; i++) { /* check stop code */
if (reason == commit_pc[i]) /* on list? */
saved_PC = PC; /* commit PC */
}
actual_PC = PC; /* save cur PC for RLS */
pcq_r->qptr = pcq_p; /* update pc q ptr */ pcq_r->qptr = pcq_p; /* update pc q ptr */
upd_ind (); upd_ind ();
return reason; return reason;
@ -1342,6 +1366,9 @@ return SCPE_OK;
Reference Manual: "When the sum is zero, the sign of the P field Reference Manual: "When the sum is zero, the sign of the P field
is retained." is retained."
Model 1 hack: If the Q field contains a record mark, it is treated
as 0 (Dave Wise; from schematics).
*/ */
t_stat add_field (uint32 d, uint32 s, t_bool sub, uint32 skp, int32 *sta) t_stat add_field (uint32 d, uint32 s, t_bool sub, uint32 skp, int32 *sta)
@ -1358,6 +1385,9 @@ ind[IN_EZ] = 1; /* assume zero */
dst = M[d] & DIGIT; /* 1st digits */ dst = M[d] & DIGIT; /* 1st digits */
src = M[s] & DIGIT; src = M[s] & DIGIT;
if ((src == REC_MARK) && /* Q record mark? */
((cpu_unit.flags & IF_RMOK) != 0)) /* Model I & enabled? */
src = 0; /* treat as 0 */
if (BAD_DIGIT (dst) || BAD_DIGIT (src)) /* bad digit? */ if (BAD_DIGIT (dst) || BAD_DIGIT (src)) /* bad digit? */
return STOP_INVDIG; return STOP_INVDIG;
if (comp) /* complement? */ if (comp) /* complement? */
@ -1375,6 +1405,9 @@ do {
if (cnt >= skp) /* get src flag */ if (cnt >= skp) /* get src flag */
src_f = M[s] & FLAG; src_f = M[s] & FLAG;
MM (s); /* decr src addr */ MM (s); /* decr src addr */
if ((src == REC_MARK) && /* Q record mark? */
((cpu_unit.flags & IF_RMOK) != 0)) /* Model I & enabled? */
src = 0; /* treat as 0 */
} }
if (BAD_DIGIT (dst) || BAD_DIGIT (src)) /* bad digit? */ if (BAD_DIGIT (dst) || BAD_DIGIT (src)) /* bad digit? */
return STOP_INVDIG; return STOP_INVDIG;
@ -1423,6 +1456,8 @@ return SCPE_OK;
In the unlike signs case, the compare is abandoned as soon as a non-zero In the unlike signs case, the compare is abandoned as soon as a non-zero
digit is seen; zeroes go through the normal flows. digit is seen; zeroes go through the normal flows.
See add for Model I hack in handling Q field record marks.
*/ */
t_stat cmp_field (uint32 d, uint32 s) t_stat cmp_field (uint32 d, uint32 s)
@ -1448,12 +1483,15 @@ do {
src_f = M[s] & FLAG; /* get src flag */ src_f = M[s] & FLAG; /* get src flag */
MM (s); /* decr src addr */ MM (s); /* decr src addr */
} }
if (BAD_DIGIT (dst) || BAD_DIGIT (src)) /* bad digit? */
return STOP_INVDIG;
if (unlike && ((dst | src) != 0)) { /* unlike signs, digit? */ if (unlike && ((dst | src) != 0)) { /* unlike signs, digit? */
ind[IN_EZ] = 0; /* not equal */ ind[IN_EZ] = 0; /* not equal */
return SCPE_OK; return SCPE_OK;
} }
if ((src == REC_MARK) && /* Q record mark? */
((cpu_unit.flags & IF_RMOK) != 0)) /* Model I & enabled? */
src = 0; /* treat as 0 */
if (BAD_DIGIT (dst) || BAD_DIGIT (src)) /* bad digit? */
return STOP_INVDIG;
src = (d != dsv)? 9 - src: 10 - src; /* complement */ src = (d != dsv)? 9 - src: 10 - src; /* complement */
add_one_digit (dst, src, &cry); /* throw away result */ add_one_digit (dst, src, &cry); /* throw away result */
MM (d); /* decr dst addr */ MM (d); /* decr dst addr */
@ -2114,12 +2152,26 @@ if (pcq_r)
else return SCPE_IERR; else return SCPE_IERR;
sim_brk_types = sim_brk_dflt = SWMASK ('E'); /* init breakpoints */ sim_brk_types = sim_brk_dflt = SWMASK ('E'); /* init breakpoints */
upd_ind (); /* update indicators */ upd_ind (); /* update indicators */
if (one_time) /* set default tables */ if (one_time) { /* set default tables */
cpu_set_table (&cpu_unit, 1, NULL, NULL); cpu_set_table (&cpu_unit, 1, NULL, NULL);
actual_PC = saved_PC = 0; /* sync PCs */
}
one_time = FALSE; one_time = FALSE;
return SCPE_OK; return SCPE_OK;
} }
/* Release routine */
t_stat cpu_set_release (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
if (actual_PC == ADDR_A (saved_PC, INST_LEN)) { /* one instr ahead? */
saved_PC = actual_PC; /* return */
sim_printf ("New PC = %05d\n", saved_PC);
}
else sim_printf ("PC unchanged\n");
return SCPE_OK;
}
/* Memory examine */ /* Memory examine */
t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
@ -2176,7 +2228,9 @@ return SCPE_OK;
t_stat cpu_set_opt1 (UNIT *uptr, int32 val, CONST char *cptr, void *desc) t_stat cpu_set_opt1 (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{ {
if (cpu_unit.flags & IF_MII) { if (cpu_unit.flags & IF_MII) {
sim_printf ("Feature is standard on 1620 Model 2\n"); if ((val & IF_RMOK) != 0)
sim_printf ("Feature is not available on 1620 Model 2\n");
else sim_printf ("Feature is standard on 1620 Model 2\n");
return SCPE_NOFNC; return SCPE_NOFNC;
} }
return SCPE_OK; return SCPE_OK;

View file

@ -1,6 +1,6 @@
/* i1620_defs.h: IBM 1620 simulator definitions /* i1620_defs.h: IBM 1620 simulator definitions
Copyright (c) 2002-2015, Robert M. Supnik Copyright (c) 2002-2017, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),
@ -27,6 +27,7 @@
I am grateful to Al Kossow, the Computer History Museum, and the IBM Corporate I am grateful to Al Kossow, the Computer History Museum, and the IBM Corporate
Archives for their help in gathering documentation about the IBM 1620. Archives for their help in gathering documentation about the IBM 1620.
19-May-17 RMS Added option for Model I diagnostic mode (Dave Wise)
05-Feb-15 TFM Added definitions for flagged RM, GM, NB 05-Feb-15 TFM Added definitions for flagged RM, GM, NB
22-May-10 RMS Added check for 64b definitions 22-May-10 RMS Added check for 64b definitions
18-Oct-02 RMS Fixed bug in ADDR_S macro (found by Hans Pufal) 18-Oct-02 RMS Fixed bug in ADDR_S macro (found by Hans Pufal)
@ -120,6 +121,7 @@
#define IN_EXPCHK 15 /* floating exponent check */ #define IN_EXPCHK 15 /* floating exponent check */
#define IN_MBREVEN 16 /* even parity check */ #define IN_MBREVEN 16 /* even parity check */
#define IN_MBRODD 17 /* odd parity check */ #define IN_MBRODD 17 /* odd parity check */
#define IN_MARCHK 18 /* MAR check - diag only */
#define IN_ANYCHK 19 /* any of read, write, even/odd */ #define IN_ANYCHK 19 /* any of read, write, even/odd */
#define IN_PRCHK 25 /* printer check */ #define IN_PRCHK 25 /* printer check */
#define IN_IXN 30 /* IX neither */ #define IN_IXN 30 /* IX neither */
@ -197,12 +199,13 @@
#define IF_4QA (1 << (UNIT_V_UF + 9)) /* 4 char Q addr */ #define IF_4QA (1 << (UNIT_V_UF + 9)) /* 4 char Q addr */
#define IF_NQX (1 << (UNIT_V_UF + 10)) /* no Q indexing */ #define IF_NQX (1 << (UNIT_V_UF + 10)) /* no Q indexing */
#define IF_IMM (1 << (UNIT_V_UF + 11)) /* immediate */ #define IF_IMM (1 << (UNIT_V_UF + 11)) /* immediate */
#define UNIT_BCD (1 << (UNIT_V_UF + 12)) /* BCD coded */ #define IF_RMOK (1 << (UNIT_V_UF + 12)) /* diag mode - force rm to 0 */
#define UNIT_MSIZE (1 << (UNIT_V_UF + 13)) /* fake flag */ #define UNIT_BCD (1 << (UNIT_V_UF + 13)) /* BCD coded */
#define ALLOPT (IF_DIV + IF_IA + IF_EDT + IF_FP + IF_BIN + IF_IDX) #define UNIT_MSIZE (1 << (UNIT_V_UF + 14)) /* fake flag */
#define MI_OPT (IF_DIV + IF_IA + IF_EDT + IF_FP) #define ALLOPT (IF_DIV + IF_IA + IF_EDT + IF_FP + IF_BIN + IF_IDX + IF_RMOK)
#define MI_OPT (IF_DIV + IF_IA + IF_EDT + IF_FP + IF_RMOK)
#define MI_STD (IF_DIV + IF_IA + IF_EDT) #define MI_STD (IF_DIV + IF_IA + IF_EDT)
#define MII_OPT (ALLOPT) #define MII_OPT (IF_DIV + IF_IA + IF_EDT + IF_FP + IF_BIN + IF_IDX)
#define MII_STD (IF_DIV + IF_IA + IF_EDT + IF_BIN + IF_IDX) #define MII_STD (IF_DIV + IF_IA + IF_EDT + IF_BIN + IF_IDX)
/* Add status codes */ /* Add status codes */