First Commit of my working state
[simh.git] / S3 / s3_cpu.c
1 /* s3_cpu.c: IBM System/3 CPU simulator
2
3 Copyright (c) 2001-2005, Charles E. Owen
4 HPL & SLC instruction code Copyright (c) 2001 by Henk Stegeman
5 Decimal Arithmetic Copyright (c) 2000 by Roger Bowler
6
7 Permission is hereby granted, free of charge, to any person obtaining a
8 copy of this software and associated documentation files (the "Software"),
9 to deal in the Software without restriction, including without limitation
10 the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 and/or sell copies of the Software, and to permit persons to whom the
12 Software is furnished to do so, subject to the following conditions:
13
14 The above copyright notice and this permission notice shall be included in
15 all copies or substantial portions of the Software.
16
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
24 Except as contained in this notice, the name of Charles E. Owen shall not be
25 used in advertising or otherwise to promote the sale, use or other dealings
26 in this Software without prior written authorization from Charles E. Owen.
27
28 ------------------------------------------------------------------------------
29
30 cpu System/3 (models 10 and 15) central processor
31
32 The IBM System/3 was a popular small-business computing system introduced
33 in 1969 as an entry-level system for businesses that could not afford
34 the lowest rungs of the System/360. Its architecture is inspired by and
35 in some ways similar to the 360, but to save cost the instruction set is
36 much smaller and the I/O channel system greatly simplified. There is no
37 compatibilty between the two systems.
38
39 The original System/3 had two models, 6 and 10, and these came in two
40 configurations: card system and disk system. The unique feature of
41 the /3 was the use of 96-column cards, although traditional 80-column
42 cards were supprted also via attachment of a 1442 reader/punch.
43 System/3 is a batch-oriented system, controlled by an operating
44 system known as SCP (System Control Program), with it's own job control
45 language known as OCL (simpler and more logical than the JCL used on
46 the mainframes). Original models did not support multiprogramming
47 or any form of interactivity. (There was a hardware dual-program
48 facility available on the model 10 at the high end).
49
50 The line grew throughout the 1970s, overlapping the low end of the 360
51 line with the introduction of the model 15. The 15 (and later larger
52 variations of the model 12) broke the 64K limit designed in the original
53 models by adding a simple address translation unit to support up to 512K
54 bytes. The model 15 added a system of storage protection and allowed
55 multiprogramming in up to 3 partitions. Communications were added to
56 allow support of multiple 3270 terminals and the models 12 and 15 broke
57 the batch orientation and facilitated interactive use via the CCP
58 (communications control program). The System/3 was effectively replaced
59 by the much easier to manage and use System/34 and System/36 at the
60 low and middle of the range, and by System/370 or System/38 at the
61 high end.
62
63 This simulator implements the model 10 and model 15. Models 4, 6,
64 8, and 12 are not supported (these were technical variations on the
65 design which offered no functionality not present on either 10 or 15).
66
67 The System/3 is a byte-oriented machine with a data path of 8 bits
68 in all models, and an address width of 16 bits.
69
70 The register state for the System/3 CPU is:
71
72 BAR <0:15> Operand 1 address register
73 AAR <0:15> Operand 2 address register
74 XR1 <0:15> Index Register 1
75 XR2 <0:15> Index Register 2
76 PSR <0:15> Condition Register
77 IAR [0:9]<0:15> Instruction Address Register (p1, p2, plus 1 for each interrupt)
78 ARR [0:9]<0:15> Address Recall Register (p1, p2, plus 1 for each interrupt)
79 (The P2 IAR & ARR are used for the Dual Program feature)
80
81 Instruction formats follow the same basic pattern: a 1-byte opcode, a
82 1-byte "Q byte", and one or two addresses following in a format defined
83 by the first 4 bits of the opcode:
84
85 Op Code Q Byte Address(es)
86
87 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
88 +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--...
89 | A 1 | A 2 | operation | | (defined by operation)| | Format based on A1, A2
90 +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--...
91
92 { --- } <---------------- Bits 00 = Operand 2 specified by 2-byte direct addr
93 Bits 01 = Operand 2 is 1-byte displacement + XR1
94 Bits 10 = Operand 2 is 1-byte displacement + XR2
95 Bits 11 = Operand 2 is not used
96
97 { --- } <---------------------- Bits 00 = Operand 1 specified by 2-byte direct addr
98 Bits 01 = Operand 1 is 1-byte displacement + XR1
99 Bits 10 = Operand 1 is 1-byte displacement + XR2
100 Bits 11 = Operand 1 is not used
101
102 Instructions come in 3 basic formats, of varying lengths which are determined
103 by the top 4 bits of opcode defined above. Minimum instruction length is 3 bytes,
104 maximum is 6.
105
106 1) Command Format (Bits 0-3 are 1111):
107
108 +------------+ +------------+ +------------+
109 | Opcode | | Q-byte | | R-byte +
110 +------------+ +------------+ +------------+
111
112 (The meaning of Q-byte and R-byte defined by the operation)
113
114
115 2) One Address Instructions (either bits 0-1 or bits 2-3 are 01):
116
117
118 Direct Addressing Format:
119
120 +------------+ +------------+ +-----------+----------+
121 | Opcode | | Q-byte | | MSB + LSB +
122 +------------+ +------------+ +-----------+----------+
123
124 Base-Displacement Format:
125
126 +------------+ +------------+ +------------+
127 | Opcode | | Q-byte | |displacement+
128 +------------+ +------------+ +------------+
129
130 Opcodes are 0011xxxx or 1100xxxx.
131
132 Q-byte can be: 1) An immediate operand
133 2) A mask
134 3) A branch condition
135 4) A data selection
136
137 2) Two Address Instructions (neither bits 0-1 nor bits 2-3 are both 11):
138
139 Operand 1 Address Direct (opcodes 0001 or 0010):
140
141 +------------+ +------------+ +----------+----------+ +------------+
142 | Opcode | | Q-byte | | MSB + LSB + |displacement|
143 +------------+ +------------+ +----------+----------+ +------------+
144
145 Operand 2 Address Direct (opcodes 0100 or 1000):
146
147 +------------+ +------------+ +------------+ +----------+----------+
148 | Opcode | | Q-byte | |displacement| | MSB + LSB +
149 +------------+ +------------+ +------------+ +----------+----------+
150
151 Both Addresses Direct (opcode 0000):
152
153 +------------+ +------------+ +----------+----------+ +-----------+----------+
154 | Opcode | | Q-byte | | MSB + LSB + + MSB + LSB +
155 +------------+ +------------+ +----------+----------+ +-----------+----------+
156
157 Both Addresses Displacement (opcodes 0101, 0110, 1001, or 1010):
158
159 +------------+ +------------+ +------------+ +------------+
160 | Opcode | | Q-byte | |displacement| |displacement|
161 +------------+ +------------+ +------------+ +------------+
162
163
164 Assembler Mnemonic Format
165 -------------------------
166
167 The assembler format contains the same elements as the machine language operation,
168 but not always in the same format. The operation code frequently specifies both
169 the opcode and the Q byte, and the top nybble of the opcode is determined by
170 the format of the addresses.
171
172 Addresses take two forms: the direct address in hex, or a relative address
173 specified thusly: (byte,XRx) where 'byte' is a 1-byte offset, and XRx is
174 either XR1 or XR2 for the two index registers. Use these formats when
175 'address' is indicated below:
176
177 When 'reg' is mentioned, a mnemonic may be used for the register, thusly:
178 IAR Instruction Address Register for the current program level
179 ARR Address Recall Register for the current program level
180 P1IAR IAR for Program Level 1
181 P2IAR IAR for Program Level 2
182 PSR Program Status Register
183 0x01 - Equal
184 0x02 - Low
185 0x04 - High
186 0x08 - Decimal overflow
187 0x10 - Test false
188 0x20 - Binary overflow
189 0x40 - Not used
190 0x80 - Not used
191 XR1 Index Register 1
192 XR2 Index Register 2
193 IARx IAR for the interrupt level x (x = 0 thru 7)
194
195 All other operands mentioned below are single-byte hex, except for the
196 length (len) operand of the two-address instructions, which is a decimal length
197 in the range 1-256.
198
199 No-address formats:
200 ------------------
201
202 HPL hex,hex Halt Program Level, the operands are the Q and R bytes
203
204
205 One-address formats:
206 -------------------
207
208 A reg,address Add to register
209 CLI address,byte Compare Logical Immediate
210 MVI address,byte Move Immediate
211 TBF address,mask Test Bits Off
212 TBN address,mask Test Bits On
213 SBF address,mask Set Bits Off
214 SBN address,mask Set Bits On
215 ST reg,address Store Register
216 L reg,address Load Register
217 LA reg,address Load Address
218 JC address,cond Jump on Condition
219 BC address,cond Branch on Condition
220
221 These operations do not specify a qbyte, it is implicit in the opcode:
222
223 B address Unconditional branch to address
224 BE address Branch Equal
225 BNE address Branch Not Equal
226 BH address Branch High
227 BNH address Branch Not High
228 BL address Branch Low
229 BNL address Branch Not Low
230 BT address Branch True
231 BF address Branch False
232 BP address Branch Plus
233 BM address Branch Minus
234 BNP address Branch Not Plus
235 BNM address Branch Not Minus
236 BZ address Branch Zero
237 BNZ address Branch Not Zero
238 BOZ address Branch Overflow Zoned
239 BOL address Branch Overflow Logical
240 BNOZ address Branch No Overflow Zoned
241 BNOL address Branch No Overflow Logical
242 NOPB address No - never jump
243
244 (substitute J for B above for a set of Jumps -- 1-byte operand (not 2),
245 always jumps forward up to 255 bytes. In this case, 'address' cannot be
246 less than the current address, nor greater than the current address + 255)
247
248 Two-address formats (first address is destination, len is decimal 1-256):
249 -------------------
250
251 MVC address,address,len Move Characters
252 CLC address,address,len Compare Logical Characters
253 ALC address,address,len Add Logical Characters
254 SLC address,address,len Subtract Logical Characters
255 ED address,address,len Edit
256 ITC address,address,len Insert and Test Characters
257 AZ address,address,len Add Zoned Decimal
258 SZ address,address,len Subtract Zoned Decimal
259
260 MNN address,address Move Numeric to Numeric
261 MNZ address,address Move Numeric to Zone
262 MZZ address,address Move Zone to Zone
263 MZN address,address Move Zone to Numeric
264
265 I/O Format
266 ----------
267
268 In the I/O format, there are always 3 fields:
269
270 da - Device Address 0-15 (decimal)
271 m - Modifier 0-1
272 n - Function 0-7
273
274 The meaning of these is entirely defined by the device addressed.
275
276 There may be an optional control byte, or an optional address (based on
277 the type of instruction).
278
279 SNS da,m,n,address Sense I/O
280 LIO da,m,n,address Load I/O
281 TIO da,m,n,address Test I/O
282
283 SIO da,m,n,cc Start I/O -- cc is a control byte
284
285 APL da,m,n Advance Program Level
286
287
288
289 ---------------------------------------------
290 Here is a handy opcode cross-reference table:
291 ---------------------------------------------
292
293 | x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF
294 ---+------------------------------------------------------------------
295 0x | - - - - ZAZ - AZ SZ MVX - ED ITC MVC CLC ALC SLC
296 1x | - - - - ZAZ - AZ SZ MVX - ED ITC MVC CLC ALC SLC
297 2x | - - - - ZAZ - AZ SZ MVX - ED ITC MVC CLC ALC SLC
298 3x | SNS LIO - - ST L A - TBN TBF SBN SBF MVI CLI - -
299 |
300 4x | - - - - ZAZ - AZ SZ MVX - ED ITC MVC CLC ALC SLC
301 5x | - - - - ZAZ - AZ SZ MVX - ED ITC MVC CLC ALC SLC
302 6x | - - - - ZAZ - AZ SZ MVX - ED ITC MVC CLC ALC SLC
303 7x | SNS LIO - - ST L A - TBN TBF SBN SBF MVI CLI - -
304 |
305 8x | - - - - ZAZ - AZ SZ MVX - ED ITC MVC CLC ALC SLC
306 9x | - - - - ZAZ - AZ SZ MVX - ED ITC MVC CLC ALC SLC
307 Ax | - - - - ZAZ - AZ SZ MVX - ED ITC MVC CLC ALC SLC
308 Bx | SNS LIO - - ST L A - TBN TBF SBN SBF MVI CLI - -
309 |
310 Cx | BC TIO LA - - - - - - - - - - - - -
311 Dx | BC TIO LA - - - - - - - - - - - - -
312 Ex | BC TIO LA - - - - - - - - - - - - -
313 Fx | HPL APL JC SIO - - - - - - - - - - - -
314
315
316 This routine is the instruction decode routine for System/3.
317 It is called from the simulator control program to execute
318 instructions in simulated memory, starting at the simulated PC.
319 It runs until 'reason' is set non-zero.
320
321 General notes:
322
323 1. Reasons to stop. The simulator can be stopped by:
324
325 HALT instruction
326 breakpoint encountered
327 program check caused by invalid opcode or qbyte or address or I/O spec
328 unknown I/O device and STOP_DEV flag set
329 I/O error in I/O simulator
330
331 2. Interrupts.
332
333 There are 8 levels of interrupt, each with it's own IAR (program
334 counter). When an interrupt occurs, execution begins at the
335 location in the IAR for that level interrupt. The program
336 must save and restore state. Each device is assigned both a
337 level and a priority in hardware. Interrupts are reset via
338 an SIO instruction, when this happens, the program level
339 IAR resumes control.
340
341 Interrupts are maintained in the global variable int_req,
342 which is zero if no interrupts are pending, otherwise, the
343 lower 16 bits represent devices, rightmost bit being device
344 0. Each device requesting an interrupt sets its bit on.
345
346
347 3. Non-existent memory. On the System/3, any reference to non-existent
348 memory (read or write) causes a program check and machine stop.
349
350 4. Adding I/O devices. These modules must be modified:
351
352 ibms3_defs.h add interrupt request definition
353 ibms3_cpu.c add IOT mask, PI mask, and routine to dev_table
354 ibms3_sys.c add pointer to data structures to sim_devices
355 */
356
357 #include "s3_defs.h"
358
359 #define UNIT_V_M15 (UNIT_V_UF) /* Model 15 extensions */
360 #define UNIT_M15 (1 << UNIT_V_M15)
361 #define UNIT_V_DPF (UNIT_V_UF+1) /* Dual Programming */
362 #define UNIT_DPF (1 << UNIT_V_DPF)
363 #define UNIT_V_MSIZE (UNIT_V_UF+3) /* dummy mask */
364 #define UNIT_MSIZE (1 << UNIT_V_MSIZE)
365
366 uint8 M[MAXMEMSIZE] = { 0 }; /* memory */
367 int32 AAR = 0; /* Operand 1 addr reg */
368 int32 BAR = 0; /* Operand 2 addr reg */
369 int32 XR1 = 0; /* Index register 1 */
370 int32 XR2 = 0; /* Index register 2 */
371 int32 PSR = 0; /* Condition Register */
372 int32 IAR[10] = { 0 }; /* IAR 0-7 = int level 8=P1 9=P2 */
373 int32 ARR[10] = { 0 }; /* ARR 0-7 = int level 8=P1 9=P2 */
374 int32 dev_disable = 0; /* interrupt disable mask */
375 int32 int_req = 0; /* Interrupt request device bitmap */
376 int32 level = 8; /* Current Execution Level*/
377 int32 stop_dev = 0; /* stop on ill dev */
378 int32 SR = 0; /* Switch Register */
379 int32 saved_PC; /* Saved (old) PC) */
380 int32 debug_reg = 0; /* set for debug/trace */
381 int32 debug_flag = 0; /* 1 when trace.log open */
382 FILE *trace;
383 extern int32 sim_int_char;
384 extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */
385
386 t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
387 t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
388 t_stat cpu_reset (DEVICE *dptr);
389 t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
390 t_stat cpu_boot (int32 unitno, DEVICE *dptr1);
391 extern int32 pkb (int32 op, int32 m, int32 n, int32 data);
392 extern int32 crd (int32 op, int32 m, int32 n, int32 data);
393 extern int32 lpt (int32 op, int32 m, int32 n, int32 data);
394 extern int32 dsk1 (int32 op, int32 m, int32 n, int32 data);
395 extern int32 dsk2 (int32 op, int32 m, int32 n, int32 data);
396 extern int32 cpu (int32 op, int32 m, int32 n, int32 data);
397 extern t_stat sim_activate (UNIT *uptr, int32 delay);
398 extern int32 fprint_sym (FILE *of, int32 addr, uint32 *val,
399 UNIT *uptr, int32 sw);
400 int32 nulldev (int32 opcode, int32 m, int32 n, int32 data);
401 int add_zoned (int32 addr1, int32 len1, int32 addr2, int32 len2);
402 int32 subtract_zoned (int32 addr1, int32 len1, int32 addr2, int32 len2);
403 static int32 compare(int32 byte1, int32 byte2, int32 cond);
404 static int32 condition(int32 qbyte);
405 static void store_decimal (int32 addr, int32 len, uint8 *dec, int sign);
406 static void load_decimal (int32 addr, int32 len, uint8 *result, int32 *count, int32 *sign);
407 static void add_decimal (uint8 *dec1, uint8 *dec2, uint8 *result, int32 *count);
408 static void subtract_decimal (uint8 *dec1, uint8 *dec2, uint8 *result, int *count, int *sign);
409 int32 GetMem(int32 addr);
410 int32 PutMem(int32 addr, int32 data);
411
412 /* IOT dispatch table */
413
414 /* System/3 supports only 16 unique device addresses! */
415
416 struct ndev dev_table[16] = {
417 { 0, 0, &cpu }, /* Device 0: CPU control */
418 { 1, 0, &pkb }, /* Device 1: 5471 console printer/keyboard */
419 { 0, 0, &nulldev },
420 { 0, 0, &nulldev },
421 { 0, 0, &nulldev },
422 { 0, 0, &crd }, /* Device 5: 1442 card reader/punch */
423 { 0, 0, &nulldev }, /* Device 6: 3410 Tape drives 1 & 2 */
424 { 0, 0, &nulldev }, /* Device 7: 3410 Tape drives 3 & 4 */
425 { 0, 0, &nulldev },
426 { 0, 0, &nulldev },
427 { 0, 0, &dsk1 }, /* Device 10: 5444 Disk Drive 1 */
428 { 0, 0, &dsk2 }, /* Device 11: 5444 Disk Drive 2 */
429 { 0, 0, &nulldev }, /* Device 12: 5448 Disk Drive 1 */
430 { 0, 0, &nulldev }, /* DEvice 13: 5448 Disk Drive 2 */
431 { 0, 0, &lpt }, /* Device 14: 1403/5203 Printer */
432 { 0, 0, &nulldev } /* Device 15: 5424 MFCU */
433 };
434
435 /* Priority assigned to interrupt levels */
436
437 int32 priority[8] = {8, 7, 5, 4, 3, 6, 2, 1};
438
439 /* CPU data structures
440
441 cpu_dev CPU device descriptor
442 cpu_unit CPU unit descriptor
443 cpu_reg CPU register list
444 cpu_mod CPU modifiers list
445 */
446
447 UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, MAXMEMSIZE) };
448
449 REG cpu_reg[] = {
450 { HRDATA (IAR, saved_PC, 16), REG_RO },
451 { HRDATA (IAR-P1, IAR[8], 16) },
452 { HRDATA (IAR-P2, IAR[9], 16) },
453 { HRDATA (ARR-P1, ARR[8], 16) },
454 { HRDATA (ARR-P2, ARR[9], 16) },
455 { HRDATA (AAR, AAR, 16) },
456 { HRDATA (BAR, BAR, 16) },
457 { HRDATA (XR1, XR1, 16) },
458 { HRDATA (XR2, XR2, 16) },
459 { HRDATA (PSR, PSR, 16) },
460 { HRDATA (SR, SR, 16) },
461 { HRDATA (INT, int_req, 16), REG_RO },
462 { HRDATA (LEVEL, level, 16) },
463 { HRDATA (IAR0, IAR[0], 16) },
464 { HRDATA (IAR1, IAR[1], 16) },
465 { HRDATA (IAR2, IAR[2], 16) },
466 { HRDATA (IAR3, IAR[3], 16) },
467 { HRDATA (IAR4, IAR[4], 16) },
468 { HRDATA (IAR5, IAR[5], 16) },
469 { HRDATA (IAR6, IAR[6], 16) },
470 { HRDATA (IAR7, IAR[7], 16) },
471 { HRDATA (ARR0, ARR[0], 16) },
472 { HRDATA (ARR1, ARR[1], 16) },
473 { HRDATA (ARR2, ARR[2], 16) },
474 { HRDATA (ARR3, ARR[3], 16) },
475 { HRDATA (ARR4, ARR[4], 16) },
476 { HRDATA (ARR5, ARR[5], 16) },
477 { HRDATA (ARR6, ARR[6], 16) },
478 { HRDATA (ARR7, ARR[7], 16) },
479 { HRDATA (DISABLE, dev_disable, 16), REG_RO },
480 { FLDATA (STOP_DEV, stop_dev, 0) },
481 { HRDATA (WRU, sim_int_char, 8) },
482 { HRDATA (DEBUG, debug_reg, 16) },
483 { NULL }
484 };
485
486 MTAB cpu_mod[] = {
487 { UNIT_M15, UNIT_M15, "M15", "M15", NULL },
488 { UNIT_M15, 0, "M10", "M10", NULL },
489 { UNIT_DPF, UNIT_DPF, "DPF", "DPF", NULL },
490 { UNIT_DPF, 0, "NODPF", "NODPF", NULL },
491 { UNIT_MSIZE, 8192, NULL, "8K", &cpu_set_size },
492 { UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size },
493 { UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size },
494 { UNIT_MSIZE, 49152, NULL, "48K", &cpu_set_size },
495 { UNIT_MSIZE, 65535, NULL, "64K", &cpu_set_size },
496 { 0 }
497 };
498
499 DEVICE cpu_dev = {
500 "CPU", &cpu_unit, cpu_reg, cpu_mod,
501 1, 16, 16, 1, 16, 8,
502 &cpu_ex, &cpu_dep, &cpu_reset,
503 NULL, NULL, NULL
504 };
505
506 t_stat sim_instr (void)
507 {
508 extern int32 sim_interval;
509 register int32 PC, IR;
510 int32 i, j, carry, zero, op1, op2;
511 int32 opcode = 0, qbyte = 0, rbyte = 0;
512 int32 opaddr, addr1, addr2, dlen1, dlen2, r;
513 int32 int_savelevel = 8, intpri, intlev, intdev, intmask;
514 int32 devno, devm, devn;
515 char display[3][9];
516 int32 val [32];
517 register t_stat reason;
518
519 /* Restore register state */
520
521 PC = IAR[level]; /* load local PC */
522 reason = 0;
523
524 /* Main instruction fetch/decode loop */
525
526 while (reason == 0) { /* loop until halted */
527 if (sim_interval <= 0) { /* check clock queue */
528 if (reason = sim_process_event ()) break;
529 }
530
531 if (int_req) { /* interrupt? */
532 intpri = 16;
533 for (i = 0; i < 16; i++) { /* Get highest priority device */
534 if ((int_req >> i) & 0x01) {
535 intlev = dev_table[i].level;
536 if (priority[intlev] < intpri) {
537 intdev = i;
538 intpri = priority[intlev];
539 }
540 }
541 }
542 intmask = 1 << intdev; /* mask is interrupting dev bit */
543 int_req = ~int_req & intmask; /* Turn off int_req for device */
544 int_savelevel = level; /* save current level for reset */
545 level = dev_table[intdev].level; /* get int level from device */
546 PC = IAR[level]; /* Use int level IAR for new PC */
547 } /* end interrupt */
548
549 if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */
550 reason = STOP_IBKPT; /* stop simulation */
551 break;
552 }
553
554 /* Machine Instruction Execution Here */
555
556 if ((debug_reg == 0) && debug_flag == 1) {
557 fclose(trace);
558 debug_flag = 0;
559 }
560 if (debug_reg) {
561 if (!debug_flag) {
562 trace = fopen("trace.log", "w");
563 debug_flag = 1;
564 }
565 }
566
567 if (debug_reg & 0x01) {
568 fprintf(trace, "ARR=%04X XR1=%04X XR2=%04X IAR=%04X ", ARR[level], XR1, XR2, PC);
569 val[0] = GetMem(PC);
570 val[1] = GetMem(PC+1);
571 val[2] = GetMem(PC+2);
572 val[3] = GetMem(PC+3);
573 val[4] = GetMem(PC+4);
574 val[5] = GetMem(PC+5);
575 fprint_sym(trace, PC, (uint32 *) val, &cpu_unit, SWMASK('M'));
576 fprintf(trace, "\n");
577 }
578
579 saved_PC = PC;
580 opaddr = GetMem(PC) & 0xf0; /* fetch addressing mode */
581 opcode = GetMem(PC) & 0x0f; /* fetch opcode */
582 PC = (PC + 1) & AMASK;
583 sim_interval = sim_interval - 1;
584
585 qbyte = GetMem(PC) & 0xff; /* fetch qbyte */
586 PC = (PC + 1) & AMASK;
587
588 if (opaddr == 0xf0) { /* Is it command format? */
589 rbyte = GetMem(PC) & 0xff;
590 PC = (PC + 1) & AMASK;
591 switch (opcode) {
592 case 0x00: /* HPL: Halt Program Level */
593 for (i = 0; i < 3; i++) {
594 for (j = 0; j < 9; j++) {
595 display[i][j] = ' ';
596 }
597 }
598 /* First line */
599 if (qbyte & 0x04) display[0][2] = '_' ;
600 if (rbyte & 0x04) display[0][6] = '_' ;
601 /* Second line */
602 if (qbyte & 0x08) display[1][1] = '|' ;
603 if (rbyte & 0x08) display[1][5] = '|' ;
604 if (qbyte & 0x10) display[1][2] = '_' ;
605 if (rbyte & 0x10) display[1][6] = '_' ;
606 if (qbyte & 0x02) display[1][3] = '|' ;
607 if (rbyte & 0x02) display[1][7] = '|' ;
608 /* Third line */
609 if (qbyte & 0x20) display[2][1] = '|' ;
610 if (rbyte & 0x20) display[2][5] = '|' ;
611 if (qbyte & 0x40) display[2][2] = '_' ;
612 if (rbyte & 0x40) display[2][6] = '_' ;
613 if (qbyte & 0x01) display[2][3] = '|' ;
614 if (rbyte & 0x01) display[2][7] = '|' ;
615 /* Print display segment array */
616 printf("\n\r");
617 for (i = 0; i < 3; i++) {
618 for (j = 0; j < 9; j++) {
619 printf ("%c", display[i][j]);
620 }
621 printf ("\n\r");
622 }
623 reason = STOP_HALT;
624 break;
625 case 0x01: /* APL: Advance Program Level */
626 devno = (qbyte >> 4) & 0x0f;
627 devm = (qbyte >> 3) & 0x01;
628 devn = qbyte & 0x07;
629 op1 = dev_table[devno].routine(4, devm, devn, rbyte);
630 if (op1 & 0x01) {
631 if (cpu_unit.flags & UNIT_DPF) { /* Dual Programming? */
632 if (level == 8) /* Yes: switch program levels */
633 level = 9;
634 else
635 level = 8;
636 PC = IAR[level];
637 } else { /* No: Loop on this inst */
638 PC = PC - 3;
639 }
640 }
641 reason = (op1 >> 16) & 0xffff;
642 break;
643 case 0x02: /* JC: Jump on Condition */
644 if (condition(qbyte) == 1) {
645 PC = (PC + rbyte) & AMASK;
646 }
647 break;
648 case 0x03: /* SIO: Start I/O */
649 devno = (qbyte >> 4) & 0x0f;
650 devm = (qbyte >> 3) & 0x01;
651 devn = qbyte & 0x07;
652 reason = dev_table[devno].routine(0, devm, devn, rbyte);
653 if (reason == RESET_INTERRUPT) {
654 reason = SCPE_OK;
655 IAR[level] = PC;
656 level = int_savelevel;
657 PC = IAR[level];
658 }
659 break;
660 default:
661 reason = STOP_INVOP;
662 break;
663 } /* switch (opcode) */
664 IAR[level] = PC;
665 continue;
666 }
667
668 /* Not command format: fetch the addresses */
669
670 addr1 = (opaddr >> 6) & 3;
671 addr2 = (opaddr >> 4) & 3;
672
673 switch (addr1) {
674 case 0:
675 BAR = GetMem(PC) << 8;
676 PC = (PC + 1) & AMASK;
677 BAR |=GetMem(PC);
678 PC = (PC + 1) & AMASK;
679 break;
680 case 1:
681 BAR = GetMem(PC);
682 BAR = (BAR + XR1) & AMASK;
683 PC = (PC + 1) & AMASK;
684 break;
685 case 2:
686 BAR = GetMem(PC);
687 BAR = (BAR + XR2) & AMASK;
688 PC = (PC + 1) & AMASK;
689 break;
690 case 3:
691 break;
692 default:
693 break;
694 } /* switch (addr1) */
695
696 switch (addr2) {
697 case 0:
698 AAR = GetMem(PC) << 8;
699 PC = (PC + 1) & AMASK;
700 AAR |= GetMem(PC);
701 PC = (PC + 1) & AMASK;
702 break;
703 case 1:
704 AAR = GetMem(PC);
705 AAR = (AAR + XR1) & AMASK;
706 PC = (PC + 1) & AMASK;
707 break;
708 case 2:
709 AAR = GetMem(PC);
710 AAR = (AAR + XR2) & AMASK;
711 PC = (PC + 1) & AMASK;
712 break;
713 case 3:
714 break;
715 default:
716 break;
717 } /* switch (addr1) */
718
719 switch (opaddr) {
720 case 0x00:
721 case 0x10:
722 case 0x20:
723 case 0x40:
724 case 0x50:
725 case 0x60:
726 case 0x80:
727 case 0x90:
728 case 0xa0:
729 switch (opcode) {
730 case 4: /* ZAZ: Zero and Add Zoned */
731 dlen2 = qbyte & 0x0f;
732 dlen1 = (qbyte >> 4) & 0xf;
733 dlen1 += dlen2;
734 op1 = BAR;
735 for (i = 0; i < (dlen1+1); i++) {
736 PutMem(op1, 0xf0);
737 op1--;
738 }
739 r = add_zoned(BAR, dlen1+1, AAR, dlen2+1);
740 PSR &= 0xF8; /* HJS mod */
741 switch (r) {
742 case 0:
743 PSR |= 0x01;
744 break;
745 case 1:
746 PSR |= 0x02;
747 break;
748 case 2:
749 PSR |= 0x04;
750 break;
751 default:
752 break;
753 }
754 break;
755 case 6: /* AZ: Add Zoned */
756 dlen2 = qbyte & 0x0f;
757 dlen1 = (qbyte >> 4) & 0xf;
758 dlen1 += dlen2;
759 r = add_zoned(BAR, dlen1+1, AAR, dlen2+1);
760 PSR &= 0xF0;
761 switch (r) {
762 case 0:
763 PSR |= 0x01;
764 break;
765 case 1:
766 PSR |= 0x02;
767 break;
768 case 2:
769 PSR |= 0x04;
770 break;
771 case 3:
772 PSR |= 0x08;
773 break;
774 default:
775 break;
776 }
777 break;
778 case 7: /* SZ: Subtract Zoned */
779 dlen2 = qbyte & 0x0f;
780 dlen1 = (qbyte >> 4) & 0xf;
781 dlen1 += dlen2;
782 r = subtract_zoned(BAR, dlen1+1, AAR, dlen2+1);
783 PSR &= 0xF0;
784 switch (r) {
785 case 0:
786 PSR |= 0x01;
787 break;
788 case 1:
789 PSR |= 0x02;
790 break;
791 case 2:
792 PSR |= 0x04;
793 break;
794 case 3:
795 PSR |= 0x08;
796 break;
797 default:
798 break;
799 }
800 break;
801 case 8: /* MVX: Move Hex */
802 op1 = GetMem(BAR);
803 op2 = GetMem(AAR);
804 switch (qbyte) {
805 case 0: /* Zone to zone */
806 op1 = (op1 & 0x0F) | (op2 & 0xF0);
807 break;
808 case 1: /* Numeric to zone */
809 op1 = (op1 & 0x0F) | (op2 << 4);
810 break;
811 case 2: /* Zone to numeric */
812 op1 = (op1 & 0xF0) | (op2 >> 4);
813 break;
814 case 3: /* Numeric to numeric */
815 op1 = (op1 & 0xF0) | (op2 & 0x0F);
816 break;
817 default:
818 reason = STOP_INVQ;
819 break;
820 }
821 PutMem(BAR, op1);
822 break;
823 case 0xa: /* ED: Edit */
824 zero = 1;
825 PSR &= 0xF8;
826 IR = GetMem(AAR);
827 if ((IR & 0xf0) != 0xF0)
828 PSR |= 0x02;
829 else
830 PSR |= 0x04;
831 while (qbyte > -1) {
832 op2 = GetMem(AAR);
833 op1 = GetMem(BAR);
834 if (op1 == 0x20) {
835 op2 |= 0xf0;
836 PutMem(BAR, op2);
837 AAR--;
838 if (op2 != 0xF0) zero = 0;
839 }
840 BAR--;
841 qbyte--;
842 }
843 if (zero)
844 PSR |= 0x01;
845 break;
846 case 0xb: /* ITC: Insert and Test Chars */
847 op2 = GetMem(AAR);
848 while (qbyte > -1) {
849 op1 = GetMem(BAR);
850 if (op1 >= 0xF1 && op1 <= 0xF9)
851 break;
852 PutMem(BAR, op2);
853 BAR++;
854 qbyte--;
855 }
856 ARR[level] = BAR;
857 break;
858 case 0xc: /* MVC: Move Characters */
859 while (qbyte > -1) {
860 PutMem(BAR, GetMem(AAR));
861 BAR--;
862 AAR--;
863 qbyte--;
864 }
865 break;
866 case 0xd: /* CLC: Compare Characters */
867 PSR &= 0xF8;
868 i = BAR = BAR - qbyte;
869 j = AAR = AAR - qbyte;
870 while (qbyte > -1) {
871 if (GetMem(i) > GetMem(j)) {
872 PSR |= 0x04;
873 break;
874 }
875 if (GetMem(i) < GetMem(j)) {
876 PSR |= 0x02;
877 break;
878 }
879 i++;
880 j++;
881 qbyte--;
882 }
883 if (qbyte == -1)
884 PSR |= 0x01;
885 break;
886 case 0xe: /* ALC: Add Logical Characters */
887 carry = 0;
888 zero = 1;
889 while (qbyte > -1) {
890 IR = GetMem(BAR) + GetMem(AAR) + carry;
891 if (IR & 0x100)
892 carry = 1;
893 else
894 carry = 0;
895 if ((IR & 0xFF) != 0) zero = 0; /* HJS mod */
896 PutMem(BAR,(IR & 0xFF));
897 BAR--;
898 AAR--;
899 qbyte--;
900 }
901 PSR &= 0xD8;
902 if (zero)
903 PSR |= 0x01; /* Equal */
904 if (!zero && !carry)
905 PSR |= 0x02; /* Low */
906 if (!zero && carry)
907 PSR |= 0x04; /* High */
908 if (carry)
909 PSR |= 0x20; /* Overflow */
910 break;
911 case 0xf: /* SLC: Subtract Logical Characters */
912 carry = 1;
913 zero = 1;
914 while (qbyte > -1) {
915 IR = GetMem(BAR) + (0xFF - GetMem(AAR)) + carry;
916 if (IR & 0x100)
917 carry = 1;
918 else
919 carry = 0;
920 if ((IR & 0xFF) != 0) zero = 0; /* HJS mod */
921 PutMem(BAR,(IR & 0xFF));
922 BAR--;
923 AAR--;
924 qbyte--;
925 }
926 PSR &= 0xF8;
927 if (zero)
928 PSR |= 0x01; /* Equal */
929 if (!zero && !carry)
930 PSR |= 0x02; /* Low */
931 if (!zero && carry)
932 PSR |= 0x04; /* High */
933 break;
934 default:
935 reason = STOP_INVOP;
936 break;
937 }
938 IAR[level] = PC;
939 continue;
940 break;
941 case 0x30:
942 case 0x70:
943 case 0xb0:
944 switch (opcode) {
945 case 0: /* SNS: Sense I/O */
946 devno = (qbyte >> 4) & 0x0f;
947 devm = (qbyte >> 3) & 0x01;
948 devn = qbyte & 0x07;
949 i = dev_table[devno].routine(3, devm, devn, rbyte);
950 PutMem(BAR, i & 0xff);
951 BAR--;
952 PutMem(BAR, (i >> 8) & 0xff);
953 reason = (i >> 16) & 0xffff;
954 break;
955 case 1: /* LIO: Load I/O */
956 devno = (qbyte >> 4) & 0x0f;
957 devm = (qbyte >> 3) & 0x01;
958 devn = qbyte & 0x07;
959 op1 = GetMem(BAR);
960 BAR--;
961 op1 |= (GetMem(BAR) << 8) & 0xff00;
962 reason = dev_table[devno].routine(1, devm, devn, op1);
963 break;
964 case 4: /* ST: Store Register */
965 switch (qbyte) {
966 case 0x01:
967 PutMem(BAR, XR1 & 0xff);
968 BAR--;
969 PutMem(BAR, (XR1 >> 8) & 0xff);
970 break;
971 case 0x02:
972 PutMem(BAR, XR2 & 0xff);
973 BAR--;
974 PutMem(BAR, (XR2 >> 8) & 0xff);
975 break;
976 case 0x04:
977 PutMem(BAR, PSR & 0xFF);
978 BAR--;
979 PutMem(BAR, 0); /* LCRR, not imp. */
980 break;
981 case 0x08:
982 PutMem(BAR, ARR[level] & 0xff);
983 BAR--;
984 PutMem(BAR, (ARR[level] >> 8) & 0xff);
985 break;
986 case 0x10:
987 PutMem(BAR, IAR[level] & 0xff);
988 BAR--;
989 PutMem(BAR, (IAR[level] >> 8) & 0xff);
990 break;
991 case 0x20:
992 PutMem(BAR, IAR[8] & 0xff);
993 BAR--;
994 PutMem(BAR, (IAR[8] >> 8) & 0xff);
995 break;
996 case 0x40:
997 PutMem(BAR, IAR[9] & 0xff);
998 BAR--;
999 PutMem(BAR, (IAR[9] >> 8) & 0xff);
1000 break;
1001 case 0x80:
1002 PutMem(BAR, IAR[0] & 0xff);
1003 BAR--;
1004 PutMem(BAR, (IAR[0] >> 8) & 0xff);
1005 break;
1006 case 0x81:
1007 PutMem(BAR, IAR[7] & 0xff);
1008 BAR--;
1009 PutMem(BAR, (IAR[7] >> 8) & 0xff);
1010 break;
1011 case 0x82:
1012 PutMem(BAR, IAR[6] & 0xff);
1013 BAR--;
1014 PutMem(BAR, (IAR[6] >> 8) & 0xff);
1015 break;
1016 case 0x84:
1017 PutMem(BAR, IAR[5] & 0xff);
1018 BAR--;
1019 PutMem(BAR, (IAR[5] >> 8) & 0xff);
1020 break;
1021 case 0x88:
1022 PutMem(BAR, IAR[4] & 0xff);
1023 BAR--;
1024 PutMem(BAR, (IAR[4] >> 8) & 0xff);
1025 break;
1026 case 0x90:
1027 PutMem(BAR, IAR[3] & 0xff);
1028 BAR--;
1029 PutMem(BAR, (IAR[3] >> 8) & 0xff);
1030 break;
1031 case 0xA0:
1032 PutMem(BAR, IAR[2] & 0xff);
1033 BAR--;
1034 PutMem(BAR, (IAR[2] >> 8) & 0xff);
1035 break;
1036 case 0xC0:
1037 PutMem(BAR, IAR[1] & 0xff);
1038 BAR--;
1039 PutMem(BAR, (IAR[1] >> 8) & 0xff);
1040 break;
1041 default:
1042 reason = STOP_INVQ;
1043 break;
1044 }
1045 break;
1046 case 5: /* L: Load Register */
1047 switch (qbyte) {
1048 case 0x01:
1049 XR1 = GetMem(BAR) & 0xff;
1050 BAR--;
1051 XR1 |= (GetMem(BAR) << 8) & 0xff00;
1052 break;
1053 case 0x02:
1054 XR2 = GetMem(BAR) & 0xff;
1055 BAR--;
1056 XR2 |= (GetMem(BAR) << 8) & 0xff00;
1057 break;
1058 case 0x04:
1059 PSR = GetMem(BAR) & 0xff;
1060 BAR--;
1061 break;
1062 case 0x08:
1063 ARR[level] = GetMem(BAR) & 0xff;
1064 BAR--;
1065 ARR[level] |= (GetMem(BAR) << 8) & 0xff00;
1066 break;
1067 case 0x10:
1068 IAR[level] = GetMem(BAR) & 0xff;
1069 BAR--;
1070 IAR[level] |= (GetMem(BAR) << 8) & 0xff00;
1071 PC = IAR[level];
1072 break;
1073 case 0x20:
1074 IAR[8] = GetMem(BAR) & 0xff;
1075 BAR--;
1076 IAR[8] |= (GetMem(BAR) << 8) & 0xff00;
1077 break;
1078 case 0x40:
1079 IAR[9] = GetMem(BAR) & 0xff;
1080 BAR--;
1081 IAR[9] |= (GetMem(BAR) << 8) & 0xff00;
1082 break;
1083 case 0x80:
1084 IAR[0] = GetMem(BAR) & 0xff;
1085 BAR--;
1086 IAR[0] |= (GetMem(BAR) << 8) & 0xff00;
1087 break;
1088 case 0x81:
1089 IAR[7] = GetMem(BAR) & 0xff;
1090 BAR--;
1091 IAR[7] |= (GetMem(BAR) << 8) & 0xff00;
1092 break;
1093 case 0x82:
1094 IAR[6] = GetMem(BAR) & 0xff;
1095 BAR--;
1096 IAR[6] |= (GetMem(BAR) << 8) & 0xff00;
1097 break;
1098 case 0x84:
1099 IAR[5] = GetMem(BAR) & 0xff;
1100 BAR--;
1101 IAR[5] |= (GetMem(BAR) << 8) & 0xff00;
1102 break;
1103 case 0x88:
1104 IAR[4] = GetMem(BAR) & 0xff;
1105 BAR--;
1106 IAR[4] |= (GetMem(BAR) << 8) & 0xff00;
1107 break;
1108 case 0x90:
1109 IAR[3] = GetMem(BAR) & 0xff;
1110 BAR--;
1111 IAR[3] |= (GetMem(BAR) << 8) & 0xff00;
1112 break;
1113 case 0xA0:
1114 IAR[2] = GetMem(BAR) & 0xff;
1115 BAR--;
1116 IAR[2] |= (GetMem(BAR) << 8) & 0xff00;
1117 break;
1118 case 0xC0:
1119 IAR[1] = GetMem(BAR) & 0xff;
1120 BAR--;
1121 IAR[1] |= (GetMem(BAR) << 8) & 0xff00;
1122 break;
1123 default:
1124 reason = STOP_INVQ;
1125 break;
1126 }
1127 break;
1128 case 6: /* A: Add to Register */
1129 IR = GetMem(BAR) & 0x00ff;
1130 BAR--;
1131 IR |= (GetMem(BAR) << 8) & 0xff00;
1132 switch (qbyte) {
1133 case 0x01:
1134 IR += XR1;
1135 XR1 = IR & AMASK;
1136 break;
1137 case 0x02:
1138 IR += XR2;
1139 XR2 = IR & AMASK;
1140 break;
1141 case 0x04:
1142 IR += PSR;
1143 PSR = IR & AMASK;
1144 break;
1145 case 0x08:
1146 IR += ARR[level];
1147 ARR[level] = IR & AMASK;
1148 break;
1149 case 0x10:
1150 IR += IAR[level];
1151 IAR[level] = IR & AMASK;
1152 break;
1153 case 0x20:
1154 IR += IAR[8];
1155 IAR[8] = IR & AMASK;
1156 break;
1157 case 0x40:
1158 IR += IAR[9];
1159 IAR[9] = IR & AMASK;
1160 break;
1161 case 0x80:
1162 IR += IAR[0];
1163 IAR[0] = IR & AMASK;
1164 break;
1165 case 0x81:
1166 IR += IAR[7];
1167 IAR[7] = IR & AMASK;
1168 break;
1169 case 0x82:
1170 IR += IAR[6];
1171 IAR[6] = IR & AMASK;
1172 break;
1173 case 0x84:
1174 IR += IAR[5];
1175 IAR[5] = IR & AMASK;
1176 break;
1177 case 0x88:
1178 IR += IAR[4];
1179 IAR[4] = IR & AMASK;
1180 break;
1181 case 0x90:
1182 IR += IAR[3];
1183 IAR[3] = IR & AMASK;
1184 break;
1185 case 0xA0:
1186 IR += IAR[2];
1187 IAR[2] = IR & AMASK;
1188 break;
1189 case 0xC0:
1190 IR += IAR[1];
1191 IAR[1] = IR & AMASK;
1192 break;
1193 default:
1194 reason = STOP_INVQ;
1195 break;
1196 }
1197 PSR &= 0xD8;
1198 if ((IR & 0xffff) == 0)
1199 PSR |= 0x01; /* Zero */
1200 if ((IR & 0xffff) != 0 && !(IR & 0x10000))
1201 PSR |= 0x02; /* Low */
1202 if ((IR & 0xffff) != 0 && (IR & 0x10000))
1203 PSR |= 0x04; /* High */
1204 if ((IR & 0x10000))
1205 PSR |= 0x20; /* Bin overflow */
1206 break;
1207 case 8: /* TBN: Test Bits On */
1208 IR = GetMem(BAR);
1209 PSR &= 0xFF;
1210 if ((IR & qbyte) != qbyte)
1211 PSR |= 0x10;
1212 break;
1213 case 9: /* TBF: Test Bits Off */
1214 IR = GetMem(BAR);
1215 PSR &= 0xFF;
1216 if ((IR & qbyte))
1217 PSR |= 0x10;
1218 break;
1219 case 0xa: /* SBN: Set Bits On */
1220 IR = GetMem(BAR);
1221 IR |= qbyte;
1222 PutMem(BAR, IR);
1223 break;
1224 case 0xb: /* SBF: Set Bits Off */
1225 IR = GetMem(BAR);
1226 IR &= ~qbyte;
1227 PutMem(BAR, IR);
1228 break;
1229 case 0xc: /* MVI: Move Immediate */
1230 PutMem(BAR, qbyte);
1231 break;
1232 case 0xd: /* CLI: Compare Immediate */
1233 PSR = compare(GetMem(BAR), qbyte, PSR);
1234 break;
1235 default:
1236 reason = STOP_INVOP;
1237 break;
1238 }
1239 IAR[level] = PC;
1240 continue;
1241 break;
1242 case 0xc0:
1243 case 0xd0:
1244 case 0xe0:
1245 switch (opcode) {
1246 case 0: /* BC: Branch on Condition */
1247 ARR[level] = AAR & AMASK;
1248 if (condition(qbyte) == 1) {
1249 IR = ARR[level];
1250 ARR[level] = PC & AMASK;
1251 PC = IR;
1252 }
1253 break;
1254 case 1: /* TIO: Test I/O */
1255 devno = (qbyte >> 4) & 0x0f;
1256 devm = (qbyte >> 3) & 0x01;
1257 devn = qbyte & 0x07;
1258 op1 = dev_table[devno].routine(2, devm, devn, rbyte);
1259 if (op1 & 0x01) {
1260 ARR[level] = AAR & AMASK;
1261 IR = ARR[level];
1262 ARR[level] = PC & AMASK;
1263 PC = IR;
1264 }
1265 reason = (op1 >> 16) & 0xffff;
1266 break;
1267 case 2: /* LA: Load Address */
1268 switch (qbyte) {
1269 case 1:
1270 XR1 = AAR;
1271 break;
1272 case 2:
1273 XR2 = AAR;
1274 break;
1275 default:
1276 reason = STOP_INVQ;
1277 break;
1278 }
1279 break;
1280 default:
1281 reason = STOP_INVOP;
1282 break;
1283 } /* switch (opcode) */
1284 IAR[level] = PC;
1285 continue;
1286
1287 default:
1288 reason = STOP_INVOP;
1289 break;
1290 } /* switch (opaddr) */
1291
1292 } /* end while (reason == 0) */
1293
1294 /* Simulation halted */
1295
1296 saved_PC = PC;
1297 return reason;
1298 }
1299
1300 /* On models 4-12, these memory functions could be inline, but
1301 on a model 15 with ATU address mapping must be performed so
1302 they are in functions here for future expansion.
1303 */
1304
1305 /* Fetch a byte from memory */
1306
1307 int32 GetMem(int32 addr)
1308 {
1309 return M[addr] & 0xff;
1310 }
1311
1312 /* Place a byte in memory */
1313
1314 int32 PutMem(int32 addr, int32 data)
1315 {
1316 M[addr] = data & 0xff;
1317 return 0;
1318 }
1319
1320 /* Check the condition register against the qbyte and return 1 if true */
1321
1322 int32 condition(int32 qbyte)
1323 {
1324 int32 r = 0, t, q;
1325 t = (qbyte & 0xf0) >> 4;
1326 q = qbyte & 0x0f;
1327 if (qbyte & 0x80) { /* True if any condition tested = 1*/
1328 if (((qbyte & 0x3f) & PSR) != 0) r = 1;
1329 } else { /* True if all conditions tested = 0 */
1330 if (((qbyte & 0x3f) & PSR) == 0) r = 1;
1331 }
1332 /* these bits reset by a test */
1333 if (qbyte & 0x10)
1334 PSR &= 0xEF; /* Reset test false if used */
1335 if (qbyte & 0x08)
1336 PSR &= 0xF7; /* Reset decimal overflow if tested */
1337 if (qbyte == 0x00)
1338 r = 1; /* unconditional branch */
1339 if (qbyte == 0x80)
1340 r = 0; /* force no branch */
1341 if (t >=0 && t < 8 && (q == 7 || q == 0xf))
1342 r = 0; /* no-op */
1343 if (t > 7 && t < 0x10 && (q == 7 || q == 0xf))
1344 r = 1; /* Force branch */
1345 return (r);
1346 }
1347 /* Given operand 1 and operand 2, compares the two and returns
1348 the System/3 condition register bits appropriately, given the
1349 condition register initial state in parameter 3
1350 */
1351
1352 int32 compare(int32 byte1, int32 byte2, int32 cond)
1353 {
1354 int32 r;
1355
1356 r = cond & 0xF8; /* mask off all but unaffected bits 2,3,4 */
1357 if (byte1 == byte2)
1358 r |= 0x01; /* set equal bit */
1359 if (byte1 < byte2)
1360 r |= 0x02; /* set less-than bit */
1361 if (byte1 > byte2)
1362 r |= 0x04; /* set greater than bit */
1363 return r;
1364 }
1365
1366 /*-------------------------------------------------------------------*/
1367 /* Add two zoned decimal operands */
1368 /* */
1369 /* Input: */
1370 /* addr1 Logical address of packed decimal storage operand 1 */
1371 /* len1 Length minus one of storage operand 1 (range 0-15) */
1372 /* addr2 Logical address of packed decimal storage operand 2 */
1373 /* len2 Length minus one of storage operand 2 (range 0-15) */
1374 /* Output: */
1375 /* The return value is the condition code: */
1376 /* 0=result zero, 1=result -ve, 2=result +ve, 3=overflow */
1377 /* */
1378 /* A program check may be generated if either logical address */
1379 /* causes an addressing, translation, or fetch protection */
1380 /* exception, or if either operand causes a data exception */
1381 /* because of invalid decimal digits or sign, or if the */
1382 /* first operand is store protected. Depending on the PSW */
1383 /* program mask, decimal overflow may cause a program check. */
1384 /*-------------------------------------------------------------------*/
1385 int32 add_zoned (int32 addr1, int32 len1, int32 addr2, int32 len2)
1386 {
1387 int cc; /* Condition code */
1388 uint8 dec1[MAX_DECIMAL_DIGITS]; /* Work area for operand 1 */
1389 uint8 dec2[MAX_DECIMAL_DIGITS]; /* Work area for operand 2 */
1390 uint8 dec3[MAX_DECIMAL_DIGITS]; /* Work area for result */
1391 int count1, count2, count3; /* Significant digit counters*/
1392 int sign1, sign2, sign3; /* Sign of operands & result */
1393
1394 /* Load operands into work areas */
1395 load_decimal (addr1, len1, dec1, &count1, &sign1);
1396 load_decimal (addr2, len2, dec2, &count2, &sign2);
1397
1398 /* Add or subtract operand values */
1399 if (count2 == 0)
1400 {
1401 /* If second operand is zero then result is first operand */
1402 memcpy (dec3, dec1, MAX_DECIMAL_DIGITS);
1403 count3 = count1;
1404 sign3 = sign1;
1405 }
1406 else if (count1 == 0)
1407 {
1408 /* If first operand is zero then result is second operand */
1409 memcpy (dec3, dec2, MAX_DECIMAL_DIGITS);
1410 count3 = count2;
1411 sign3 = sign2;
1412 }
1413 else if (sign1 == sign2)
1414 {
1415 /* If signs are equal then add operands */
1416 add_decimal (dec1, dec2, dec3, &count3);
1417 sign3 = sign1;
1418 }
1419 else
1420 {
1421 /* If signs are opposite then subtract operands */
1422 subtract_decimal (dec1, dec2, dec3, &count3, &sign3);
1423 if (sign1 < 0) sign3 = -sign3;
1424 }
1425
1426 /* Set condition code */
1427 cc = (count3 == 0) ? 0 : (sign3 < 1) ? 1 : 2;
1428
1429 /* Overflow if result exceeds first operand length */
1430 if (count3 > len1)
1431 cc = 3;
1432
1433 /* Set positive sign if result is zero */
1434 if (count3 == 0)
1435 sign3 = 1;
1436
1437 /* Store result into first operand location */
1438 store_decimal (addr1, len1, dec3, sign3);
1439
1440 /* Return condition code */
1441 return cc;
1442
1443 } /* end function add_packed */
1444
1445 /*-------------------------------------------------------------------*/
1446 /* Subtract two zoned decimal operands */
1447 /* */
1448 /* Input: */
1449 /* addr1 Logical address of packed decimal storage operand 1 */
1450 /* len1 Length minus one of storage operand 1 (range 0-15) */
1451 /* addr2 Logical address of packed decimal storage operand 2 */
1452 /* len2 Length minus one of storage operand 2 (range 0-15) */
1453 /* Output: */
1454 /* The return value is the condition code: */
1455 /* 0=result zero, 1=result -ve, 2=result +ve, 3=overflow */
1456 /* */
1457 /* A program check may be generated if either logical address */
1458 /* causes an addressing, translation, or fetch protection */
1459 /* exception, or if either operand causes a data exception */
1460 /* because of invalid decimal digits or sign, or if the */
1461 /* first operand is store protected. Depending on the PSW */
1462 /* program mask, decimal overflow may cause a program check. */
1463 /*-------------------------------------------------------------------*/
1464 int32 subtract_zoned (int32 addr1, int32 len1, int32 addr2, int32 len2)
1465 {
1466 int cc; /* Condition code */
1467 uint8 dec1[MAX_DECIMAL_DIGITS]; /* Work area for operand 1 */
1468 uint8 dec2[MAX_DECIMAL_DIGITS]; /* Work area for operand 2 */
1469 uint8 dec3[MAX_DECIMAL_DIGITS]; /* Work area for result */
1470 int count1, count2, count3; /* Significant digit counters*/
1471 int sign1, sign2, sign3; /* Sign of operands & result */
1472
1473 /* Load operands into work areas */
1474 load_decimal (addr1, len1, dec1, &count1, &sign1);
1475 load_decimal (addr2, len2, dec2, &count2, &sign2);
1476
1477 /* Add or subtract operand values */
1478 if (count2 == 0)
1479 {
1480 /* If second operand is zero then result is first operand */
1481 memcpy (dec3, dec1, MAX_DECIMAL_DIGITS);
1482 count3 = count1;
1483 sign3 = sign1;
1484 }
1485 else if (count1 == 0)
1486 {
1487 /* If first operand is zero then result is -second operand */
1488 memcpy (dec3, dec2, MAX_DECIMAL_DIGITS);
1489 count3 = count2;
1490 sign3 = -sign2;
1491 }
1492 else if (sign1 != sign2)
1493 {
1494 /* If signs are opposite then add operands */
1495 add_decimal (dec1, dec2, dec3, &count3);
1496 sign3 = sign1;
1497 }
1498 else
1499 {
1500 /* If signs are equal then subtract operands */
1501 subtract_decimal (dec1, dec2, dec3, &count3, &sign3);
1502 if (sign1 < 0) sign3 = -sign3;
1503 }
1504
1505 /* Set condition code */
1506 cc = (count3 == 0) ? 0 : (sign3 < 1) ? 1 : 2;
1507
1508 /* Overflow if result exceeds first operand length */
1509 if (count3 > len1)
1510 cc = 3;
1511
1512 /* Set positive sign if result is zero */
1513 if (count3 == 0)
1514 sign3 = 1;
1515
1516 /* Store result into first operand location */
1517 store_decimal (addr1, len1, dec3, sign3);
1518
1519 /* Return condition code */
1520 return cc;
1521
1522 } /* end function subtract_packed */
1523
1524
1525 /*-------------------------------------------------------------------*/
1526 /* Add two decimal byte strings as unsigned decimal numbers */
1527 /* */
1528 /* Input: */
1529 /* dec1 A 31-byte area containing the decimal digits of */
1530 /* the first operand. Each byte contains one decimal */
1531 /* digit in the low-order 4 bits of the byte. */
1532 /* dec2 A 31-byte area containing the decimal digits of */
1533 /* the second operand. Each byte contains one decimal */
1534 /* digit in the low-order 4 bits of the byte. */
1535 /* Output: */
1536 /* result Points to a 31-byte area to contain the result */
1537 /* digits. One decimal digit is placed in the low-order */
1538 /* 4 bits of each byte. */
1539 /* count Points to an integer to receive the number of */
1540 /* digits in the result excluding leading zeroes. */
1541 /* This field is set to zero if the result is all zero, */
1542 /* or to MAX_DECIMAL_DIGITS+1 if overflow occurred. */
1543 /*-------------------------------------------------------------------*/
1544 static void add_decimal (uint8 *dec1, uint8 *dec2, uint8 *result, int32 *count)
1545 {
1546 int d; /* Decimal digit */
1547 int i; /* Array subscript */
1548 int n = 0; /* Significant digit counter */
1549 int carry = 0; /* Carry indicator */
1550
1551 /* Add digits from right to left */
1552 for (i = MAX_DECIMAL_DIGITS - 1; i >= 0; i--)
1553 {
1554 /* Add digits from first and second operands */
1555 d = dec1[i] + dec2[i] + carry;
1556
1557 /* Check for carry into next digit */
1558 if (d > 9) {
1559 d -= 10;
1560 carry = 1;
1561 } else {
1562 carry = 0;
1563 }
1564
1565 /* Check for significant digit */
1566 if (d != 0)
1567 n = MAX_DECIMAL_DIGITS - i;
1568
1569 /* Store digit in result */
1570 result[i] = d;
1571
1572 } /* end for */
1573
1574 /* Check for carry out of leftmost digit */
1575 if (carry)
1576 n = MAX_DECIMAL_DIGITS + 1;
1577
1578 /* Return significant digit counter */
1579 *count = n;
1580
1581 } /* end function add_decimal */
1582
1583 /*-------------------------------------------------------------------*/
1584 /* Subtract two decimal byte strings as unsigned decimal numbers */
1585 /* */
1586 /* Input: */
1587 /* dec1 A 31-byte area containing the decimal digits of */
1588 /* the first operand. Each byte contains one decimal */
1589 /* digit in the low-order 4 bits of the byte. */
1590 /* dec2 A 31-byte area containing the decimal digits of */
1591 /* the second operand. Each byte contains one decimal */
1592 /* digit in the low-order 4 bits of the byte. */
1593 /* Output: */
1594 /* result Points to a 31-byte area to contain the result */
1595 /* digits. One decimal digit is placed in the low-order */
1596 /* 4 bits of each byte. */
1597 /* count Points to an integer to receive the number of */
1598 /* digits in the result excluding leading zeroes. */
1599 /* This field is set to zero if the result is all zero. */
1600 /* sign -1 if the result is negative (operand2 > operand1) */
1601 /* +1 if the result is positive (operand2 <= operand1) */
1602 /*-------------------------------------------------------------------*/
1603 static void subtract_decimal (uint8 *dec1, uint8 *dec2, uint8 *result, int *count, int *sign)
1604 {
1605 int d; /* Decimal digit */
1606 int i; /* Array subscript */
1607 int n = 0; /* Significant digit counter */
1608 int borrow = 0; /* Borrow indicator */
1609 int rc; /* Return code */
1610 uint8 *higher; /* -> Higher value operand */
1611 uint8 *lower; /* -> Lower value operand */
1612
1613 /* Compare digits to find which operand has higher numeric value */
1614 rc = memcmp (dec1, dec2, MAX_DECIMAL_DIGITS);
1615
1616 /* Return positive zero result if both operands are equal */
1617 if (rc == 0) {
1618 memset (result, 0, MAX_DECIMAL_DIGITS);
1619 *count = 0;
1620 *sign = +1;
1621 return;
1622 }
1623
1624 /* Point to higher and lower value operands and set sign */
1625 if (rc > 0) {
1626 higher = dec1;
1627 lower = dec2;
1628 *sign = +1;
1629 } else {
1630 lower = dec1;
1631 higher = dec2;
1632 *sign = -1;
1633 }
1634
1635 /* Subtract digits from right to left */
1636 for (i = MAX_DECIMAL_DIGITS - 1; i >= 0; i--)
1637 {
1638 /* Subtract lower operand digit from higher operand digit */
1639 d = higher[i] - lower[i] - borrow;
1640
1641 /* Check for borrow from next digit */
1642 if (d < 0) {
1643 d += 10;
1644 borrow = 1;
1645 } else {
1646 borrow = 0;
1647 }
1648
1649 /* Check for significant digit */
1650 if (d != 0)
1651 n = MAX_DECIMAL_DIGITS - i;
1652
1653 /* Store digit in result */
1654 result[i] = d;
1655
1656 } /* end for */
1657
1658 /* Return significant digit counter */
1659 *count = n;
1660
1661 } /* end function subtract_decimal */
1662
1663 /*-------------------------------------------------------------------*/
1664 /* Load a zoned decimal storage operand into a decimal byte string */
1665 /* */
1666 /* Input: */
1667 /* addr Logical address of zoned decimal storage operand */
1668 /* len Length minus one of storage operand (range 0-15) */
1669 /* Output: */
1670 /* result Points to a 31-byte area into which the decimal */
1671 /* digits are loaded. One decimal digit is loaded */
1672 /* into the low-order 4 bits of each byte, and the */
1673 /* result is padded to the left with high-order zeroes */
1674 /* if the storage operand contains less than 31 digits. */
1675 /* count Points to an integer to receive the number of */
1676 /* digits in the result excluding leading zeroes. */
1677 /* This field is set to zero if the result is all zero. */
1678 /* sign Points to an integer which will be set to -1 if a */
1679 /* negative sign was loaded from the operand, or +1 if */
1680 /* a positive sign was loaded from the operand. */
1681 /* */
1682 /* A program check may be generated if the logical address */
1683 /* causes an addressing, translation, or fetch protection */
1684 /* exception, or if the operand causes a data exception */
1685 /* because of invalid decimal digits or sign. */
1686 /*-------------------------------------------------------------------*/
1687 static void load_decimal (int32 addr, int32 len, uint8 *result, int32 *count, int32 *sign)
1688 {
1689 int h; /* Hexadecimal digit */
1690 int i, j; /* Array subscripts */
1691 int n; /* Significant digit counter */
1692
1693 if ((GetMem(addr) & 0xf0) == 0xD0)
1694 *sign = -1;
1695 else
1696 *sign = 1;
1697 j = len;
1698 for (i = MAX_DECIMAL_DIGITS; i > -1; i--) {
1699 if (j) {
1700 h = GetMem(addr) & 0x0f;
1701 addr--;
1702 j--;
1703 } else {
1704 h = 0;
1705 }
1706 result [i-1] = h;
1707 if (h > 0) n = i;
1708 }
1709 *count = 32 - n;
1710
1711 } /* end function load_decimal */
1712
1713 /*-------------------------------------------------------------------*/
1714 /* Store decimal byte string into packed decimal storage operand */
1715 /* */
1716 /* Input: */
1717 /* addr Logical address of packed decimal storage operand */
1718 /* len Length minus one of storage operand (range 0-15) */
1719 /* dec A 31-byte area containing the decimal digits to be */
1720 /* stored. Each byte contains one decimal digit in */
1721 /* the low-order 4 bits of the byte. */
1722 /* sign -1 if a negative sign is to be stored, or +1 if a */
1723 /* positive sign is to be stored. */
1724 /* */
1725 /* A program check may be generated if the logical address */
1726 /* causes an addressing, translation, or protection exception. */
1727 /*-------------------------------------------------------------------*/
1728 static void store_decimal (int32 addr, int32 len, uint8 *dec, int sign)
1729 {
1730 int i, j, a; /* Array subscripts */
1731
1732 j = len;
1733 a = addr;
1734 for (i = MAX_DECIMAL_DIGITS; i > -1; i--) {
1735 if (j) {
1736 PutMem(a, (dec[i-1] | 0xf0));
1737 a--;
1738 j--;
1739 } else {
1740 break;
1741 }
1742 }
1743 if (sign == -1) {
1744 PutMem(addr, (GetMem(addr) & 0x0f));
1745 PutMem(addr, (GetMem(addr) | 0xf0));
1746 }
1747
1748 } /* end function store_decimal */
1749
1750 /* CPU Device Control */
1751
1752 int32 cpu (int32 op, int32 m, int32 n, int32 data)
1753 {
1754 int32 iodata = 0;
1755
1756 switch (op) {
1757 case 0x00: /* Start IO */
1758 return SCPE_OK;
1759 case 0x01: /* LIO */
1760 return SCPE_OK;
1761 case 0x02: /* TIO */
1762 break;
1763 case 0x03: /* SNS */
1764 /* SNS CPU gets the data switches */
1765 iodata = SR;
1766 break;
1767 case 0x04: /* APL */
1768 break;
1769 default:
1770 break;
1771 }
1772 return ((SCPE_OK << 16) | iodata);
1773 }
1774
1775
1776
1777 /* Null device */
1778
1779 int32 nulldev (int32 opcode, int32 m, int32 n, int32 data)
1780 {
1781 if (opcode == 1)
1782 return SCPE_OK; /* Ok to LIO unconfigured devices? */
1783 return STOP_INVDEV;
1784 }
1785
1786 /* Reset routine */
1787
1788 t_stat cpu_reset (DEVICE *dptr)
1789 {
1790 int_req = 0;
1791 level = 8;
1792 sim_brk_types = sim_brk_dflt = SWMASK ('E');
1793 return SCPE_OK;
1794 }
1795
1796 /* Memory examine */
1797
1798 t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
1799 {
1800 if (addr >= MEMSIZE) return SCPE_NXM;
1801 if (vptr != NULL) *vptr = M[addr] & 0xff;
1802 return SCPE_OK;
1803 }
1804
1805 /* Memory deposit */
1806
1807 t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)
1808 {
1809 if (addr >= MEMSIZE) return SCPE_NXM;
1810 M[addr] = val & 0xff;
1811 return SCPE_OK;
1812 }
1813
1814 t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
1815 {
1816 int32 mc = 0;
1817 uint32 i;
1818
1819 if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 07777) != 0))
1820 return SCPE_ARG;
1821 for (i = val; i < MEMSIZE; i++) mc = mc | M[i];
1822 if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE)))
1823 return SCPE_OK;
1824 MEMSIZE = val;
1825 for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0;
1826 return SCPE_OK;
1827 }
1828
1829 t_stat cpu_boot (int32 unitno, DEVICE *dptr)
1830 {
1831 level = 8;
1832 IAR[8] = 0;
1833 return SCPE_OK;
1834 }