| 1 | /* pdp8_cpu.c: PDP-8 CPU simulator\r |
| 2 | \r |
| 3 | Copyright (c) 1993-2007, Robert M Supnik\r |
| 4 | \r |
| 5 | Permission is hereby granted, free of charge, to any person obtaining a\r |
| 6 | copy of this software and associated documentation files (the "Software"),\r |
| 7 | to deal in the Software without restriction, including without limitation\r |
| 8 | the rights to use, copy, modify, merge, publish, distribute, sublicense,\r |
| 9 | and/or sell copies of the Software, and to permit persons to whom the\r |
| 10 | Software is furnished to do so, subject to the following conditions:\r |
| 11 | \r |
| 12 | The above copyright notice and this permission notice shall be included in\r |
| 13 | all copies or substantial portions of the Software.\r |
| 14 | \r |
| 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r |
| 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r |
| 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r |
| 18 | ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r |
| 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r |
| 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r |
| 21 | \r |
| 22 | Except as contained in this notice, the name of Robert M Supnik shall not be\r |
| 23 | used in advertising or otherwise to promote the sale, use or other dealings\r |
| 24 | in this Software without prior written authorization from Robert M Supnik.\r |
| 25 | \r |
| 26 | cpu central processor\r |
| 27 | \r |
| 28 | 28-Apr-07 RMS Removed clock initialization\r |
| 29 | 30-Oct-06 RMS Added idle and infinite loop detection\r |
| 30 | 30-Sep-06 RMS Fixed SC value after DVI overflow (found by Don North)\r |
| 31 | 22-Sep-05 RMS Fixed declarations (from Sterling Garwood)\r |
| 32 | 16-Aug-05 RMS Fixed C++ declaration and cast problems\r |
| 33 | 06-Nov-04 RMS Added =n to SHOW HISTORY\r |
| 34 | 31-Dec-03 RMS Fixed bug in set_cpu_hist\r |
| 35 | 13-Oct-03 RMS Added instruction history\r |
| 36 | Added TSC8-75 support (from Bernhard Baehr)\r |
| 37 | 12-Mar-03 RMS Added logical name support\r |
| 38 | 04-Oct-02 RMS Revamped device dispatching, added device number support\r |
| 39 | 06-Jan-02 RMS Added device enable/disable routines\r |
| 40 | 30-Dec-01 RMS Added old PC queue\r |
| 41 | 16-Dec-01 RMS Fixed bugs in EAE\r |
| 42 | 07-Dec-01 RMS Revised to use new breakpoint package\r |
| 43 | 30-Nov-01 RMS Added RL8A, extended SET/SHOW support\r |
| 44 | 16-Sep-01 RMS Fixed bug in reset routine, added KL8A support\r |
| 45 | 10-Aug-01 RMS Removed register from declarations\r |
| 46 | 17-Jul-01 RMS Moved function prototype\r |
| 47 | 07-Jun-01 RMS Fixed bug in JMS to non-existent memory\r |
| 48 | 25-Apr-01 RMS Added device enable/disable support\r |
| 49 | 18-Mar-01 RMS Added DF32 support\r |
| 50 | 05-Mar-01 RMS Added clock calibration support\r |
| 51 | 15-Feb-01 RMS Added DECtape support\r |
| 52 | 14-Apr-99 RMS Changed t_addr to unsigned\r |
| 53 | \r |
| 54 | The register state for the PDP-8 is:\r |
| 55 | \r |
| 56 | AC<0:11> accumulator\r |
| 57 | MQ<0:11> multiplier-quotient\r |
| 58 | L link flag\r |
| 59 | PC<0:11> program counter\r |
| 60 | IF<0:2> instruction field\r |
| 61 | IB<0:2> instruction buffer\r |
| 62 | DF<0:2> data field\r |
| 63 | UF user flag\r |
| 64 | UB user buffer\r |
| 65 | SF<0:6> interrupt save field\r |
| 66 | \r |
| 67 | The PDP-8 has three instruction formats: memory reference, I/O transfer,\r |
| 68 | and operate. The memory reference format is:\r |
| 69 | \r |
| 70 | 0 1 2 3 4 5 6 7 8 9 10 11\r |
| 71 | +--+--+--+--+--+--+--+--+--+--+--+--+\r |
| 72 | | op |in|zr| page offset | memory reference\r |
| 73 | +--+--+--+--+--+--+--+--+--+--+--+--+\r |
| 74 | \r |
| 75 | <0:2> mnemonic action\r |
| 76 | \r |
| 77 | 000 AND AC = AC & M[MA]\r |
| 78 | 001 TAD L'AC = AC + M[MA]\r |
| 79 | 010 DCA M[MA] = AC, AC = 0\r |
| 80 | 011 ISZ M[MA] = M[MA] + 1, skip if M[MA] == 0\r |
| 81 | 100 JMS M[MA] = PC, PC = MA + 1\r |
| 82 | 101 JMP PC = MA\r |
| 83 | \r |
| 84 | <3:4> mode action\r |
| 85 | 00 page zero MA = IF'0'IR<5:11>\r |
| 86 | 01 current page MA = IF'PC<0:4>'IR<5:11>\r |
| 87 | 10 indirect page zero MA = xF'M[IF'0'IR<5:11>]\r |
| 88 | 11 indirect current page MA = xF'M[IF'PC<0:4>'IR<5:11>]\r |
| 89 | \r |
| 90 | where x is D for AND, TAD, ISZ, DCA, and I for JMS, JMP.\r |
| 91 | \r |
| 92 | Memory reference instructions can access an address space of 32K words.\r |
| 93 | The address space is divided into eight 4K word fields; each field is\r |
| 94 | divided into thirty-two 128 word pages. An instruction can directly\r |
| 95 | address, via its 7b offset, locations 0-127 on page zero or on the current\r |
| 96 | page. All 32k words can be accessed via indirect addressing and the\r |
| 97 | instruction and data field registers. If an indirect address is in\r |
| 98 | locations 0010-0017 of any field, the indirect address is incremented\r |
| 99 | and rewritten to memory before use.\r |
| 100 | \r |
| 101 | The I/O transfer format is as follows:\r |
| 102 | \r |
| 103 | 0 1 2 3 4 5 6 7 8 9 10 11\r |
| 104 | +--+--+--+--+--+--+--+--+--+--+--+--+\r |
| 105 | | op | device | pulse | I/O transfer\r |
| 106 | +--+--+--+--+--+--+--+--+--+--+--+--+\r |
| 107 | \r |
| 108 | The IO transfer instruction sends the the specified pulse to the\r |
| 109 | specified I/O device. The I/O device may take data from the AC,\r |
| 110 | return data to the AC, initiate or cancel operations, or skip on\r |
| 111 | status.\r |
| 112 | \r |
| 113 | The operate format is as follows:\r |
| 114 | \r |
| 115 | +--+--+--+--+--+--+--+--+--+--+--+--+\r |
| 116 | | 1| 1| 1| 0| | | | | | | | | operate group 1\r |
| 117 | +--+--+--+--+--+--+--+--+--+--+--+--+\r |
| 118 | | | | | | | | |\r |
| 119 | | | | | | | | +--- increment AC 3\r |
| 120 | | | | | | | +--- rotate 1 or 2 4\r |
| 121 | | | | | | +--- rotate left 4\r |
| 122 | | | | | +--- rotate right 4\r |
| 123 | | | | +--- complement L 2\r |
| 124 | | | +--- complement AC 2\r |
| 125 | | +--- clear L 1\r |
| 126 | +-- clear AC 1\r |
| 127 | \r |
| 128 | +--+--+--+--+--+--+--+--+--+--+--+--+\r |
| 129 | | 1| 1| 1| 1| | | | | | | | 0| operate group 2\r |
| 130 | +--+--+--+--+--+--+--+--+--+--+--+--+\r |
| 131 | | | | | | | |\r |
| 132 | | | | | | | +--- halt 3\r |
| 133 | | | | | | +--- or switch register 3\r |
| 134 | | | | | +--- reverse skip sense 1\r |
| 135 | | | | +--- skip on L != 0 1\r |
| 136 | | | +--- skip on AC == 0 1\r |
| 137 | | +--- skip on AC < 0 1\r |
| 138 | +-- clear AC 2\r |
| 139 | \r |
| 140 | +--+--+--+--+--+--+--+--+--+--+--+--+\r |
| 141 | | 1| 1| 1| 1| | | | | | | | 1| operate group 3\r |
| 142 | +--+--+--+--+--+--+--+--+--+--+--+--+\r |
| 143 | | | | | \______/\r |
| 144 | | | | | |\r |
| 145 | | | +--|-----+--- EAE command 3\r |
| 146 | | | +--- AC -> MQ, 0 -> AC 2\r |
| 147 | | +--- MQ v AC --> AC 2\r |
| 148 | +-- clear AC 1\r |
| 149 | \r |
| 150 | The operate instruction can be microprogrammed to perform operations\r |
| 151 | on the AC, MQ, and link.\r |
| 152 | \r |
| 153 | This routine is the instruction decode routine for the PDP-8.\r |
| 154 | It is called from the simulator control program to execute\r |
| 155 | instructions in simulated memory, starting at the simulated PC.\r |
| 156 | It runs until 'reason' is set non-zero.\r |
| 157 | \r |
| 158 | General notes:\r |
| 159 | \r |
| 160 | 1. Reasons to stop. The simulator can be stopped by:\r |
| 161 | \r |
| 162 | HALT instruction\r |
| 163 | breakpoint encountered\r |
| 164 | unimplemented instruction and stop_inst flag set\r |
| 165 | I/O error in I/O simulator\r |
| 166 | \r |
| 167 | 2. Interrupts. Interrupts are maintained by three parallel variables:\r |
| 168 | \r |
| 169 | dev_done device done flags\r |
| 170 | int_enable interrupt enable flags\r |
| 171 | int_req interrupt requests\r |
| 172 | \r |
| 173 | In addition, int_req contains the interrupt enable flag, the\r |
| 174 | CIF not pending flag, and the ION not pending flag. If all\r |
| 175 | three of these flags are set, and at least one interrupt request\r |
| 176 | is set, then an interrupt occurs.\r |
| 177 | \r |
| 178 | 3. Non-existent memory. On the PDP-8, reads to non-existent memory\r |
| 179 | return zero, and writes are ignored. In the simulator, the\r |
| 180 | largest possible memory is instantiated and initialized to zero.\r |
| 181 | Thus, only writes outside the current field (indirect writes) need\r |
| 182 | be checked against actual memory size.\r |
| 183 | \r |
| 184 | 3. Adding I/O devices. These modules must be modified:\r |
| 185 | \r |
| 186 | pdp8_defs.h add device number and interrupt definitions\r |
| 187 | pdp8_sys.c add sim_devices table entry\r |
| 188 | */\r |
| 189 | \r |
| 190 | #include "pdp8_defs.h"\r |
| 191 | \r |
| 192 | #define PCQ_SIZE 64 /* must be 2**n */\r |
| 193 | #define PCQ_MASK (PCQ_SIZE - 1)\r |
| 194 | #define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = MA\r |
| 195 | #define UNIT_V_NOEAE (UNIT_V_UF) /* EAE absent */\r |
| 196 | #define UNIT_NOEAE (1 << UNIT_V_NOEAE)\r |
| 197 | #define UNIT_V_MSIZE (UNIT_V_UF + 1) /* dummy mask */\r |
| 198 | #define UNIT_MSIZE (1 << UNIT_V_MSIZE)\r |
| 199 | #define OP_KSF 06031 /* for idle */\r |
| 200 | \r |
| 201 | #define HIST_PC 0x40000000\r |
| 202 | #define HIST_MIN 64\r |
| 203 | #define HIST_MAX 65536\r |
| 204 | \r |
| 205 | typedef struct {\r |
| 206 | int32 pc;\r |
| 207 | int32 ea;\r |
| 208 | int16 ir;\r |
| 209 | int16 opnd;\r |
| 210 | int16 lac;\r |
| 211 | int16 mq;\r |
| 212 | } InstHistory;\r |
| 213 | \r |
| 214 | uint16 M[MAXMEMSIZE] = { 0 }; /* main memory */\r |
| 215 | int32 saved_LAC = 0; /* saved L'AC */\r |
| 216 | int32 saved_MQ = 0; /* saved MQ */\r |
| 217 | int32 saved_PC = 0; /* saved IF'PC */\r |
| 218 | int32 saved_DF = 0; /* saved Data Field */\r |
| 219 | int32 IB = 0; /* Instruction Buffer */\r |
| 220 | int32 SF = 0; /* Save Field */\r |
| 221 | int32 emode = 0; /* EAE mode */\r |
| 222 | int32 gtf = 0; /* EAE gtf flag */\r |
| 223 | int32 SC = 0; /* EAE shift count */\r |
| 224 | int32 UB = 0; /* User mode Buffer */\r |
| 225 | int32 UF = 0; /* User mode Flag */\r |
| 226 | int32 OSR = 0; /* Switch Register */\r |
| 227 | int32 tsc_ir = 0; /* TSC8-75 IR */\r |
| 228 | int32 tsc_pc = 0; /* TSC8-75 PC */\r |
| 229 | int32 tsc_cdf = 0; /* TSC8-75 CDF flag */\r |
| 230 | int32 tsc_enb = 0; /* TSC8-75 enabled */\r |
| 231 | int16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */\r |
| 232 | int32 pcq_p = 0; /* PC queue ptr */\r |
| 233 | REG *pcq_r = NULL; /* PC queue reg ptr */\r |
| 234 | int32 dev_done = 0; /* dev done flags */\r |
| 235 | int32 int_enable = INT_INIT_ENABLE; /* intr enables */\r |
| 236 | int32 int_req = 0; /* intr requests */\r |
| 237 | int32 stop_inst = 0; /* trap on ill inst */\r |
| 238 | int32 (*dev_tab[DEV_MAX])(int32 IR, int32 dat); /* device dispatch */\r |
| 239 | int32 hst_p = 0; /* history pointer */\r |
| 240 | int32 hst_lnt = 0; /* history length */\r |
| 241 | InstHistory *hst = NULL; /* instruction history */\r |
| 242 | \r |
| 243 | extern int32 sim_interval;\r |
| 244 | extern int32 sim_int_char;\r |
| 245 | extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */\r |
| 246 | extern DEVICE *sim_devices[];\r |
| 247 | extern FILE *sim_log;\r |
| 248 | extern t_bool sim_idle_enab;\r |
| 249 | \r |
| 250 | t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);\r |
| 251 | t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);\r |
| 252 | t_stat cpu_reset (DEVICE *dptr);\r |
| 253 | t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);\r |
| 254 | t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc);\r |
| 255 | t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc);\r |
| 256 | t_bool build_dev_tab (void);\r |
| 257 | \r |
| 258 | /* CPU data structures\r |
| 259 | \r |
| 260 | cpu_dev CPU device descriptor\r |
| 261 | cpu_unit CPU unit descriptor\r |
| 262 | cpu_reg CPU register list\r |
| 263 | cpu_mod CPU modifier list\r |
| 264 | */\r |
| 265 | \r |
| 266 | UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, MAXMEMSIZE) };\r |
| 267 | \r |
| 268 | REG cpu_reg[] = {\r |
| 269 | { ORDATA (PC, saved_PC, 15) },\r |
| 270 | { ORDATA (AC, saved_LAC, 12) },\r |
| 271 | { FLDATA (L, saved_LAC, 12) },\r |
| 272 | { ORDATA (MQ, saved_MQ, 12) },\r |
| 273 | { ORDATA (SR, OSR, 12) },\r |
| 274 | { GRDATA (IF, saved_PC, 8, 3, 12) },\r |
| 275 | { GRDATA (DF, saved_DF, 8, 3, 12) },\r |
| 276 | { GRDATA (IB, IB, 8, 3, 12) },\r |
| 277 | { ORDATA (SF, SF, 7) },\r |
| 278 | { FLDATA (UB, UB, 0) },\r |
| 279 | { FLDATA (UF, UF, 0) },\r |
| 280 | { ORDATA (SC, SC, 5) },\r |
| 281 | { FLDATA (GTF, gtf, 0) },\r |
| 282 | { FLDATA (EMODE, emode, 0) },\r |
| 283 | { FLDATA (ION, int_req, INT_V_ION) },\r |
| 284 | { FLDATA (ION_DELAY, int_req, INT_V_NO_ION_PENDING) },\r |
| 285 | { FLDATA (CIF_DELAY, int_req, INT_V_NO_CIF_PENDING) },\r |
| 286 | { FLDATA (PWR_INT, int_req, INT_V_PWR) },\r |
| 287 | { FLDATA (UF_INT, int_req, INT_V_UF) },\r |
| 288 | { ORDATA (INT, int_req, INT_V_ION+1), REG_RO },\r |
| 289 | { ORDATA (DONE, dev_done, INT_V_DIRECT), REG_RO },\r |
| 290 | { ORDATA (ENABLE, int_enable, INT_V_DIRECT), REG_RO },\r |
| 291 | { BRDATA (PCQ, pcq, 8, 15, PCQ_SIZE), REG_RO+REG_CIRC },\r |
| 292 | { ORDATA (PCQP, pcq_p, 6), REG_HRO },\r |
| 293 | { FLDATA (STOP_INST, stop_inst, 0) },\r |
| 294 | { ORDATA (WRU, sim_int_char, 8) },\r |
| 295 | { NULL }\r |
| 296 | };\r |
| 297 | \r |
| 298 | MTAB cpu_mod[] = {\r |
| 299 | { UNIT_NOEAE, UNIT_NOEAE, "no EAE", "NOEAE", NULL },\r |
| 300 | { UNIT_NOEAE, 0, "EAE", "EAE", NULL },\r |
| 301 | { MTAB_XTD|MTAB_VDV, 0, "IDLE", "IDLE", &sim_set_idle, &sim_show_idle },\r |
| 302 | { MTAB_XTD|MTAB_VDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL },\r |
| 303 | { UNIT_MSIZE, 4096, NULL, "4K", &cpu_set_size },\r |
| 304 | { UNIT_MSIZE, 8192, NULL, "8K", &cpu_set_size },\r |
| 305 | { UNIT_MSIZE, 12288, NULL, "12K", &cpu_set_size },\r |
| 306 | { UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size },\r |
| 307 | { UNIT_MSIZE, 20480, NULL, "20K", &cpu_set_size },\r |
| 308 | { UNIT_MSIZE, 24576, NULL, "24K", &cpu_set_size },\r |
| 309 | { UNIT_MSIZE, 28672, NULL, "28K", &cpu_set_size },\r |
| 310 | { UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size },\r |
| 311 | { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY",\r |
| 312 | &cpu_set_hist, &cpu_show_hist },\r |
| 313 | { 0 }\r |
| 314 | };\r |
| 315 | \r |
| 316 | DEVICE cpu_dev = {\r |
| 317 | "CPU", &cpu_unit, cpu_reg, cpu_mod,\r |
| 318 | 1, 8, 15, 1, 8, 12,\r |
| 319 | &cpu_ex, &cpu_dep, &cpu_reset,\r |
| 320 | NULL, NULL, NULL,\r |
| 321 | NULL, 0\r |
| 322 | };\r |
| 323 | \r |
| 324 | t_stat sim_instr (void)\r |
| 325 | {\r |
| 326 | int32 IR, MB, IF, DF, LAC, MQ;\r |
| 327 | uint32 PC, MA;\r |
| 328 | int32 device, pulse, temp, iot_data;\r |
| 329 | t_stat reason;\r |
| 330 | \r |
| 331 | /* Restore register state */\r |
| 332 | \r |
| 333 | if (build_dev_tab ()) return SCPE_STOP; /* build dev_tab */\r |
| 334 | PC = saved_PC & 007777; /* load local copies */\r |
| 335 | IF = saved_PC & 070000;\r |
| 336 | DF = saved_DF & 070000;\r |
| 337 | LAC = saved_LAC & 017777;\r |
| 338 | MQ = saved_MQ & 07777;\r |
| 339 | int_req = INT_UPDATE;\r |
| 340 | reason = 0;\r |
| 341 | \r |
| 342 | /* Main instruction fetch/decode loop */\r |
| 343 | \r |
| 344 | while (reason == 0) { /* loop until halted */\r |
| 345 | \r |
| 346 | if (sim_interval <= 0) { /* check clock queue */\r |
| 347 | if (reason = sim_process_event ()) break;\r |
| 348 | }\r |
| 349 | \r |
| 350 | if (int_req > INT_PENDING) { /* interrupt? */\r |
| 351 | int_req = int_req & ~INT_ION; /* interrupts off */\r |
| 352 | SF = (UF << 6) | (IF >> 9) | (DF >> 12); /* form save field */\r |
| 353 | IF = IB = DF = UF = UB = 0; /* clear mem ext */\r |
| 354 | PCQ_ENTRY; /* save old PC */\r |
| 355 | M[0] = PC; /* save PC in 0 */\r |
| 356 | PC = 1; /* fetch next from 1 */\r |
| 357 | }\r |
| 358 | \r |
| 359 | MA = IF | PC; /* form PC */\r |
| 360 | if (sim_brk_summ && sim_brk_test (MA, SWMASK ('E'))) { /* breakpoint? */\r |
| 361 | reason = STOP_IBKPT; /* stop simulation */\r |
| 362 | break;\r |
| 363 | }\r |
| 364 | \r |
| 365 | IR = M[MA]; /* fetch instruction */\r |
| 366 | PC = (PC + 1) & 07777; /* increment PC */\r |
| 367 | int_req = int_req | INT_NO_ION_PENDING; /* clear ION delay */\r |
| 368 | sim_interval = sim_interval - 1;\r |
| 369 | \r |
| 370 | /* Instruction decoding.\r |
| 371 | \r |
| 372 | The opcode (IR<0:2>), indirect flag (IR<3>), and page flag (IR<4>)\r |
| 373 | are decoded together. This produces 32 decode points, four per\r |
| 374 | major opcode. For IOT, the extra decode points are not useful;\r |
| 375 | for OPR, only the group flag (IR<3>) is used.\r |
| 376 | \r |
| 377 | AND, TAD, ISZ, DCA calculate a full 15b effective address.\r |
| 378 | JMS, JMP calculate a 12b field-relative effective address.\r |
| 379 | \r |
| 380 | Autoindex calculations always occur within the same field as the\r |
| 381 | instruction fetch. The field must exist; otherwise, the instruction\r |
| 382 | fetched would be 0000, and indirect addressing could not occur.\r |
| 383 | \r |
| 384 | Note that MA contains IF'PC.\r |
| 385 | */\r |
| 386 | \r |
| 387 | if (hst_lnt) { /* history enabled? */\r |
| 388 | int32 ea;\r |
| 389 | \r |
| 390 | hst_p = (hst_p + 1); /* next entry */\r |
| 391 | if (hst_p >= hst_lnt) hst_p = 0;\r |
| 392 | hst[hst_p].pc = MA | HIST_PC; /* save PC, IR, LAC, MQ */\r |
| 393 | hst[hst_p].ir = IR;\r |
| 394 | hst[hst_p].lac = LAC;\r |
| 395 | hst[hst_p].mq = MQ;\r |
| 396 | if (IR < 06000) { /* mem ref? */\r |
| 397 | if (IR & 0200) ea = (MA & 077600) | (IR & 0177);\r |
| 398 | else ea = IF | (IR & 0177); /* direct addr */\r |
| 399 | if (IR & 0400) { /* indirect? */\r |
| 400 | if (IR < 04000) { /* mem operand? */\r |
| 401 | if ((ea & 07770) != 00010) ea = DF | M[ea];\r |
| 402 | else ea = DF | ((M[ea] + 1) & 07777);\r |
| 403 | }\r |
| 404 | else { /* no, jms/jmp */\r |
| 405 | if ((ea & 07770) != 00010) ea = IB | M[ea];\r |
| 406 | else ea = IB | ((M[ea] + 1) & 07777);\r |
| 407 | }\r |
| 408 | }\r |
| 409 | hst[hst_p].ea = ea; /* save eff addr */\r |
| 410 | hst[hst_p].opnd = M[ea]; /* save operand */\r |
| 411 | }\r |
| 412 | }\r |
| 413 | \r |
| 414 | switch ((IR >> 7) & 037) { /* decode IR<0:4> */\r |
| 415 | \r |
| 416 | /* Opcode 0, AND */\r |
| 417 | \r |
| 418 | case 000: /* AND, dir, zero */\r |
| 419 | MA = IF | (IR & 0177); /* dir addr, page zero */\r |
| 420 | LAC = LAC & (M[MA] | 010000);\r |
| 421 | break;\r |
| 422 | \r |
| 423 | case 001: /* AND, dir, curr */\r |
| 424 | MA = (MA & 077600) | (IR & 0177); /* dir addr, curr page */\r |
| 425 | LAC = LAC & (M[MA] | 010000);\r |
| 426 | break;\r |
| 427 | \r |
| 428 | case 002: /* AND, indir, zero */\r |
| 429 | MA = IF | (IR & 0177); /* dir addr, page zero */\r |
| 430 | if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */\r |
| 431 | else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */\r |
| 432 | LAC = LAC & (M[MA] | 010000);\r |
| 433 | break;\r |
| 434 | \r |
| 435 | case 003: /* AND, indir, curr */\r |
| 436 | MA = (MA & 077600) | (IR & 0177); /* dir addr, curr page */\r |
| 437 | if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */\r |
| 438 | else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */\r |
| 439 | LAC = LAC & (M[MA] | 010000);\r |
| 440 | break;\r |
| 441 | \r |
| 442 | /* Opcode 1, TAD */\r |
| 443 | \r |
| 444 | case 004: /* TAD, dir, zero */\r |
| 445 | MA = IF | (IR & 0177); /* dir addr, page zero */\r |
| 446 | LAC = (LAC + M[MA]) & 017777;\r |
| 447 | break;\r |
| 448 | \r |
| 449 | case 005: /* TAD, dir, curr */\r |
| 450 | MA = (MA & 077600) | (IR & 0177); /* dir addr, curr page */\r |
| 451 | LAC = (LAC + M[MA]) & 017777;\r |
| 452 | break;\r |
| 453 | \r |
| 454 | case 006: /* TAD, indir, zero */\r |
| 455 | MA = IF | (IR & 0177); /* dir addr, page zero */\r |
| 456 | if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */\r |
| 457 | else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */\r |
| 458 | LAC = (LAC + M[MA]) & 017777;\r |
| 459 | break;\r |
| 460 | \r |
| 461 | case 007: /* TAD, indir, curr */\r |
| 462 | MA = (MA & 077600) | (IR & 0177); /* dir addr, curr page */\r |
| 463 | if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */\r |
| 464 | else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */\r |
| 465 | LAC = (LAC + M[MA]) & 017777;\r |
| 466 | break;\r |
| 467 | \r |
| 468 | /* Opcode 2, ISZ */\r |
| 469 | \r |
| 470 | case 010: /* ISZ, dir, zero */\r |
| 471 | MA = IF | (IR & 0177); /* dir addr, page zero */\r |
| 472 | M[MA] = MB = (M[MA] + 1) & 07777; /* field must exist */\r |
| 473 | if (MB == 0) PC = (PC + 1) & 07777;\r |
| 474 | break;\r |
| 475 | \r |
| 476 | case 011: /* ISZ, dir, curr */\r |
| 477 | MA = (MA & 077600) | (IR & 0177); /* dir addr, curr page */\r |
| 478 | M[MA] = MB = (M[MA] + 1) & 07777; /* field must exist */\r |
| 479 | if (MB == 0) PC = (PC + 1) & 07777;\r |
| 480 | break;\r |
| 481 | \r |
| 482 | case 012: /* ISZ, indir, zero */\r |
| 483 | MA = IF | (IR & 0177); /* dir addr, page zero */\r |
| 484 | if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */\r |
| 485 | else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */\r |
| 486 | MB = (M[MA] + 1) & 07777;\r |
| 487 | if (MEM_ADDR_OK (MA)) M[MA] = MB;\r |
| 488 | if (MB == 0) PC = (PC + 1) & 07777;\r |
| 489 | break;\r |
| 490 | \r |
| 491 | case 013: /* ISZ, indir, curr */\r |
| 492 | MA = (MA & 077600) | (IR & 0177); /* dir addr, curr page */\r |
| 493 | if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */\r |
| 494 | else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */\r |
| 495 | MB = (M[MA] + 1) & 07777;\r |
| 496 | if (MEM_ADDR_OK (MA)) M[MA] = MB;\r |
| 497 | if (MB == 0) PC = (PC + 1) & 07777;\r |
| 498 | break;\r |
| 499 | \r |
| 500 | /* Opcode 3, DCA */\r |
| 501 | \r |
| 502 | case 014: /* DCA, dir, zero */\r |
| 503 | MA = IF | (IR & 0177); /* dir addr, page zero */\r |
| 504 | M[MA] = LAC & 07777;\r |
| 505 | LAC = LAC & 010000;\r |
| 506 | break;\r |
| 507 | \r |
| 508 | case 015: /* DCA, dir, curr */\r |
| 509 | MA = (MA & 077600) | (IR & 0177); /* dir addr, curr page */\r |
| 510 | M[MA] = LAC & 07777;\r |
| 511 | LAC = LAC & 010000;\r |
| 512 | break;\r |
| 513 | \r |
| 514 | case 016: /* DCA, indir, zero */\r |
| 515 | MA = IF | (IR & 0177); /* dir addr, page zero */\r |
| 516 | if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */\r |
| 517 | else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */\r |
| 518 | if (MEM_ADDR_OK (MA)) M[MA] = LAC & 07777;\r |
| 519 | LAC = LAC & 010000;\r |
| 520 | break;\r |
| 521 | \r |
| 522 | case 017: /* DCA, indir, curr */\r |
| 523 | MA = (MA & 077600) | (IR & 0177); /* dir addr, curr page */\r |
| 524 | if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */\r |
| 525 | else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */\r |
| 526 | if (MEM_ADDR_OK (MA)) M[MA] = LAC & 07777;\r |
| 527 | LAC = LAC & 010000;\r |
| 528 | break;\r |
| 529 | \r |
| 530 | /* Opcode 4, JMS. From Bernhard Baehr's description of the TSC8-75:\r |
| 531 | \r |
| 532 | (In user mode) the current JMS opcode is moved to the ERIOT register, the ECDF\r |
| 533 | flag is cleared. The address of the JMS instruction is loaded into the ERTB\r |
| 534 | register and the TSC8-75 I/O flag is raised. When the TSC8-75 is enabled, the\r |
| 535 | target addess of the JMS is loaded into PC, but nothing else (loading of IF, UF,\r |
| 536 | clearing the interrupt inhibit flag, storing of the return address in the first\r |
| 537 | word of the subroutine) happens. When the TSC8-75 is disabled, the JMS is performed\r |
| 538 | as usual. */\r |
| 539 | \r |
| 540 | case 020: /* JMS, dir, zero */\r |
| 541 | PCQ_ENTRY;\r |
| 542 | MA = IR & 0177; /* dir addr, page zero */\r |
| 543 | if (UF) { /* user mode? */\r |
| 544 | tsc_ir = IR; /* save instruction */\r |
| 545 | tsc_cdf = 0; /* clear flag */\r |
| 546 | }\r |
| 547 | if (UF && tsc_enb) { /* user mode, TSC enab? */\r |
| 548 | tsc_pc = (PC - 1) & 07777; /* save PC */\r |
| 549 | int_req = int_req | INT_TSC; /* request intr */\r |
| 550 | }\r |
| 551 | else { /* normal */\r |
| 552 | IF = IB; /* change IF */\r |
| 553 | UF = UB; /* change UF */\r |
| 554 | int_req = int_req | INT_NO_CIF_PENDING; /* clr intr inhibit */\r |
| 555 | MA = IF | MA;\r |
| 556 | if (MEM_ADDR_OK (MA)) M[MA] = PC;\r |
| 557 | }\r |
| 558 | PC = (MA + 1) & 07777;\r |
| 559 | break;\r |
| 560 | \r |
| 561 | case 021: /* JMS, dir, curr */\r |
| 562 | PCQ_ENTRY;\r |
| 563 | MA = (MA & 007600) | (IR & 0177); /* dir addr, curr page */\r |
| 564 | if (UF) { /* user mode? */\r |
| 565 | tsc_ir = IR; /* save instruction */\r |
| 566 | tsc_cdf = 0; /* clear flag */\r |
| 567 | }\r |
| 568 | if (UF && tsc_enb) { /* user mode, TSC enab? */\r |
| 569 | tsc_pc = (PC - 1) & 07777; /* save PC */\r |
| 570 | int_req = int_req | INT_TSC; /* request intr */\r |
| 571 | }\r |
| 572 | else { /* normal */\r |
| 573 | IF = IB; /* change IF */\r |
| 574 | UF = UB; /* change UF */\r |
| 575 | int_req = int_req | INT_NO_CIF_PENDING; /* clr intr inhibit */\r |
| 576 | MA = IF | MA;\r |
| 577 | if (MEM_ADDR_OK (MA)) M[MA] = PC;\r |
| 578 | }\r |
| 579 | PC = (MA + 1) & 07777;\r |
| 580 | break;\r |
| 581 | \r |
| 582 | case 022: /* JMS, indir, zero */\r |
| 583 | PCQ_ENTRY;\r |
| 584 | MA = IF | (IR & 0177); /* dir addr, page zero */\r |
| 585 | if ((MA & 07770) != 00010) MA = M[MA]; /* indirect; autoinc? */\r |
| 586 | else MA = (M[MA] = (M[MA] + 1) & 07777); /* incr before use */\r |
| 587 | if (UF) { /* user mode? */\r |
| 588 | tsc_ir = IR; /* save instruction */\r |
| 589 | tsc_cdf = 0; /* clear flag */\r |
| 590 | }\r |
| 591 | if (UF && tsc_enb) { /* user mode, TSC enab? */\r |
| 592 | tsc_pc = (PC - 1) & 07777; /* save PC */\r |
| 593 | int_req = int_req | INT_TSC; /* request intr */\r |
| 594 | }\r |
| 595 | else { /* normal */\r |
| 596 | IF = IB; /* change IF */\r |
| 597 | UF = UB; /* change UF */\r |
| 598 | int_req = int_req | INT_NO_CIF_PENDING; /* clr intr inhibit */\r |
| 599 | MA = IF | MA;\r |
| 600 | if (MEM_ADDR_OK (MA)) M[MA] = PC;\r |
| 601 | }\r |
| 602 | PC = (MA + 1) & 07777;\r |
| 603 | break;\r |
| 604 | \r |
| 605 | case 023: /* JMS, indir, curr */\r |
| 606 | PCQ_ENTRY;\r |
| 607 | MA = (MA & 077600) | (IR & 0177); /* dir addr, curr page */\r |
| 608 | if ((MA & 07770) != 00010) MA = M[MA]; /* indirect; autoinc? */\r |
| 609 | else MA = (M[MA] = (M[MA] + 1) & 07777); /* incr before use */\r |
| 610 | if (UF) { /* user mode? */\r |
| 611 | tsc_ir = IR; /* save instruction */\r |
| 612 | tsc_cdf = 0; /* clear flag */\r |
| 613 | }\r |
| 614 | if (UF && tsc_enb) { /* user mode, TSC enab? */\r |
| 615 | tsc_pc = (PC - 1) & 07777; /* save PC */\r |
| 616 | int_req = int_req | INT_TSC; /* request intr */\r |
| 617 | }\r |
| 618 | else { /* normal */\r |
| 619 | IF = IB; /* change IF */\r |
| 620 | UF = UB; /* change UF */\r |
| 621 | int_req = int_req | INT_NO_CIF_PENDING; /* clr intr inhibit */\r |
| 622 | MA = IF | MA;\r |
| 623 | if (MEM_ADDR_OK (MA)) M[MA] = PC;\r |
| 624 | }\r |
| 625 | PC = (MA + 1) & 07777;\r |
| 626 | break;\r |
| 627 | \r |
| 628 | /* Opcode 5, JMP. From Bernhard Baehr's description of the TSC8-75:\r |
| 629 | \r |
| 630 | (In user mode) the current JMP opcode is moved to the ERIOT register, the ECDF\r |
| 631 | flag is cleared. The address of the JMP instruction is loaded into the ERTB\r |
| 632 | register and the TSC8-75 I/O flag is raised. Then the JMP is performed as usual\r |
| 633 | (including the setting of IF, UF and clearing the interrupt inhibit flag). */\r |
| 634 | \r |
| 635 | \r |
| 636 | case 024: /* JMP, dir, zero */\r |
| 637 | PCQ_ENTRY;\r |
| 638 | MA = IR & 0177; /* dir addr, page zero */\r |
| 639 | if (UF) { /* user mode? */\r |
| 640 | tsc_ir = IR; /* save instruction */\r |
| 641 | tsc_cdf = 0; /* clear flag */\r |
| 642 | if (tsc_enb) { /* TSC8 enabled? */\r |
| 643 | tsc_pc = (PC - 1) & 07777; /* save PC */\r |
| 644 | int_req = int_req | INT_TSC; /* request intr */\r |
| 645 | }\r |
| 646 | }\r |
| 647 | IF = IB; /* change IF */\r |
| 648 | UF = UB; /* change UF */\r |
| 649 | int_req = int_req | INT_NO_CIF_PENDING; /* clr intr inhibit */\r |
| 650 | PC = MA;\r |
| 651 | break;\r |
| 652 | \r |
| 653 | /* If JMP direct, also check for idle (KSF/JMP *-1) and infinite loop */\r |
| 654 | \r |
| 655 | case 025: /* JMP, dir, curr */\r |
| 656 | PCQ_ENTRY;\r |
| 657 | MA = (MA & 007600) | (IR & 0177); /* dir addr, curr page */\r |
| 658 | if (UF) { /* user mode? */\r |
| 659 | tsc_ir = IR; /* save instruction */\r |
| 660 | tsc_cdf = 0; /* clear flag */\r |
| 661 | if (tsc_enb) { /* TSC8 enabled? */\r |
| 662 | tsc_pc = (PC - 1) & 07777; /* save PC */\r |
| 663 | int_req = int_req | INT_TSC; /* request intr */\r |
| 664 | }\r |
| 665 | }\r |
| 666 | if (sim_idle_enab && /* idling enabled? */\r |
| 667 | (IF == IB)) { /* to same bank? */\r |
| 668 | if (MA == ((PC - 2) & 07777)) { /* 1) JMP *-1? */\r |
| 669 | if (!(int_req & (INT_ION|INT_TTI)) && /* iof, TTI flag off? */\r |
| 670 | (M[IB|((PC - 2) & 07777)] == OP_KSF)) /* next is KSF? */\r |
| 671 | sim_idle (TMR_CLK, FALSE); /* we're idle */\r |
| 672 | } /* end JMP *-1 */\r |
| 673 | else if (MA == ((PC - 1) & 07777)) { /* 2) JMP *? */\r |
| 674 | if (!(int_req & INT_ION)) /* iof? */\r |
| 675 | reason = STOP_LOOP; /* then infinite loop */\r |
| 676 | else if (!(int_req & INT_ALL)) /* ion, not intr? */\r |
| 677 | sim_idle (TMR_CLK, FALSE); /* we're idle */\r |
| 678 | } /* end JMP */\r |
| 679 | } /* end idle enabled */\r |
| 680 | IF = IB; /* change IF */\r |
| 681 | UF = UB; /* change UF */\r |
| 682 | int_req = int_req | INT_NO_CIF_PENDING; /* clr intr inhibit */\r |
| 683 | PC = MA;\r |
| 684 | break;\r |
| 685 | \r |
| 686 | case 026: /* JMP, indir, zero */\r |
| 687 | PCQ_ENTRY;\r |
| 688 | MA = IF | (IR & 0177); /* dir addr, page zero */\r |
| 689 | if ((MA & 07770) != 00010) MA = M[MA]; /* indirect; autoinc? */\r |
| 690 | else MA = (M[MA] = (M[MA] + 1) & 07777); /* incr before use */\r |
| 691 | if (UF) { /* user mode? */\r |
| 692 | tsc_ir = IR; /* save instruction */\r |
| 693 | tsc_cdf = 0; /* clear flag */\r |
| 694 | if (tsc_enb) { /* TSC8 enabled? */\r |
| 695 | tsc_pc = (PC - 1) & 07777; /* save PC */\r |
| 696 | int_req = int_req | INT_TSC; /* request intr */\r |
| 697 | }\r |
| 698 | }\r |
| 699 | IF = IB; /* change IF */\r |
| 700 | UF = UB; /* change UF */\r |
| 701 | int_req = int_req | INT_NO_CIF_PENDING; /* clr intr inhibit */\r |
| 702 | PC = MA;\r |
| 703 | break;\r |
| 704 | \r |
| 705 | case 027: /* JMP, indir, curr */\r |
| 706 | PCQ_ENTRY;\r |
| 707 | MA = (MA & 077600) | (IR & 0177); /* dir addr, curr page */\r |
| 708 | if ((MA & 07770) != 00010) MA = M[MA]; /* indirect; autoinc? */\r |
| 709 | else MA = (M[MA] = (M[MA] + 1) & 07777); /* incr before use */\r |
| 710 | if (UF) { /* user mode? */\r |
| 711 | tsc_ir = IR; /* save instruction */\r |
| 712 | tsc_cdf = 0; /* clear flag */\r |
| 713 | if (tsc_enb) { /* TSC8 enabled? */\r |
| 714 | tsc_pc = (PC - 1) & 07777; /* save PC */\r |
| 715 | int_req = int_req | INT_TSC; /* request intr */\r |
| 716 | }\r |
| 717 | }\r |
| 718 | IF = IB; /* change IF */\r |
| 719 | UF = UB; /* change UF */\r |
| 720 | int_req = int_req | INT_NO_CIF_PENDING; /* clr intr inhibit */\r |
| 721 | PC = MA;\r |
| 722 | break;\r |
| 723 | \r |
| 724 | /* Opcode 7, OPR group 1 */\r |
| 725 | \r |
| 726 | case 034:case 035: /* OPR, group 1 */\r |
| 727 | switch ((IR >> 4) & 017) { /* decode IR<4:7> */\r |
| 728 | case 0: /* nop */\r |
| 729 | break;\r |
| 730 | case 1: /* CML */\r |
| 731 | LAC = LAC ^ 010000;\r |
| 732 | break;\r |
| 733 | case 2: /* CMA */\r |
| 734 | LAC = LAC ^ 07777;\r |
| 735 | break;\r |
| 736 | case 3: /* CMA CML */\r |
| 737 | LAC = LAC ^ 017777;\r |
| 738 | break;\r |
| 739 | case 4: /* CLL */\r |
| 740 | LAC = LAC & 07777;\r |
| 741 | break;\r |
| 742 | case 5: /* CLL CML = STL */\r |
| 743 | LAC = LAC | 010000;\r |
| 744 | break;\r |
| 745 | case 6: /* CLL CMA */\r |
| 746 | LAC = (LAC ^ 07777) & 07777;\r |
| 747 | break;\r |
| 748 | case 7: /* CLL CMA CML */\r |
| 749 | LAC = (LAC ^ 07777) | 010000;\r |
| 750 | break;\r |
| 751 | case 010: /* CLA */\r |
| 752 | LAC = LAC & 010000;\r |
| 753 | break;\r |
| 754 | case 011: /* CLA CML */\r |
| 755 | LAC = (LAC & 010000) ^ 010000;\r |
| 756 | break;\r |
| 757 | case 012: /* CLA CMA = STA */\r |
| 758 | LAC = LAC | 07777;\r |
| 759 | break;\r |
| 760 | case 013: /* CLA CMA CML */\r |
| 761 | LAC = (LAC | 07777) ^ 010000;\r |
| 762 | break;\r |
| 763 | case 014: /* CLA CLL */\r |
| 764 | LAC = 0;\r |
| 765 | break;\r |
| 766 | case 015: /* CLA CLL CML */\r |
| 767 | LAC = 010000;\r |
| 768 | break;\r |
| 769 | case 016: /* CLA CLL CMA */\r |
| 770 | LAC = 07777;\r |
| 771 | break;\r |
| 772 | case 017: /* CLA CLL CMA CML */\r |
| 773 | LAC = 017777;\r |
| 774 | break;\r |
| 775 | } /* end switch opers */\r |
| 776 | \r |
| 777 | if (IR & 01) LAC = (LAC + 1) & 017777; /* IAC */\r |
| 778 | switch ((IR >> 1) & 07) { /* decode IR<8:10> */\r |
| 779 | case 0: /* nop */\r |
| 780 | break;\r |
| 781 | case 1: /* BSW */\r |
| 782 | LAC = (LAC & 010000) | ((LAC >> 6) & 077) | ((LAC & 077) << 6);\r |
| 783 | break;\r |
| 784 | case 2: /* RAL */\r |
| 785 | LAC = ((LAC << 1) | (LAC >> 12)) & 017777;\r |
| 786 | break;\r |
| 787 | case 3: /* RTL */\r |
| 788 | LAC = ((LAC << 2) | (LAC >> 11)) & 017777;\r |
| 789 | break;\r |
| 790 | case 4: /* RAR */\r |
| 791 | LAC = ((LAC >> 1) | (LAC << 12)) & 017777;\r |
| 792 | break;\r |
| 793 | case 5: /* RTR */\r |
| 794 | LAC = ((LAC >> 2) | (LAC << 11)) & 017777;\r |
| 795 | break;\r |
| 796 | case 6: /* RAL RAR - undef */\r |
| 797 | LAC = LAC & (IR | 010000); /* uses AND path */\r |
| 798 | break;\r |
| 799 | case 7: /* RTL RTR - undef */\r |
| 800 | LAC = (LAC & 010000) | (MA & 07600) | (IR & 0177);\r |
| 801 | break; /* uses address path */\r |
| 802 | } /* end switch shifts */\r |
| 803 | break; /* end group 1 */\r |
| 804 | \r |
| 805 | /* OPR group 2. From Bernhard Baehr's description of the TSC8-75:\r |
| 806 | \r |
| 807 | (In user mode) HLT (7402), OSR (7404) and microprogrammed combinations with\r |
| 808 | HLT and OSR: Additional to raising a user mode interrupt, the current OPR\r |
| 809 | opcode is moved to the ERIOT register and the ECDF flag is cleared. */\r |
| 810 | \r |
| 811 | case 036:case 037: /* OPR, groups 2, 3 */\r |
| 812 | if ((IR & 01) == 0) { /* group 2 */\r |
| 813 | switch ((IR >> 3) & 017) { /* decode IR<6:8> */\r |
| 814 | case 0: /* nop */\r |
| 815 | break;\r |
| 816 | case 1: /* SKP */\r |
| 817 | PC = (PC + 1) & 07777;\r |
| 818 | break;\r |
| 819 | case 2: /* SNL */\r |
| 820 | if (LAC >= 010000) PC = (PC + 1) & 07777;\r |
| 821 | break;\r |
| 822 | case 3: /* SZL */\r |
| 823 | if (LAC < 010000) PC = (PC + 1) & 07777;\r |
| 824 | break;\r |
| 825 | case 4: /* SZA */\r |
| 826 | if ((LAC & 07777) == 0) PC = (PC + 1) & 07777;\r |
| 827 | break;\r |
| 828 | case 5: /* SNA */\r |
| 829 | if ((LAC & 07777) != 0) PC = (PC + 1) & 07777;\r |
| 830 | break;\r |
| 831 | case 6: /* SZA | SNL */\r |
| 832 | if ((LAC == 0) || (LAC >= 010000))\r |
| 833 | PC = (PC + 1) & 07777;\r |
| 834 | break;\r |
| 835 | case 7: /* SNA & SZL */\r |
| 836 | if ((LAC != 0) && (LAC < 010000)) PC = (PC + 1) & 07777;\r |
| 837 | break;\r |
| 838 | case 010: /* SMA */\r |
| 839 | if ((LAC & 04000) != 0) PC = (PC + 1) & 07777;\r |
| 840 | break;\r |
| 841 | case 011: /* SPA */\r |
| 842 | if ((LAC & 04000) == 0) PC = (PC + 1) & 07777;\r |
| 843 | break;\r |
| 844 | case 012: /* SMA | SNL */\r |
| 845 | if (LAC >= 04000) PC = (PC + 1) & 07777;\r |
| 846 | break;\r |
| 847 | case 013: /* SPA & SZL */\r |
| 848 | if (LAC < 04000) PC = (PC + 1) & 07777;\r |
| 849 | break;\r |
| 850 | case 014: /* SMA | SZA */\r |
| 851 | if (((LAC & 04000) != 0) || ((LAC & 07777) == 0))\r |
| 852 | PC = (PC + 1) & 07777;\r |
| 853 | break;\r |
| 854 | case 015: /* SPA & SNA */\r |
| 855 | if (((LAC & 04000) == 0) && ((LAC & 07777) != 0))\r |
| 856 | PC = (PC + 1) & 07777;\r |
| 857 | break;\r |
| 858 | case 016: /* SMA | SZA | SNL */\r |
| 859 | if ((LAC >= 04000) || (LAC == 0)) PC = (PC + 1) & 07777;\r |
| 860 | break;\r |
| 861 | case 017: /* SPA & SNA & SZL */\r |
| 862 | if ((LAC < 04000) && (LAC != 0)) PC = (PC + 1) & 07777;\r |
| 863 | break;\r |
| 864 | } /* end switch skips */\r |
| 865 | if (IR & 0200) LAC = LAC & 010000; /* CLA */\r |
| 866 | if ((IR & 06) && UF) { /* user mode? */\r |
| 867 | int_req = int_req | INT_UF; /* request intr */\r |
| 868 | tsc_ir = IR; /* save instruction */\r |
| 869 | tsc_cdf = 0; /* clear flag */\r |
| 870 | }\r |
| 871 | else {\r |
| 872 | if (IR & 04) LAC = LAC | OSR; /* OSR */\r |
| 873 | if (IR & 02) reason = STOP_HALT; /* HLT */\r |
| 874 | }\r |
| 875 | break;\r |
| 876 | } /* end if group 2 */\r |
| 877 | \r |
| 878 | /* OPR group 3 standard\r |
| 879 | \r |
| 880 | MQA!MQL exchanges AC and MQ, as follows:\r |
| 881 | \r |
| 882 | temp = MQ;\r |
| 883 | MQ = LAC & 07777;\r |
| 884 | LAC = LAC & 010000 | temp;\r |
| 885 | */\r |
| 886 | \r |
| 887 | temp = MQ; /* group 3 */\r |
| 888 | if (IR & 0200) LAC = LAC & 010000; /* CLA */\r |
| 889 | if (IR & 0020) { /* MQL */\r |
| 890 | MQ = LAC & 07777;\r |
| 891 | LAC = LAC & 010000;\r |
| 892 | }\r |
| 893 | if (IR & 0100) LAC = LAC | temp; /* MQA */\r |
| 894 | if ((IR & 0056) && (cpu_unit.flags & UNIT_NOEAE)) {\r |
| 895 | reason = stop_inst; /* EAE not present */\r |
| 896 | break;\r |
| 897 | }\r |
| 898 | \r |
| 899 | /* OPR group 3 EAE\r |
| 900 | \r |
| 901 | The EAE operates in two modes:\r |
| 902 | \r |
| 903 | Mode A, PDP-8/I compatible\r |
| 904 | Mode B, extended capability\r |
| 905 | \r |
| 906 | Mode B provides eight additional subfunctions; in addition, some\r |
| 907 | of the Mode A functions operate differently in Mode B.\r |
| 908 | \r |
| 909 | The mode switch instructions are decoded explicitly and cannot be\r |
| 910 | microprogrammed with other EAE functions (SWAB performs an MQL as\r |
| 911 | part of standard group 3 decoding). If mode switching is decoded,\r |
| 912 | all other EAE timing is suppressed.\r |
| 913 | */\r |
| 914 | \r |
| 915 | if (IR == 07431) { /* SWAB */\r |
| 916 | emode = 1; /* set mode flag */\r |
| 917 | break;\r |
| 918 | }\r |
| 919 | if (IR == 07447) { /* SWBA */\r |
| 920 | emode = gtf = 0; /* clear mode, gtf */\r |
| 921 | break;\r |
| 922 | }\r |
| 923 | \r |
| 924 | /* If not switching modes, the EAE operation is determined by the mode\r |
| 925 | and IR<6,8:10>:\r |
| 926 | \r |
| 927 | <6:10> mode A mode B comments\r |
| 928 | \r |
| 929 | 0x000 NOP NOP\r |
| 930 | 0x001 SCL ACS\r |
| 931 | 0x010 MUY MUY if mode B, next = address\r |
| 932 | 0x011 DVI DVI if mode B, next = address\r |
| 933 | 0x100 NMI NMI if mode B, clear AC if\r |
| 934 | result = 4000'0000\r |
| 935 | 0x101 SHL SHL if mode A, extra shift\r |
| 936 | 0x110 ASR ASR if mode A, extra shift\r |
| 937 | 0x111 LSR LSR if mode A, extra shift\r |
| 938 | 1x000 SCA SCA\r |
| 939 | 1x001 SCA + SCL DAD\r |
| 940 | 1x010 SCA + MUY DST\r |
| 941 | 1x011 SCA + DVI SWBA NOP if not detected earlier\r |
| 942 | 1x100 SCA + NMI DPSZ \r |
| 943 | 1x101 SCA + SHL DPIC must be combined with MQA!MQL\r |
| 944 | 1x110 SCA + ASR DCM must be combined with MQA!MQL\r |
| 945 | 1x111 SCA + LSR SAM\r |
| 946 | \r |
| 947 | EAE instructions which fetch memory operands use the CPU's DEFER\r |
| 948 | state to read the first word; if the address operand is in locations\r |
| 949 | x0010 - x0017, it is autoincremented.\r |
| 950 | */\r |
| 951 | \r |
| 952 | if (emode == 0) gtf = 0; /* mode A? clr gtf */\r |
| 953 | switch ((IR >> 1) & 027) { /* decode IR<6,8:10> */\r |
| 954 | \r |
| 955 | case 020: /* mode A, B: SCA */\r |
| 956 | LAC = LAC | SC;\r |
| 957 | break;\r |
| 958 | case 000: /* mode A, B: NOP */\r |
| 959 | break;\r |
| 960 | \r |
| 961 | case 021: /* mode B: DAD */\r |
| 962 | if (emode) {\r |
| 963 | MA = IF | PC;\r |
| 964 | if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */\r |
| 965 | else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */\r |
| 966 | MQ = MQ + M[MA];\r |
| 967 | MA = DF | ((MA + 1) & 07777);\r |
| 968 | LAC = (LAC & 07777) + M[MA] + (MQ >> 12);\r |
| 969 | MQ = MQ & 07777;\r |
| 970 | PC = (PC + 1) & 07777;\r |
| 971 | break;\r |
| 972 | }\r |
| 973 | LAC = LAC | SC; /* mode A: SCA then */\r |
| 974 | case 001: /* mode B: ACS */\r |
| 975 | if (emode) {\r |
| 976 | SC = LAC & 037;\r |
| 977 | LAC = LAC & 010000;\r |
| 978 | }\r |
| 979 | else { /* mode A: SCL */\r |
| 980 | SC = (~M[IF | PC]) & 037;\r |
| 981 | PC = (PC + 1) & 07777;\r |
| 982 | }\r |
| 983 | break;\r |
| 984 | \r |
| 985 | case 022: /* mode B: DST */\r |
| 986 | if (emode) {\r |
| 987 | MA = IF | PC;\r |
| 988 | if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */\r |
| 989 | else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */\r |
| 990 | if (MEM_ADDR_OK (MA)) M[MA] = MQ & 07777;\r |
| 991 | MA = DF | ((MA + 1) & 07777);\r |
| 992 | if (MEM_ADDR_OK (MA)) M[MA] = LAC & 07777;\r |
| 993 | PC = (PC + 1) & 07777;\r |
| 994 | break;\r |
| 995 | }\r |
| 996 | LAC = LAC | SC; /* mode A: SCA then */\r |
| 997 | case 002: /* MUY */\r |
| 998 | MA = IF | PC;\r |
| 999 | if (emode) { /* mode B: defer */\r |
| 1000 | if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */\r |
| 1001 | else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */\r |
| 1002 | }\r |
| 1003 | temp = (MQ * M[MA]) + (LAC & 07777);\r |
| 1004 | LAC = (temp >> 12) & 07777;\r |
| 1005 | MQ = temp & 07777;\r |
| 1006 | PC = (PC + 1) & 07777;\r |
| 1007 | SC = 014; /* 12 shifts */\r |
| 1008 | break;\r |
| 1009 | \r |
| 1010 | case 023: /* mode B: SWBA */\r |
| 1011 | if (emode) break;\r |
| 1012 | LAC = LAC | SC; /* mode A: SCA then */\r |
| 1013 | case 003: /* DVI */\r |
| 1014 | MA = IF | PC;\r |
| 1015 | if (emode) { /* mode B: defer */\r |
| 1016 | if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */\r |
| 1017 | else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */\r |
| 1018 | }\r |
| 1019 | if ((LAC & 07777) >= M[MA]) { /* overflow? */\r |
| 1020 | LAC = LAC | 010000; /* set link */\r |
| 1021 | MQ = ((MQ << 1) + 1) & 07777; /* rotate MQ */\r |
| 1022 | SC = 0; /* no shifts */\r |
| 1023 | }\r |
| 1024 | else {\r |
| 1025 | temp = ((LAC & 07777) << 12) | MQ;\r |
| 1026 | MQ = temp / M[MA];\r |
| 1027 | LAC = temp % M[MA];\r |
| 1028 | SC = 015; /* 13 shifts */\r |
| 1029 | }\r |
| 1030 | PC = (PC + 1) & 07777;\r |
| 1031 | break;\r |
| 1032 | \r |
| 1033 | case 024: /* mode B: DPSZ */\r |
| 1034 | if (emode) {\r |
| 1035 | if (((LAC | MQ) & 07777) == 0) PC = (PC + 1) & 07777;\r |
| 1036 | break;\r |
| 1037 | }\r |
| 1038 | LAC = LAC | SC; /* mode A: SCA then */\r |
| 1039 | case 004: /* NMI */\r |
| 1040 | temp = (LAC << 12) | MQ; /* preserve link */\r |
| 1041 | for (SC = 0; ((temp & 017777777) != 0) &&\r |
| 1042 | (temp & 040000000) == ((temp << 1) & 040000000); SC++)\r |
| 1043 | temp = temp << 1;\r |
| 1044 | LAC = (temp >> 12) & 017777;\r |
| 1045 | MQ = temp & 07777;\r |
| 1046 | if (emode && ((LAC & 07777) == 04000) && (MQ == 0))\r |
| 1047 | LAC = LAC & 010000; /* clr if 4000'0000 */\r |
| 1048 | break;\r |
| 1049 | \r |
| 1050 | case 025: /* mode B: DPIC */\r |
| 1051 | if (emode) {\r |
| 1052 | temp = (LAC + 1) & 07777; /* SWP already done! */\r |
| 1053 | LAC = MQ + (temp == 0);\r |
| 1054 | MQ = temp;\r |
| 1055 | break;\r |
| 1056 | }\r |
| 1057 | LAC = LAC | SC; /* mode A: SCA then */\r |
| 1058 | case 5: /* SHL */\r |
| 1059 | SC = (M[IF | PC] & 037) + (emode ^ 1); /* shift+1 if mode A */\r |
| 1060 | if (SC > 25) temp = 0; /* >25? result = 0 */\r |
| 1061 | else temp = ((LAC << 12) | MQ) << SC; /* <=25? shift LAC:MQ */\r |
| 1062 | LAC = (temp >> 12) & 017777;\r |
| 1063 | MQ = temp & 07777;\r |
| 1064 | PC = (PC + 1) & 07777;\r |
| 1065 | SC = emode? 037: 0; /* SC = 0 if mode A */\r |
| 1066 | break;\r |
| 1067 | \r |
| 1068 | case 026: /* mode B: DCM */\r |
| 1069 | if (emode) {\r |
| 1070 | temp = (-LAC) & 07777; /* SWP already done! */\r |
| 1071 | LAC = (MQ ^ 07777) + (temp == 0);\r |
| 1072 | MQ = temp;\r |
| 1073 | break;\r |
| 1074 | }\r |
| 1075 | LAC = LAC | SC; /* mode A: SCA then */\r |
| 1076 | case 6: /* ASR */\r |
| 1077 | SC = (M[IF | PC] & 037) + (emode ^ 1); /* shift+1 if mode A */\r |
| 1078 | temp = ((LAC & 07777) << 12) | MQ; /* sext from AC0 */\r |
| 1079 | if (LAC & 04000) temp = temp | ~037777777;\r |
| 1080 | if (emode && (SC != 0)) gtf = (temp >> (SC - 1)) & 1;\r |
| 1081 | if (SC > 25) temp = (LAC & 04000)? -1: 0;\r |
| 1082 | else temp = temp >> SC;\r |
| 1083 | LAC = (temp >> 12) & 017777;\r |
| 1084 | MQ = temp & 07777;\r |
| 1085 | PC = (PC + 1) & 07777;\r |
| 1086 | SC = emode? 037: 0; /* SC = 0 if mode A */\r |
| 1087 | break;\r |
| 1088 | \r |
| 1089 | case 027: /* mode B: SAM */\r |
| 1090 | if (emode) {\r |
| 1091 | temp = LAC & 07777;\r |
| 1092 | LAC = MQ + (temp ^ 07777) + 1; /* L'AC = MQ - AC */\r |
| 1093 | gtf = (temp <= MQ) ^ ((temp ^ MQ) >> 11);\r |
| 1094 | break;\r |
| 1095 | }\r |
| 1096 | LAC = LAC | SC; /* mode A: SCA then */\r |
| 1097 | case 7: /* LSR */\r |
| 1098 | SC = (M[IF | PC] & 037) + (emode ^ 1); /* shift+1 if mode A */\r |
| 1099 | temp = ((LAC & 07777) << 12) | MQ; /* clear link */\r |
| 1100 | if (emode && (SC != 0)) gtf = (temp >> (SC - 1)) & 1;\r |
| 1101 | if (SC > 24) temp = 0; /* >24? result = 0 */\r |
| 1102 | else temp = temp >> SC; /* <=24? shift AC:MQ */\r |
| 1103 | LAC = (temp >> 12) & 07777;\r |
| 1104 | MQ = temp & 07777;\r |
| 1105 | PC = (PC + 1) & 07777;\r |
| 1106 | SC = emode? 037: 0; /* SC = 0 if mode A */\r |
| 1107 | break;\r |
| 1108 | } /* end switch */\r |
| 1109 | break; /* end case 7 */\r |
| 1110 | \r |
| 1111 | /* Opcode 6, IOT. From Bernhard Baehr's description of the TSC8-75:\r |
| 1112 | \r |
| 1113 | (In user mode) Additional to raising a user mode interrupt, the current IOT\r |
| 1114 | opcode is moved to the ERIOT register. When the IOT is a CDF instruction (62x1),\r |
| 1115 | the ECDF flag is set, otherwise it is cleared. */\r |
| 1116 | \r |
| 1117 | case 030:case 031:case 032:case 033: /* IOT */\r |
| 1118 | if (UF) { /* privileged? */\r |
| 1119 | int_req = int_req | INT_UF; /* request intr */\r |
| 1120 | tsc_ir = IR; /* save instruction */\r |
| 1121 | if ((IR & 07707) == 06201) tsc_cdf = 1; /* set/clear flag */\r |
| 1122 | else tsc_cdf = 0;\r |
| 1123 | break;\r |
| 1124 | }\r |
| 1125 | device = (IR >> 3) & 077; /* device = IR<3:8> */\r |
| 1126 | pulse = IR & 07; /* pulse = IR<9:11> */\r |
| 1127 | iot_data = LAC & 07777; /* AC unchanged */\r |
| 1128 | switch (device) { /* decode IR<3:8> */\r |
| 1129 | \r |
| 1130 | case 000: /* CPU control */\r |
| 1131 | switch (pulse) { /* decode IR<9:11> */\r |
| 1132 | \r |
| 1133 | case 0: /* SKON */\r |
| 1134 | if (int_req & INT_ION) PC = (PC + 1) & 07777;\r |
| 1135 | int_req = int_req & ~INT_ION;\r |
| 1136 | break;\r |
| 1137 | \r |
| 1138 | case 1: /* ION */\r |
| 1139 | int_req = (int_req | INT_ION) & ~INT_NO_ION_PENDING;\r |
| 1140 | break;\r |
| 1141 | \r |
| 1142 | case 2: /* IOF */\r |
| 1143 | int_req = int_req & ~INT_ION;\r |
| 1144 | break;\r |
| 1145 | \r |
| 1146 | case 3: /* SRQ */\r |
| 1147 | if (int_req & INT_ALL) PC = (PC + 1) & 07777;\r |
| 1148 | break;\r |
| 1149 | \r |
| 1150 | case 4: /* GTF */\r |
| 1151 | LAC = (LAC & 010000) |\r |
| 1152 | ((LAC & 010000) >> 1) | (gtf << 10) |\r |
| 1153 | (((int_req & INT_ALL) != 0) << 9) |\r |
| 1154 | (((int_req & INT_ION) != 0) << 7) | SF;\r |
| 1155 | break;\r |
| 1156 | \r |
| 1157 | case 5: /* RTF */\r |
| 1158 | gtf = ((LAC & 02000) >> 10);\r |
| 1159 | UB = (LAC & 0100) >> 6;\r |
| 1160 | IB = (LAC & 0070) << 9;\r |
| 1161 | DF = (LAC & 0007) << 12;\r |
| 1162 | LAC = ((LAC & 04000) << 1) | iot_data;\r |
| 1163 | int_req = (int_req | INT_ION) & ~INT_NO_CIF_PENDING;\r |
| 1164 | break;\r |
| 1165 | \r |
| 1166 | case 6: /* SGT */\r |
| 1167 | if (gtf) PC = (PC + 1) & 07777;\r |
| 1168 | break;\r |
| 1169 | \r |
| 1170 | case 7: /* CAF */\r |
| 1171 | gtf = 0;\r |
| 1172 | emode = 0;\r |
| 1173 | int_req = int_req & INT_NO_CIF_PENDING;\r |
| 1174 | dev_done = 0;\r |
| 1175 | int_enable = INT_INIT_ENABLE;\r |
| 1176 | LAC = 0;\r |
| 1177 | reset_all (1); /* reset all dev */\r |
| 1178 | break;\r |
| 1179 | } /* end switch pulse */\r |
| 1180 | break; /* end case 0 */\r |
| 1181 | \r |
| 1182 | case 020:case 021:case 022:case 023:\r |
| 1183 | case 024:case 025:case 026:case 027: /* memory extension */\r |
| 1184 | switch (pulse) { /* decode IR<9:11> */\r |
| 1185 | \r |
| 1186 | case 1: /* CDF */\r |
| 1187 | DF = (IR & 0070) << 9;\r |
| 1188 | break;\r |
| 1189 | \r |
| 1190 | case 2: /* CIF */\r |
| 1191 | IB = (IR & 0070) << 9;\r |
| 1192 | int_req = int_req & ~INT_NO_CIF_PENDING;\r |
| 1193 | break;\r |
| 1194 | \r |
| 1195 | case 3: /* CDF CIF */\r |
| 1196 | DF = IB = (IR & 0070) << 9;\r |
| 1197 | int_req = int_req & ~INT_NO_CIF_PENDING;\r |
| 1198 | break;\r |
| 1199 | \r |
| 1200 | case 4:\r |
| 1201 | switch (device & 07) { /* decode IR<6:8> */\r |
| 1202 | \r |
| 1203 | case 0: /* CINT */\r |
| 1204 | int_req = int_req & ~INT_UF;\r |
| 1205 | break;\r |
| 1206 | \r |
| 1207 | case 1: /* RDF */\r |
| 1208 | LAC = LAC | (DF >> 9);\r |
| 1209 | break;\r |
| 1210 | \r |
| 1211 | case 2: /* RIF */\r |
| 1212 | LAC = LAC | (IF >> 9);\r |
| 1213 | break;\r |
| 1214 | \r |
| 1215 | case 3: /* RIB */\r |
| 1216 | LAC = LAC | SF;\r |
| 1217 | break;\r |
| 1218 | \r |
| 1219 | case 4: /* RMF */\r |
| 1220 | UB = (SF & 0100) >> 6;\r |
| 1221 | IB = (SF & 0070) << 9;\r |
| 1222 | DF = (SF & 0007) << 12;\r |
| 1223 | int_req = int_req & ~INT_NO_CIF_PENDING;\r |
| 1224 | break;\r |
| 1225 | \r |
| 1226 | case 5: /* SINT */\r |
| 1227 | if (int_req & INT_UF) PC = (PC + 1) & 07777;\r |
| 1228 | break;\r |
| 1229 | \r |
| 1230 | case 6: /* CUF */\r |
| 1231 | UB = 0;\r |
| 1232 | int_req = int_req & ~INT_NO_CIF_PENDING;\r |
| 1233 | break;\r |
| 1234 | \r |
| 1235 | case 7: /* SUF */\r |
| 1236 | UB = 1;\r |
| 1237 | int_req = int_req & ~INT_NO_CIF_PENDING;\r |
| 1238 | break;\r |
| 1239 | } /* end switch device */\r |
| 1240 | break;\r |
| 1241 | \r |
| 1242 | default:\r |
| 1243 | reason = stop_inst;\r |
| 1244 | break;\r |
| 1245 | } /* end switch pulse */\r |
| 1246 | break; /* end case 20-27 */\r |
| 1247 | \r |
| 1248 | case 010: /* power fail */\r |
| 1249 | switch (pulse) { /* decode IR<9:11> */\r |
| 1250 | \r |
| 1251 | case 1: /* SBE */\r |
| 1252 | break;\r |
| 1253 | \r |
| 1254 | case 2: /* SPL */\r |
| 1255 | if (int_req & INT_PWR) PC = (PC + 1) & 07777;\r |
| 1256 | break;\r |
| 1257 | \r |
| 1258 | case 3: /* CAL */\r |
| 1259 | int_req = int_req & ~INT_PWR;\r |
| 1260 | break;\r |
| 1261 | \r |
| 1262 | default:\r |
| 1263 | reason = stop_inst;\r |
| 1264 | break;\r |
| 1265 | } /* end switch pulse */\r |
| 1266 | break; /* end case 10 */\r |
| 1267 | \r |
| 1268 | default: /* I/O device */\r |
| 1269 | if (dev_tab[device]) { /* dev present? */\r |
| 1270 | iot_data = dev_tab[device] (IR, iot_data);\r |
| 1271 | LAC = (LAC & 010000) | (iot_data & 07777);\r |
| 1272 | if (iot_data & IOT_SKP) PC = (PC + 1) & 07777;\r |
| 1273 | if (iot_data >= IOT_REASON)\r |
| 1274 | reason = iot_data >> IOT_V_REASON;\r |
| 1275 | }\r |
| 1276 | else reason = stop_inst; /* stop on flag */\r |
| 1277 | break;\r |
| 1278 | } /* end switch device */\r |
| 1279 | break; /* end case IOT */\r |
| 1280 | } /* end switch opcode */\r |
| 1281 | } /* end while */\r |
| 1282 | \r |
| 1283 | /* Simulation halted */\r |
| 1284 | \r |
| 1285 | saved_PC = IF | (PC & 07777); /* save copies */\r |
| 1286 | saved_DF = DF & 070000;\r |
| 1287 | saved_LAC = LAC & 017777;\r |
| 1288 | saved_MQ = MQ & 07777;\r |
| 1289 | pcq_r->qptr = pcq_p; /* update pc q ptr */\r |
| 1290 | return reason;\r |
| 1291 | } /* end sim_instr */\r |
| 1292 | \r |
| 1293 | /* Reset routine */\r |
| 1294 | \r |
| 1295 | t_stat cpu_reset (DEVICE *dptr)\r |
| 1296 | {\r |
| 1297 | int_req = (int_req & ~INT_ION) | INT_NO_CIF_PENDING;\r |
| 1298 | saved_DF = IB = saved_PC & 070000;\r |
| 1299 | UF = UB = gtf = emode = 0;\r |
| 1300 | pcq_r = find_reg ("PCQ", NULL, dptr);\r |
| 1301 | if (pcq_r) pcq_r->qptr = 0;\r |
| 1302 | else return SCPE_IERR;\r |
| 1303 | sim_brk_types = sim_brk_dflt = SWMASK ('E');\r |
| 1304 | return SCPE_OK;\r |
| 1305 | }\r |
| 1306 | \r |
| 1307 | /* Memory examine */\r |
| 1308 | \r |
| 1309 | t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)\r |
| 1310 | {\r |
| 1311 | if (addr >= MEMSIZE) return SCPE_NXM;\r |
| 1312 | if (vptr != NULL) *vptr = M[addr] & 07777;\r |
| 1313 | return SCPE_OK;\r |
| 1314 | }\r |
| 1315 | \r |
| 1316 | /* Memory deposit */\r |
| 1317 | \r |
| 1318 | t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)\r |
| 1319 | {\r |
| 1320 | if (addr >= MEMSIZE) return SCPE_NXM;\r |
| 1321 | M[addr] = val & 07777;\r |
| 1322 | return SCPE_OK;\r |
| 1323 | }\r |
| 1324 | \r |
| 1325 | /* Memory size change */\r |
| 1326 | \r |
| 1327 | t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)\r |
| 1328 | {\r |
| 1329 | int32 mc = 0;\r |
| 1330 | uint32 i;\r |
| 1331 | \r |
| 1332 | if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 07777) != 0))\r |
| 1333 | return SCPE_ARG;\r |
| 1334 | for (i = val; i < MEMSIZE; i++) mc = mc | M[i];\r |
| 1335 | if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE)))\r |
| 1336 | return SCPE_OK;\r |
| 1337 | MEMSIZE = val;\r |
| 1338 | for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0;\r |
| 1339 | return SCPE_OK;\r |
| 1340 | }\r |
| 1341 | \r |
| 1342 | /* Change device number for a device */\r |
| 1343 | \r |
| 1344 | t_stat set_dev (UNIT *uptr, int32 val, char *cptr, void *desc)\r |
| 1345 | {\r |
| 1346 | DEVICE *dptr;\r |
| 1347 | DIB *dibp;\r |
| 1348 | uint32 newdev;\r |
| 1349 | t_stat r;\r |
| 1350 | \r |
| 1351 | if (cptr == NULL) return SCPE_ARG;\r |
| 1352 | if (uptr == NULL) return SCPE_IERR;\r |
| 1353 | dptr = find_dev_from_unit (uptr);\r |
| 1354 | if (dptr == NULL) return SCPE_IERR;\r |
| 1355 | dibp = (DIB *) dptr->ctxt;\r |
| 1356 | if (dibp == NULL) return SCPE_IERR;\r |
| 1357 | newdev = get_uint (cptr, 8, DEV_MAX - 1, &r); /* get new */\r |
| 1358 | if ((r != SCPE_OK) || (newdev == dibp->dev)) return r;\r |
| 1359 | dibp->dev = newdev; /* store */\r |
| 1360 | return SCPE_OK;\r |
| 1361 | }\r |
| 1362 | \r |
| 1363 | /* Show device number for a device */\r |
| 1364 | \r |
| 1365 | t_stat show_dev (FILE *st, UNIT *uptr, int32 val, void *desc)\r |
| 1366 | {\r |
| 1367 | DEVICE *dptr;\r |
| 1368 | DIB *dibp;\r |
| 1369 | \r |
| 1370 | if (uptr == NULL) return SCPE_IERR;\r |
| 1371 | dptr = find_dev_from_unit (uptr);\r |
| 1372 | if (dptr == NULL) return SCPE_IERR;\r |
| 1373 | dibp = (DIB *) dptr->ctxt;\r |
| 1374 | if (dibp == NULL) return SCPE_IERR;\r |
| 1375 | fprintf (st, "devno=%02o", dibp->dev);\r |
| 1376 | if (dibp->num > 1) fprintf (st, "-%2o", dibp->dev + dibp->num - 1);\r |
| 1377 | return SCPE_OK;\r |
| 1378 | }\r |
| 1379 | \r |
| 1380 | /* CPU device handler - should never get here! */\r |
| 1381 | \r |
| 1382 | int32 bad_dev (int32 IR, int32 AC)\r |
| 1383 | {\r |
| 1384 | return (SCPE_IERR << IOT_V_REASON) | AC; /* broken! */\r |
| 1385 | }\r |
| 1386 | \r |
| 1387 | /* Build device dispatch table */\r |
| 1388 | \r |
| 1389 | t_bool build_dev_tab (void)\r |
| 1390 | {\r |
| 1391 | DEVICE *dptr;\r |
| 1392 | DIB *dibp;\r |
| 1393 | uint32 i, j;\r |
| 1394 | static const uint8 std_dev[] = {\r |
| 1395 | 000, 010, 020, 021, 022, 023, 024, 025, 026, 027\r |
| 1396 | };\r |
| 1397 | \r |
| 1398 | for (i = 0; i < DEV_MAX; i++) dev_tab[i] = NULL; /* clr table */\r |
| 1399 | for (i = 0; i < ((uint32) sizeof (std_dev)); i++) /* std entries */\r |
| 1400 | dev_tab[std_dev[i]] = &bad_dev;\r |
| 1401 | for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* add devices */\r |
| 1402 | dibp = (DIB *) dptr->ctxt; /* get DIB */\r |
| 1403 | if (dibp && !(dptr->flags & DEV_DIS)) { /* enabled? */\r |
| 1404 | for (j = 0; j < dibp->num; j++) { /* loop thru disp */\r |
| 1405 | if (dibp->dsp[j]) { /* any dispatch? */\r |
| 1406 | if (dev_tab[dibp->dev + j]) { /* already filled? */\r |
| 1407 | printf ("%s device number conflict at %02o\n",\r |
| 1408 | sim_dname (dptr), dibp->dev + j);\r |
| 1409 | if (sim_log) fprintf (sim_log,\r |
| 1410 | "%s device number conflict at %02o\n",\r |
| 1411 | sim_dname (dptr), dibp->dev + j);\r |
| 1412 | return TRUE;\r |
| 1413 | }\r |
| 1414 | dev_tab[dibp->dev + j] = dibp->dsp[j]; /* fill */\r |
| 1415 | } /* end if dsp */\r |
| 1416 | } /* end for j */\r |
| 1417 | } /* end if enb */\r |
| 1418 | } /* end for i */\r |
| 1419 | return FALSE;\r |
| 1420 | }\r |
| 1421 | \r |
| 1422 | /* Set history */\r |
| 1423 | \r |
| 1424 | t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc)\r |
| 1425 | {\r |
| 1426 | int32 i, lnt;\r |
| 1427 | t_stat r;\r |
| 1428 | \r |
| 1429 | if (cptr == NULL) {\r |
| 1430 | for (i = 0; i < hst_lnt; i++) hst[i].pc = 0;\r |
| 1431 | hst_p = 0;\r |
| 1432 | return SCPE_OK;\r |
| 1433 | }\r |
| 1434 | lnt = (int32) get_uint (cptr, 10, HIST_MAX, &r);\r |
| 1435 | if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) return SCPE_ARG;\r |
| 1436 | hst_p = 0;\r |
| 1437 | if (hst_lnt) {\r |
| 1438 | free (hst);\r |
| 1439 | hst_lnt = 0;\r |
| 1440 | hst = NULL;\r |
| 1441 | }\r |
| 1442 | if (lnt) {\r |
| 1443 | hst = (InstHistory *) calloc (lnt, sizeof (InstHistory));\r |
| 1444 | if (hst == NULL) return SCPE_MEM;\r |
| 1445 | hst_lnt = lnt;\r |
| 1446 | }\r |
| 1447 | return SCPE_OK;\r |
| 1448 | }\r |
| 1449 | \r |
| 1450 | /* Show history */\r |
| 1451 | \r |
| 1452 | t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc)\r |
| 1453 | {\r |
| 1454 | int32 l, k, di, lnt;\r |
| 1455 | char *cptr = (char *) desc;\r |
| 1456 | t_stat r;\r |
| 1457 | t_value sim_eval;\r |
| 1458 | InstHistory *h;\r |
| 1459 | extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val,\r |
| 1460 | UNIT *uptr, int32 sw);\r |
| 1461 | \r |
| 1462 | if (hst_lnt == 0) return SCPE_NOFNC; /* enabled? */\r |
| 1463 | if (cptr) {\r |
| 1464 | lnt = (int32) get_uint (cptr, 10, hst_lnt, &r);\r |
| 1465 | if ((r != SCPE_OK) || (lnt == 0)) return SCPE_ARG;\r |
| 1466 | }\r |
| 1467 | else lnt = hst_lnt;\r |
| 1468 | di = hst_p - lnt; /* work forward */\r |
| 1469 | if (di < 0) di = di + hst_lnt;\r |
| 1470 | fprintf (st, "PC L AC MQ ea IR\n\n");\r |
| 1471 | for (k = 0; k < lnt; k++) { /* print specified */\r |
| 1472 | h = &hst[(++di) % hst_lnt]; /* entry pointer */\r |
| 1473 | if (h->pc & HIST_PC) { /* instruction? */\r |
| 1474 | l = (h->lac >> 12) & 1; /* link */\r |
| 1475 | fprintf (st, "%05o %o %04o %04o ", h->pc & ADDRMASK, l, h->lac & 07777, h->mq);\r |
| 1476 | if (h->ir < 06000) fprintf (st, "%05o ", h->ea);\r |
| 1477 | else fprintf (st, " ");\r |
| 1478 | sim_eval = h->ir;\r |
| 1479 | if ((fprint_sym (st, h->pc & ADDRMASK, &sim_eval, &cpu_unit, SWMASK ('M'))) > 0)\r |
| 1480 | fprintf (st, "(undefined) %04o", h->ir);\r |
| 1481 | if (h->ir < 04000) fprintf (st, " [%04o]", h->opnd);\r |
| 1482 | fputc ('\n', st); /* end line */\r |
| 1483 | } /* end else instruction */\r |
| 1484 | } /* end for */\r |
| 1485 | return SCPE_OK;\r |
| 1486 | }\r |