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