From c4c8043215de114efa63ed3a0821b7233b0301bd Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Sun, 21 May 2017 21:47:30 -0700 Subject: [PATCH] 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 --- I1620/i1620_cpu.c | 76 +++++++++++++++++++++++++++++++++++++++------- I1620/i1620_defs.h | 15 +++++---- 2 files changed, 74 insertions(+), 17 deletions(-) diff --git a/I1620/i1620_cpu.c b/I1620/i1620_cpu.c index 458609c1..1ad0e410 100644 --- a/I1620/i1620_cpu.c +++ b/I1620/i1620_cpu.c @@ -26,6 +26,11 @@ This CPU module incorporates code and comments from the 1620 simulator by 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) 07-May-15 RMS Added missing TFL instruction (Tom McBride) 28-Mar-15 RMS Revised to use sim_printf @@ -120,6 +125,7 @@ typedef struct { uint8 M[MAXMEMSIZE] = { 0 }; /* main memory */ uint32 saved_PC = 0; /* saved PC */ +uint32 actual_PC = 0; /* actual PC at halt */ uint32 IR2 = 1; /* inst reg 2 */ uint32 PAR = 0; /* P 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_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_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_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[] = { { DRDATA (PC, saved_PC, 16), PV_LEFT }, + { DRDATA (APC, actual_PC, 16), PV_LEFT + REG_HRO }, { DRDATA (IR2, IR2, 16), PV_LEFT }, { DRDATA (PR1, PR1, 16), PV_LEFT }, { 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_DIV, IF_DIV, "DIV", "DIV", &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, 0, "no FP", "NOFP", NULL }, { IF_BIN, IF_BIN, "BIN", "BIN", &cpu_set_opt2 }, @@ -252,6 +262,8 @@ MTAB cpu_mod[] = { { UNIT_MSIZE, 0, NULL, "TABLE", &cpu_set_table }, { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY", &cpu_set_hist, &cpu_show_hist }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, NULL, "RELEASE", + &cpu_set_release, NULL }, { 0 } }; @@ -407,10 +419,12 @@ const uint8 k_valid_p[NUM_IO] = { 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] = { - -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, -1, -1, -1, -1, 0, -1, -1, -1, -1, /* 20 - 29 */ 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 }; +/* 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 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) idxe = idxb = 0; upd_ind (); /* update indicators */ -reason = 0; +reason = SCPE_OK; /* Main instruction fetch/decode loop */ -while (reason == 0) { /* loop until halted */ +while (reason == SCPE_OK) { /* loop until halted */ saved_PC = PC; /* commit prev instr */ 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]; } - PC = PC + INST_LEN; /* advance PC */ + PC = ADDR_A (PC, INST_LEN); /* advance PC */ switch (op) { /* case on op */ /* Transmit digit - P,Q are valid */ @@ -685,7 +705,7 @@ while (reason == 0) { /* loop until halted */ case OP_BNI: upd_ind (); /* update indicators */ 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 */ break; } @@ -1037,7 +1057,6 @@ while (reason == 0) { /* loop until halted */ /* Halt */ case OP_H: - saved_PC = PC; /* commit inst */ reason = STOP_HALT; /* stop */ break; @@ -1056,6 +1075,11 @@ while (reason == 0) { /* loop until 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 */ upd_ind (); return reason; @@ -1342,6 +1366,9 @@ return SCPE_OK; Reference Manual: "When the sum is zero, the sign of the P field 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) @@ -1358,6 +1385,9 @@ ind[IN_EZ] = 1; /* assume zero */ dst = M[d] & DIGIT; /* 1st digits */ 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? */ return STOP_INVDIG; if (comp) /* complement? */ @@ -1375,6 +1405,9 @@ do { if (cnt >= skp) /* get src flag */ src_f = M[s] & FLAG; 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? */ 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 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) @@ -1448,12 +1483,15 @@ do { src_f = M[s] & FLAG; /* get src flag */ 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? */ ind[IN_EZ] = 0; /* not equal */ 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 */ add_one_digit (dst, src, &cry); /* throw away result */ MM (d); /* decr dst addr */ @@ -2114,12 +2152,26 @@ if (pcq_r) else return SCPE_IERR; sim_brk_types = sim_brk_dflt = SWMASK ('E'); /* init breakpoints */ upd_ind (); /* update indicators */ -if (one_time) /* set default tables */ +if (one_time) { /* set default tables */ cpu_set_table (&cpu_unit, 1, NULL, NULL); + actual_PC = saved_PC = 0; /* sync PCs */ + } one_time = FALSE; 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 */ 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) { 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_OK; diff --git a/I1620/i1620_defs.h b/I1620/i1620_defs.h index 72faac28..b796c4a7 100644 --- a/I1620/i1620_defs.h +++ b/I1620/i1620_defs.h @@ -1,6 +1,6 @@ /* 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 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 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 22-May-10 RMS Added check for 64b definitions 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_MBREVEN 16 /* even 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_PRCHK 25 /* printer check */ #define IN_IXN 30 /* IX neither */ @@ -197,12 +199,13 @@ #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_IMM (1 << (UNIT_V_UF + 11)) /* immediate */ -#define UNIT_BCD (1 << (UNIT_V_UF + 12)) /* BCD coded */ -#define UNIT_MSIZE (1 << (UNIT_V_UF + 13)) /* fake flag */ -#define ALLOPT (IF_DIV + IF_IA + IF_EDT + IF_FP + IF_BIN + IF_IDX) -#define MI_OPT (IF_DIV + IF_IA + IF_EDT + IF_FP) +#define IF_RMOK (1 << (UNIT_V_UF + 12)) /* diag mode - force rm to 0 */ +#define UNIT_BCD (1 << (UNIT_V_UF + 13)) /* BCD coded */ +#define UNIT_MSIZE (1 << (UNIT_V_UF + 14)) /* fake flag */ +#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 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) /* Add status codes */