1 /* s3_cpu.c: IBM System/3 CPU simulator
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
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:
14 The above copyright notice and this permission notice shall be included in
15 all copies or substantial portions of the Software.
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.
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.
28 ------------------------------------------------------------------------------
30 cpu System/3 (models 10 and 15) central processor
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.
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).
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
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).
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.
70 The register state for the System/3 CPU is:
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)
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:
85 Op Code Q Byte Address(es)
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 +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--...
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
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
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,
106 1) Command Format (Bits 0-3 are 1111):
108 +------------+ +------------+ +------------+
109 | Opcode | | Q-byte | | R-byte +
110 +------------+ +------------+ +------------+
112 (The meaning of Q-byte and R-byte defined by the operation)
115 2) One Address Instructions (either bits 0-1 or bits 2-3 are 01):
118 Direct Addressing Format:
120 +------------+ +------------+ +-----------+----------+
121 | Opcode | | Q-byte | | MSB + LSB +
122 +------------+ +------------+ +-----------+----------+
124 Base-Displacement Format:
126 +------------+ +------------+ +------------+
127 | Opcode | | Q-byte | |displacement+
128 +------------+ +------------+ +------------+
130 Opcodes are 0011xxxx or 1100xxxx.
132 Q-byte can be: 1) An immediate operand
134 3) A branch condition
137 2) Two Address Instructions (neither bits 0-1 nor bits 2-3 are both 11):
139 Operand 1 Address Direct (opcodes 0001 or 0010):
141 +------------+ +------------+ +----------+----------+ +------------+
142 | Opcode | | Q-byte | | MSB + LSB + |displacement|
143 +------------+ +------------+ +----------+----------+ +------------+
145 Operand 2 Address Direct (opcodes 0100 or 1000):
147 +------------+ +------------+ +------------+ +----------+----------+
148 | Opcode | | Q-byte | |displacement| | MSB + LSB +
149 +------------+ +------------+ +------------+ +----------+----------+
151 Both Addresses Direct (opcode 0000):
153 +------------+ +------------+ +----------+----------+ +-----------+----------+
154 | Opcode | | Q-byte | | MSB + LSB + + MSB + LSB +
155 +------------+ +------------+ +----------+----------+ +-----------+----------+
157 Both Addresses Displacement (opcodes 0101, 0110, 1001, or 1010):
159 +------------+ +------------+ +------------+ +------------+
160 | Opcode | | Q-byte | |displacement| |displacement|
161 +------------+ +------------+ +------------+ +------------+
164 Assembler Mnemonic Format
165 -------------------------
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.
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:
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
186 0x08 - Decimal overflow
188 0x20 - Binary overflow
193 IARx IAR for the interrupt level x (x = 0 thru 7)
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
202 HPL hex,hex Halt Program Level, the operands are the Q and R bytes
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
221 These operations do not specify a qbyte, it is implicit in the opcode:
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
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)
248 Two-address formats (first address is destination, len is decimal 1-256):
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
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
268 In the I/O format, there are always 3 fields:
270 da - Device Address 0-15 (decimal)
274 The meaning of these is entirely defined by the device addressed.
276 There may be an optional control byte, or an optional address (based on
277 the type of instruction).
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
283 SIO da,m,n,cc Start I/O -- cc is a control byte
285 APL da,m,n Advance Program Level
289 ---------------------------------------------
290 Here is a handy opcode cross-reference table:
291 ---------------------------------------------
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 - -
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 - -
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 - -
310 Cx | BC TIO LA - - - - - - - - - - - - -
311 Dx | BC TIO LA - - - - - - - - - - - - -
312 Ex | BC TIO LA - - - - - - - - - - - - -
313 Fx | HPL APL JC SIO - - - - - - - - - - - -
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.
323 1. Reasons to stop. The simulator can be stopped by:
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
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
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.
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.
350 4. Adding I/O devices. These modules must be modified:
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
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)
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 */
383 extern int32 sim_int_char
;
384 extern int32 sim_brk_types
, sim_brk_dflt
, sim_brk_summ
; /* breakpoint info */
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
);
412 /* IOT dispatch table */
414 /* System/3 supports only 16 unique device addresses! */
416 struct ndev dev_table
[16] = {
417 { 0, 0, &cpu
}, /* Device 0: CPU control */
418 { 1, 0, &pkb
}, /* Device 1: 5471 console printer/keyboard */
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 */
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 */
435 /* Priority assigned to interrupt levels */
437 int32 priority
[8] = {8, 7, 5, 4, 3, 6, 2, 1};
439 /* CPU data structures
441 cpu_dev CPU device descriptor
442 cpu_unit CPU unit descriptor
443 cpu_reg CPU register list
444 cpu_mod CPU modifiers list
447 UNIT cpu_unit
= { UDATA (NULL
, UNIT_FIX
+ UNIT_BINK
, MAXMEMSIZE
) };
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) },
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
},
500 "CPU", &cpu_unit
, cpu_reg
, cpu_mod
,
502 &cpu_ex
, &cpu_dep
, &cpu_reset
,
506 t_stat
sim_instr (void)
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
;
517 register t_stat reason
;
519 /* Restore register state */
521 PC
= IAR
[level
]; /* load local PC */
524 /* Main instruction fetch/decode loop */
526 while (reason
== 0) { /* loop until halted */
527 if (sim_interval
<= 0) { /* check clock queue */
528 if (reason
= sim_process_event ()) break;
531 if (int_req
) { /* interrupt? */
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
) {
538 intpri
= priority
[intlev
];
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 */
549 if (sim_brk_summ
&& sim_brk_test (PC
, SWMASK ('E'))) { /* breakpoint? */
550 reason
= STOP_IBKPT
; /* stop simulation */
554 /* Machine Instruction Execution Here */
556 if ((debug_reg
== 0) && debug_flag
== 1) {
562 trace
= fopen("trace.log", "w");
567 if (debug_reg
& 0x01) {
568 fprintf(trace
, "ARR=%04X XR1=%04X XR2=%04X IAR=%04X ", ARR
[level
], XR1
, XR2
, 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");
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;
585 qbyte
= GetMem(PC
) & 0xff; /* fetch qbyte */
586 PC
= (PC
+ 1) & AMASK
;
588 if (opaddr
== 0xf0) { /* Is it command format? */
589 rbyte
= GetMem(PC
) & 0xff;
590 PC
= (PC
+ 1) & AMASK
;
592 case 0x00: /* HPL: Halt Program Level */
593 for (i
= 0; i
< 3; i
++) {
594 for (j
= 0; j
< 9; j
++) {
599 if (qbyte
& 0x04) display
[0][2] = '_' ;
600 if (rbyte
& 0x04) display
[0][6] = '_' ;
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] = '|' ;
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 */
617 for (i
= 0; i
< 3; i
++) {
618 for (j
= 0; j
< 9; j
++) {
619 printf ("%c", display
[i
][j
]);
625 case 0x01: /* APL: Advance Program Level */
626 devno
= (qbyte
>> 4) & 0x0f;
627 devm
= (qbyte
>> 3) & 0x01;
629 op1
= dev_table
[devno
].routine(4, devm
, devn
, rbyte
);
631 if (cpu_unit
.flags
& UNIT_DPF
) { /* Dual Programming? */
632 if (level
== 8) /* Yes: switch program levels */
637 } else { /* No: Loop on this inst */
641 reason
= (op1
>> 16) & 0xffff;
643 case 0x02: /* JC: Jump on Condition */
644 if (condition(qbyte
) == 1) {
645 PC
= (PC
+ rbyte
) & AMASK
;
648 case 0x03: /* SIO: Start I/O */
649 devno
= (qbyte
>> 4) & 0x0f;
650 devm
= (qbyte
>> 3) & 0x01;
652 reason
= dev_table
[devno
].routine(0, devm
, devn
, rbyte
);
653 if (reason
== RESET_INTERRUPT
) {
656 level
= int_savelevel
;
663 } /* switch (opcode) */
668 /* Not command format: fetch the addresses */
670 addr1
= (opaddr
>> 6) & 3;
671 addr2
= (opaddr
>> 4) & 3;
675 BAR
= GetMem(PC
) << 8;
676 PC
= (PC
+ 1) & AMASK
;
678 PC
= (PC
+ 1) & AMASK
;
682 BAR
= (BAR
+ XR1
) & AMASK
;
683 PC
= (PC
+ 1) & AMASK
;
687 BAR
= (BAR
+ XR2
) & AMASK
;
688 PC
= (PC
+ 1) & AMASK
;
694 } /* switch (addr1) */
698 AAR
= GetMem(PC
) << 8;
699 PC
= (PC
+ 1) & AMASK
;
701 PC
= (PC
+ 1) & AMASK
;
705 AAR
= (AAR
+ XR1
) & AMASK
;
706 PC
= (PC
+ 1) & AMASK
;
710 AAR
= (AAR
+ XR2
) & AMASK
;
711 PC
= (PC
+ 1) & AMASK
;
717 } /* switch (addr1) */
730 case 4: /* ZAZ: Zero and Add Zoned */
731 dlen2
= qbyte
& 0x0f;
732 dlen1
= (qbyte
>> 4) & 0xf;
735 for (i
= 0; i
< (dlen1
+1); i
++) {
739 r
= add_zoned(BAR
, dlen1
+1, AAR
, dlen2
+1);
740 PSR
&= 0xF8; /* HJS mod */
755 case 6: /* AZ: Add Zoned */
756 dlen2
= qbyte
& 0x0f;
757 dlen1
= (qbyte
>> 4) & 0xf;
759 r
= add_zoned(BAR
, dlen1
+1, AAR
, dlen2
+1);
778 case 7: /* SZ: Subtract Zoned */
779 dlen2
= qbyte
& 0x0f;
780 dlen1
= (qbyte
>> 4) & 0xf;
782 r
= subtract_zoned(BAR
, dlen1
+1, AAR
, dlen2
+1);
801 case 8: /* MVX: Move Hex */
805 case 0: /* Zone to zone */
806 op1
= (op1
& 0x0F) | (op2
& 0xF0);
808 case 1: /* Numeric to zone */
809 op1
= (op1
& 0x0F) | (op2
<< 4);
811 case 2: /* Zone to numeric */
812 op1
= (op1
& 0xF0) | (op2
>> 4);
814 case 3: /* Numeric to numeric */
815 op1
= (op1
& 0xF0) | (op2
& 0x0F);
823 case 0xa: /* ED: Edit */
827 if ((IR
& 0xf0) != 0xF0)
838 if (op2
!= 0xF0) zero
= 0;
846 case 0xb: /* ITC: Insert and Test Chars */
850 if (op1
>= 0xF1 && op1
<= 0xF9)
858 case 0xc: /* MVC: Move Characters */
860 PutMem(BAR
, GetMem(AAR
));
866 case 0xd: /* CLC: Compare Characters */
868 i
= BAR
= BAR
- qbyte
;
869 j
= AAR
= AAR
- qbyte
;
871 if (GetMem(i
) > GetMem(j
)) {
875 if (GetMem(i
) < GetMem(j
)) {
886 case 0xe: /* ALC: Add Logical Characters */
890 IR
= GetMem(BAR
) + GetMem(AAR
) + carry
;
895 if ((IR
& 0xFF) != 0) zero
= 0; /* HJS mod */
896 PutMem(BAR
,(IR
& 0xFF));
903 PSR
|= 0x01; /* Equal */
905 PSR
|= 0x02; /* Low */
907 PSR
|= 0x04; /* High */
909 PSR
|= 0x20; /* Overflow */
911 case 0xf: /* SLC: Subtract Logical Characters */
915 IR
= GetMem(BAR
) + (0xFF - GetMem(AAR
)) + carry
;
920 if ((IR
& 0xFF) != 0) zero
= 0; /* HJS mod */
921 PutMem(BAR
,(IR
& 0xFF));
928 PSR
|= 0x01; /* Equal */
930 PSR
|= 0x02; /* Low */
932 PSR
|= 0x04; /* High */
945 case 0: /* SNS: Sense I/O */
946 devno
= (qbyte
>> 4) & 0x0f;
947 devm
= (qbyte
>> 3) & 0x01;
949 i
= dev_table
[devno
].routine(3, devm
, devn
, rbyte
);
950 PutMem(BAR
, i
& 0xff);
952 PutMem(BAR
, (i
>> 8) & 0xff);
953 reason
= (i
>> 16) & 0xffff;
955 case 1: /* LIO: Load I/O */
956 devno
= (qbyte
>> 4) & 0x0f;
957 devm
= (qbyte
>> 3) & 0x01;
961 op1
|= (GetMem(BAR
) << 8) & 0xff00;
962 reason
= dev_table
[devno
].routine(1, devm
, devn
, op1
);
964 case 4: /* ST: Store Register */
967 PutMem(BAR
, XR1
& 0xff);
969 PutMem(BAR
, (XR1
>> 8) & 0xff);
972 PutMem(BAR
, XR2
& 0xff);
974 PutMem(BAR
, (XR2
>> 8) & 0xff);
977 PutMem(BAR
, PSR
& 0xFF);
979 PutMem(BAR
, 0); /* LCRR, not imp. */
982 PutMem(BAR
, ARR
[level
] & 0xff);
984 PutMem(BAR
, (ARR
[level
] >> 8) & 0xff);
987 PutMem(BAR
, IAR
[level
] & 0xff);
989 PutMem(BAR
, (IAR
[level
] >> 8) & 0xff);
992 PutMem(BAR
, IAR
[8] & 0xff);
994 PutMem(BAR
, (IAR
[8] >> 8) & 0xff);
997 PutMem(BAR
, IAR
[9] & 0xff);
999 PutMem(BAR
, (IAR
[9] >> 8) & 0xff);
1002 PutMem(BAR
, IAR
[0] & 0xff);
1004 PutMem(BAR
, (IAR
[0] >> 8) & 0xff);
1007 PutMem(BAR
, IAR
[7] & 0xff);
1009 PutMem(BAR
, (IAR
[7] >> 8) & 0xff);
1012 PutMem(BAR
, IAR
[6] & 0xff);
1014 PutMem(BAR
, (IAR
[6] >> 8) & 0xff);
1017 PutMem(BAR
, IAR
[5] & 0xff);
1019 PutMem(BAR
, (IAR
[5] >> 8) & 0xff);
1022 PutMem(BAR
, IAR
[4] & 0xff);
1024 PutMem(BAR
, (IAR
[4] >> 8) & 0xff);
1027 PutMem(BAR
, IAR
[3] & 0xff);
1029 PutMem(BAR
, (IAR
[3] >> 8) & 0xff);
1032 PutMem(BAR
, IAR
[2] & 0xff);
1034 PutMem(BAR
, (IAR
[2] >> 8) & 0xff);
1037 PutMem(BAR
, IAR
[1] & 0xff);
1039 PutMem(BAR
, (IAR
[1] >> 8) & 0xff);
1046 case 5: /* L: Load Register */
1049 XR1
= GetMem(BAR
) & 0xff;
1051 XR1
|= (GetMem(BAR
) << 8) & 0xff00;
1054 XR2
= GetMem(BAR
) & 0xff;
1056 XR2
|= (GetMem(BAR
) << 8) & 0xff00;
1059 PSR
= GetMem(BAR
) & 0xff;
1063 ARR
[level
] = GetMem(BAR
) & 0xff;
1065 ARR
[level
] |= (GetMem(BAR
) << 8) & 0xff00;
1068 IAR
[level
] = GetMem(BAR
) & 0xff;
1070 IAR
[level
] |= (GetMem(BAR
) << 8) & 0xff00;
1074 IAR
[8] = GetMem(BAR
) & 0xff;
1076 IAR
[8] |= (GetMem(BAR
) << 8) & 0xff00;
1079 IAR
[9] = GetMem(BAR
) & 0xff;
1081 IAR
[9] |= (GetMem(BAR
) << 8) & 0xff00;
1084 IAR
[0] = GetMem(BAR
) & 0xff;
1086 IAR
[0] |= (GetMem(BAR
) << 8) & 0xff00;
1089 IAR
[7] = GetMem(BAR
) & 0xff;
1091 IAR
[7] |= (GetMem(BAR
) << 8) & 0xff00;
1094 IAR
[6] = GetMem(BAR
) & 0xff;
1096 IAR
[6] |= (GetMem(BAR
) << 8) & 0xff00;
1099 IAR
[5] = GetMem(BAR
) & 0xff;
1101 IAR
[5] |= (GetMem(BAR
) << 8) & 0xff00;
1104 IAR
[4] = GetMem(BAR
) & 0xff;
1106 IAR
[4] |= (GetMem(BAR
) << 8) & 0xff00;
1109 IAR
[3] = GetMem(BAR
) & 0xff;
1111 IAR
[3] |= (GetMem(BAR
) << 8) & 0xff00;
1114 IAR
[2] = GetMem(BAR
) & 0xff;
1116 IAR
[2] |= (GetMem(BAR
) << 8) & 0xff00;
1119 IAR
[1] = GetMem(BAR
) & 0xff;
1121 IAR
[1] |= (GetMem(BAR
) << 8) & 0xff00;
1128 case 6: /* A: Add to Register */
1129 IR
= GetMem(BAR
) & 0x00ff;
1131 IR
|= (GetMem(BAR
) << 8) & 0xff00;
1147 ARR
[level
] = IR
& AMASK
;
1151 IAR
[level
] = IR
& AMASK
;
1155 IAR
[8] = IR
& AMASK
;
1159 IAR
[9] = IR
& AMASK
;
1163 IAR
[0] = IR
& AMASK
;
1167 IAR
[7] = IR
& AMASK
;
1171 IAR
[6] = IR
& AMASK
;
1175 IAR
[5] = IR
& AMASK
;
1179 IAR
[4] = IR
& AMASK
;
1183 IAR
[3] = IR
& AMASK
;
1187 IAR
[2] = IR
& AMASK
;
1191 IAR
[1] = IR
& AMASK
;
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 */
1205 PSR
|= 0x20; /* Bin overflow */
1207 case 8: /* TBN: Test Bits On */
1210 if ((IR
& qbyte
) != qbyte
)
1213 case 9: /* TBF: Test Bits Off */
1219 case 0xa: /* SBN: Set Bits On */
1224 case 0xb: /* SBF: Set Bits Off */
1229 case 0xc: /* MVI: Move Immediate */
1232 case 0xd: /* CLI: Compare Immediate */
1233 PSR
= compare(GetMem(BAR
), qbyte
, PSR
);
1236 reason
= STOP_INVOP
;
1246 case 0: /* BC: Branch on Condition */
1247 ARR
[level
] = AAR
& AMASK
;
1248 if (condition(qbyte
) == 1) {
1250 ARR
[level
] = PC
& AMASK
;
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
);
1260 ARR
[level
] = AAR
& AMASK
;
1262 ARR
[level
] = PC
& AMASK
;
1265 reason
= (op1
>> 16) & 0xffff;
1267 case 2: /* LA: Load Address */
1281 reason
= STOP_INVOP
;
1283 } /* switch (opcode) */
1288 reason
= STOP_INVOP
;
1290 } /* switch (opaddr) */
1292 } /* end while (reason == 0) */
1294 /* Simulation halted */
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.
1305 /* Fetch a byte from memory */
1307 int32
GetMem(int32 addr
)
1309 return M
[addr
] & 0xff;
1312 /* Place a byte in memory */
1314 int32
PutMem(int32 addr
, int32 data
)
1316 M
[addr
] = data
& 0xff;
1320 /* Check the condition register against the qbyte and return 1 if true */
1322 int32
condition(int32 qbyte
)
1325 t
= (qbyte
& 0xf0) >> 4;
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;
1332 /* these bits reset by a test */
1334 PSR
&= 0xEF; /* Reset test false if used */
1336 PSR
&= 0xF7; /* Reset decimal overflow if tested */
1338 r
= 1; /* unconditional branch */
1340 r
= 0; /* force no branch */
1341 if (t
>=0 && t
< 8 && (q
== 7 || q
== 0xf))
1343 if (t
> 7 && t
< 0x10 && (q
== 7 || q
== 0xf))
1344 r
= 1; /* Force branch */
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
1352 int32
compare(int32 byte1
, int32 byte2
, int32 cond
)
1356 r
= cond
& 0xF8; /* mask off all but unaffected bits 2,3,4 */
1358 r
|= 0x01; /* set equal bit */
1360 r
|= 0x02; /* set less-than bit */
1362 r
|= 0x04; /* set greater than bit */
1366 /*-------------------------------------------------------------------*/
1367 /* Add two zoned decimal operands */
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) */
1375 /* The return value is the condition code: */
1376 /* 0=result zero, 1=result -ve, 2=result +ve, 3=overflow */
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
)
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 */
1394 /* Load operands into work areas */
1395 load_decimal (addr1
, len1
, dec1
, &count1
, &sign1
);
1396 load_decimal (addr2
, len2
, dec2
, &count2
, &sign2
);
1398 /* Add or subtract operand values */
1401 /* If second operand is zero then result is first operand */
1402 memcpy (dec3
, dec1
, MAX_DECIMAL_DIGITS
);
1406 else if (count1
== 0)
1408 /* If first operand is zero then result is second operand */
1409 memcpy (dec3
, dec2
, MAX_DECIMAL_DIGITS
);
1413 else if (sign1
== sign2
)
1415 /* If signs are equal then add operands */
1416 add_decimal (dec1
, dec2
, dec3
, &count3
);
1421 /* If signs are opposite then subtract operands */
1422 subtract_decimal (dec1
, dec2
, dec3
, &count3
, &sign3
);
1423 if (sign1
< 0) sign3
= -sign3
;
1426 /* Set condition code */
1427 cc
= (count3
== 0) ? 0 : (sign3
< 1) ? 1 : 2;
1429 /* Overflow if result exceeds first operand length */
1433 /* Set positive sign if result is zero */
1437 /* Store result into first operand location */
1438 store_decimal (addr1
, len1
, dec3
, sign3
);
1440 /* Return condition code */
1443 } /* end function add_packed */
1445 /*-------------------------------------------------------------------*/
1446 /* Subtract two zoned decimal operands */
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) */
1454 /* The return value is the condition code: */
1455 /* 0=result zero, 1=result -ve, 2=result +ve, 3=overflow */
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
)
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 */
1473 /* Load operands into work areas */
1474 load_decimal (addr1
, len1
, dec1
, &count1
, &sign1
);
1475 load_decimal (addr2
, len2
, dec2
, &count2
, &sign2
);
1477 /* Add or subtract operand values */
1480 /* If second operand is zero then result is first operand */
1481 memcpy (dec3
, dec1
, MAX_DECIMAL_DIGITS
);
1485 else if (count1
== 0)
1487 /* If first operand is zero then result is -second operand */
1488 memcpy (dec3
, dec2
, MAX_DECIMAL_DIGITS
);
1492 else if (sign1
!= sign2
)
1494 /* If signs are opposite then add operands */
1495 add_decimal (dec1
, dec2
, dec3
, &count3
);
1500 /* If signs are equal then subtract operands */
1501 subtract_decimal (dec1
, dec2
, dec3
, &count3
, &sign3
);
1502 if (sign1
< 0) sign3
= -sign3
;
1505 /* Set condition code */
1506 cc
= (count3
== 0) ? 0 : (sign3
< 1) ? 1 : 2;
1508 /* Overflow if result exceeds first operand length */
1512 /* Set positive sign if result is zero */
1516 /* Store result into first operand location */
1517 store_decimal (addr1
, len1
, dec3
, sign3
);
1519 /* Return condition code */
1522 } /* end function subtract_packed */
1525 /*-------------------------------------------------------------------*/
1526 /* Add two decimal byte strings as unsigned decimal numbers */
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. */
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
)
1546 int d
; /* Decimal digit */
1547 int i
; /* Array subscript */
1548 int n
= 0; /* Significant digit counter */
1549 int carry
= 0; /* Carry indicator */
1551 /* Add digits from right to left */
1552 for (i
= MAX_DECIMAL_DIGITS
- 1; i
>= 0; i
--)
1554 /* Add digits from first and second operands */
1555 d
= dec1
[i
] + dec2
[i
] + carry
;
1557 /* Check for carry into next digit */
1565 /* Check for significant digit */
1567 n
= MAX_DECIMAL_DIGITS
- i
;
1569 /* Store digit in result */
1574 /* Check for carry out of leftmost digit */
1576 n
= MAX_DECIMAL_DIGITS
+ 1;
1578 /* Return significant digit counter */
1581 } /* end function add_decimal */
1583 /*-------------------------------------------------------------------*/
1584 /* Subtract two decimal byte strings as unsigned decimal numbers */
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. */
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
)
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 */
1613 /* Compare digits to find which operand has higher numeric value */
1614 rc
= memcmp (dec1
, dec2
, MAX_DECIMAL_DIGITS
);
1616 /* Return positive zero result if both operands are equal */
1618 memset (result
, 0, MAX_DECIMAL_DIGITS
);
1624 /* Point to higher and lower value operands and set sign */
1635 /* Subtract digits from right to left */
1636 for (i
= MAX_DECIMAL_DIGITS
- 1; i
>= 0; i
--)
1638 /* Subtract lower operand digit from higher operand digit */
1639 d
= higher
[i
] - lower
[i
] - borrow
;
1641 /* Check for borrow from next digit */
1649 /* Check for significant digit */
1651 n
= MAX_DECIMAL_DIGITS
- i
;
1653 /* Store digit in result */
1658 /* Return significant digit counter */
1661 } /* end function subtract_decimal */
1663 /*-------------------------------------------------------------------*/
1664 /* Load a zoned decimal storage operand into a decimal byte string */
1667 /* addr Logical address of zoned decimal storage operand */
1668 /* len Length minus one of storage operand (range 0-15) */
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. */
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
)
1689 int h
; /* Hexadecimal digit */
1690 int i
, j
; /* Array subscripts */
1691 int n
; /* Significant digit counter */
1693 if ((GetMem(addr
) & 0xf0) == 0xD0)
1698 for (i
= MAX_DECIMAL_DIGITS
; i
> -1; i
--) {
1700 h
= GetMem(addr
) & 0x0f;
1711 } /* end function load_decimal */
1713 /*-------------------------------------------------------------------*/
1714 /* Store decimal byte string into packed decimal storage operand */
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. */
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
)
1730 int i
, j
, a
; /* Array subscripts */
1734 for (i
= MAX_DECIMAL_DIGITS
; i
> -1; i
--) {
1736 PutMem(a
, (dec
[i
-1] | 0xf0));
1744 PutMem(addr
, (GetMem(addr
) & 0x0f));
1745 PutMem(addr
, (GetMem(addr
) | 0xf0));
1748 } /* end function store_decimal */
1750 /* CPU Device Control */
1752 int32
cpu (int32 op
, int32 m
, int32 n
, int32 data
)
1757 case 0x00: /* Start IO */
1759 case 0x01: /* LIO */
1761 case 0x02: /* TIO */
1763 case 0x03: /* SNS */
1764 /* SNS CPU gets the data switches */
1767 case 0x04: /* APL */
1772 return ((SCPE_OK
<< 16) | iodata
);
1779 int32
nulldev (int32 opcode
, int32 m
, int32 n
, int32 data
)
1782 return SCPE_OK
; /* Ok to LIO unconfigured devices? */
1788 t_stat
cpu_reset (DEVICE
*dptr
)
1792 sim_brk_types
= sim_brk_dflt
= SWMASK ('E');
1796 /* Memory examine */
1798 t_stat
cpu_ex (t_value
*vptr
, t_addr addr
, UNIT
*uptr
, int32 sw
)
1800 if (addr
>= MEMSIZE
) return SCPE_NXM
;
1801 if (vptr
!= NULL
) *vptr
= M
[addr
] & 0xff;
1805 /* Memory deposit */
1807 t_stat
cpu_dep (t_value val
, t_addr addr
, UNIT
*uptr
, int32 sw
)
1809 if (addr
>= MEMSIZE
) return SCPE_NXM
;
1810 M
[addr
] = val
& 0xff;
1814 t_stat
cpu_set_size (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
1819 if ((val
<= 0) || (val
> MAXMEMSIZE
) || ((val
& 07777) != 0))
1821 for (i
= val
; i
< MEMSIZE
; i
++) mc
= mc
| M
[i
];
1822 if ((mc
!= 0) && (!get_yn ("Really truncate memory [N]?", FALSE
)))
1825 for (i
= MEMSIZE
; i
< MAXMEMSIZE
; i
++) M
[i
] = 0;
1829 t_stat
cpu_boot (int32 unitno
, DEVICE
*dptr
)