1 /* i1401_cpu.c: IBM 1401 CPU simulator
3 Copyright (c) 1993-2007, Robert M. Supnik
5 Permission is hereby granted, free of charge, to any person obtaining a
6 copy of this software and associated documentation files (the "Software"),
7 to deal in the Software without restriction, including without limitation
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 and/or sell copies of the Software, and to permit persons to whom the
10 Software is furnished to do so, subject to the following conditions:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 Except as contained in this notice, the name of Robert M Supnik shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from Robert M Supnik.
26 07-Jul-07 RMS Removed restriction on load-mode binary tape
27 28-Jun-07 RMS Added support for SS overlap modifiers
28 22-May-06 RMS Fixed format error in CPU history (found by Peter Schorn)
29 06-Mar-06 RMS Fixed bug in divide (found by Van Snyder)
30 22-Sep-05 RMS Fixed declarations (from Sterling Garwood)
31 01-Sep-05 RMS Removed error stops in MCE
32 16-Aug-05 RMS Fixed C++ declaration and cast problems
33 02-Jun-05 RMS Fixed SSB-SSG clearing on RESET
34 (reported by Ralph Reinke)
35 14-Nov-04 WVS Added column binary support, debug support
36 06-Nov-04 RMS Added instruction history
37 12-Jul-03 RMS Moved ASCII/BCD tables to included file
38 Revised fetch to model hardware
39 Removed length checking in fetch phase
40 16-Mar-03 RMS Fixed mnemonic, instruction lengths, and reverse
41 scan length check bug for MCS
42 Fixed MCE bug, BS off by 1 if zero suppress
43 Fixed chaining bug, D lost if return to SCP
44 Fixed H branch, branch occurs after continue
45 Added check for invalid 8 character MCW, LCA
46 03-Jun-03 RMS Added 1311 support
47 22-May-02 RMS Added multiply and divide
48 30-Dec-01 RMS Added old PC queue
49 30-Nov-01 RMS Added extended SET/SHOW support
50 10-Aug-01 RMS Removed register in declarations
51 07-Dec-00 RMS Fixed bugs found by Charles Owen
52 -- 4,7 char NOPs are legal
53 -- 1 char B is chained BCE
54 -- MCE moves whole char after first
55 14-Apr-99 RMS Changed t_addr to unsigned
57 The register state for the IBM 1401 is:
59 IS I storage address register (PC)
60 AS A storage address register (address of first operand)
61 BS B storage address register (address of second operand)
67 The IBM 1401 is a variable instruction length, decimal data system.
68 Memory consists of 4000, 8000, 12000, or 16000 BCD characters, each
69 containing six bits of data and a word mark. There are no general
70 registers; all instructions are memory to memory, using explicit
71 addresses or an address pointer from a prior instruction.
73 BCD numeric data consists of the low four bits of a character (DIGIT),
74 encoded as X, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, X, X, X, X, X. The high
75 two bits (ZONE) encode the sign of the data as +, +, -, +. Character
76 data uses all six bits of a character. Numeric and character fields are
77 delimited by a word mark. Fields are typically processed in descending
78 address order (low-order data to high-order data).
80 The 1401 encodes a decimal address, and an index register number, in
84 addr + 0 <1:0> of thousands hundreds
85 addr + 1 index register # tens
86 addr + 2 <3:2> of thousands ones
88 Normally the digit values 0, 11, 12, 13, 14, 15 are illegal in addresses.
89 However, in indexing, digits are passed through the adder, and illegal
90 values are normalized to legal counterparts.
92 The 1401 has six instruction formats:
94 op A and B addresses, if any, from AS and BS
95 op d A and B addresses, if any, from AS and BS
96 op aaa B address, if any, from BS
97 op aaa d B address, if any, from BS
101 where aaa is the A address, bbb is the B address, and d is a modifier.
102 The opcode has word mark set; all other characters have word mark clear.
104 This routine is the instruction decode routine for the IBM 1401.
105 It is called from the simulator control program to execute
106 instructions in simulated memory, starting at the simulated PC.
107 It runs until 'reason' is set non-zero.
111 1. Reasons to stop. The simulator can be stopped by:
114 breakpoint encountered
115 illegal addresses or instruction formats
116 I/O error in I/O simulator
118 2. Interrupts. The 1401 has no interrupt structure.
120 3. Non-existent memory. On the 1401, references to non-existent
121 memory halt the processor.
123 4. Adding I/O devices. These modules must be modified:
125 i1401_cpu.c add device dispatching code to iodisp
126 i1401_sys.c add sim_devices table entry
129 #include "i1401_defs.h"
130 #include "i1401_dat.h"
132 #define PCQ_SIZE 64 /* must be 2**n */
133 #define PCQ_MASK (PCQ_SIZE - 1)
134 #define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = saved_IS
137 #define HIST_MAX 65536
145 /* These macros validate addresses. If an addresses error is detected,
146 they return an error status to the caller. These macros should only
147 be used in a routine that returns a t_stat value.
150 #define MM(x) x = x - 1; \
152 x = BA + MAXMEMSIZE - 1; \
153 reason = STOP_WRAP; \
157 #define PP(x) x = x + 1; \
158 if (ADDR_ERR (x)) { \
159 x = BA + (x % MAXMEMSIZE); \
160 reason = STOP_WRAP; \
164 #define BRANCH if (ADDR_ERR (AS)) { \
165 reason = STOP_INVBR; \
168 if (cpu_unit.flags & XSA) BS = IS; \
173 uint8 M
[MAXMEMSIZE
] = { 0 }; /* main memory */
174 int32 saved_IS
= 0; /* saved IS */
175 int32 AS
= 0; /* AS */
176 int32 BS
= 0; /* BS */
177 int32 D
= 0; /* modifier */
178 int32 as_err
= 0, bs_err
= 0; /* error flags */
179 int32 hb_pend
= 0; /* halt br pending */
180 uint16 pcq
[PCQ_SIZE
] = { 0 }; /* PC queue */
181 int32 pcq_p
= 0; /* PC queue ptr */
182 REG
*pcq_r
= NULL
; /* PC queue reg ptr */
183 int32 ind
[64] = { 0 }; /* indicators */
184 int32 ssa
= 1; /* sense switch A */
185 int32 prchk
= 0; /* process check stop */
186 int32 iochk
= 0; /* I/O check stop */
187 int32 hst_p
= 0; /* history pointer */
188 int32 hst_lnt
= 0; /* history length */
189 InstHistory
*hst
= NULL
; /* instruction history */
190 t_bool conv_old
= 0; /* old conversions */
192 extern int32 sim_int_char
;
193 extern int32 sim_emax
;
194 extern t_value
*sim_eval
;
195 extern FILE *sim_deb
;
196 extern uint32 sim_brk_types
, sim_brk_dflt
, sim_brk_summ
; /* breakpoint info */
198 t_stat
cpu_ex (t_value
*vptr
, t_addr addr
, UNIT
*uptr
, int32 sw
);
199 t_stat
cpu_dep (t_value val
, t_addr addr
, UNIT
*uptr
, int32 sw
);
200 t_stat
cpu_reset (DEVICE
*dptr
);
201 t_stat
cpu_set_size (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
);
202 t_stat
cpu_set_hist (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
);
203 t_stat
cpu_show_hist (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
);
204 t_stat
cpu_set_conv (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
);
205 t_stat
cpu_show_conv (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
);
206 int32
store_addr_h (int32 addr
);
207 int32
store_addr_t (int32 addr
);
208 int32
store_addr_u (int32 addr
);
209 int32
div_add (int32 ap
, int32 bp
, int32 aend
);
210 int32
div_sub (int32 ap
, int32 bp
, int32 aend
);
211 void div_sign (int32 dvrc
, int32 dvdc
, int32 qp
, int32 rp
);
212 t_stat
iomod (int32 ilnt
, int32 mod
, const int32
*tptr
);
213 t_stat
iodisp (int32 dev
, int32 unit
, int32 flag
, int32 mod
);
215 extern t_stat
read_card (int32 ilnt
, int32 mod
);
216 extern t_stat
punch_card (int32 ilnt
, int32 mod
);
217 extern t_stat
select_stack (int32 mod
);
218 extern t_stat
carriage_control (int32 mod
);
219 extern t_stat
write_line (int32 ilnt
, int32 mod
);
220 extern t_stat
inq_io (int32 flag
, int32 mod
);
221 extern t_stat
mt_io (int32 unit
, int32 flag
, int32 mod
);
222 extern t_stat
dp_io (int32 fnc
, int32 flag
, int32 mod
);
223 extern t_stat
mt_func (int32 unit
, int32 mod
);
224 extern t_stat
sim_activate (UNIT
*uptr
, int32 delay
);
225 extern t_stat
fprint_sym (FILE *of
, t_addr addr
, t_value
*val
, UNIT
*uptr
, int32 sw
);
227 /* CPU data structures
229 cpu_dev CPU device descriptor
230 cpu_unit CPU unit descriptor
231 cpu_reg CPU register list
232 cpu_mod CPU modifier list
236 UDATA (NULL
, UNIT_FIX
+ UNIT_BCD
+ STDOPT
, MAXMEMSIZE
)
240 { DRDATA (IS
, saved_IS
, 14), PV_LEFT
},
241 { DRDATA (AS
, AS
, 14), PV_LEFT
},
242 { DRDATA (BS
, BS
, 14), PV_LEFT
},
243 { FLDATA (ASERR
, as_err
, 0) },
244 { FLDATA (BSERR
, bs_err
, 0) },
245 { ORDATA (D
, D
, 7) },
246 { FLDATA (SSA
, ssa
, 0) },
247 { FLDATA (SSB
, ind
[IN_SSB
], 0) },
248 { FLDATA (SSC
, ind
[IN_SSC
], 0) },
249 { FLDATA (SSD
, ind
[IN_SSD
], 0) },
250 { FLDATA (SSE
, ind
[IN_SSE
], 0) },
251 { FLDATA (SSF
, ind
[IN_SSF
], 0) },
252 { FLDATA (SSG
, ind
[IN_SSG
], 0) },
253 { FLDATA (EQU
, ind
[IN_EQU
], 0) },
254 { FLDATA (UNEQ
, ind
[IN_UNQ
], 0) },
255 { FLDATA (HIGH
, ind
[IN_HGH
], 0) },
256 { FLDATA (LOW
, ind
[IN_LOW
], 0) },
257 { FLDATA (OVF
, ind
[IN_OVF
], 0) },
258 { FLDATA (IOCHK
, iochk
, 0) },
259 { FLDATA (PRCHK
, prchk
, 0) },
260 { FLDATA (HBPEND
, hb_pend
, 0) },
261 { BRDATA (ISQ
, pcq
, 10, 14, PCQ_SIZE
), REG_RO
+REG_CIRC
},
262 { DRDATA (ISQP
, pcq_p
, 6), REG_HRO
},
263 { ORDATA (WRU
, sim_int_char
, 8) },
264 { FLDATA (CONVOLD
, conv_old
, 0), REG_HIDDEN
},
269 { XSA
, XSA
, "XSA", "XSA", NULL
},
270 { XSA
, 0, "no XSA", "NOXSA", NULL
},
271 { HLE
, HLE
, "HLE", "HLE", NULL
},
272 { HLE
, 0, "no HLE", "NOHLE", NULL
},
273 { BBE
, BBE
, "BBE", "BBE", NULL
},
274 { BBE
, 0, "no BBE", "NOBBE", NULL
},
275 { MA
, MA
, "MA", 0, NULL
},
276 { MA
, 0, "no MA", 0, NULL
},
277 { MR
, MR
, "MR", "MR", NULL
},
278 { MR
, 0, "no MR", "NOMR", NULL
},
279 { EPE
, EPE
, "EPE", "EPE", NULL
},
280 { EPE
, 0, "no EPE", "NOEPE", NULL
},
281 { MDV
, MDV
, "MDV", "MDV", NULL
},
282 { MDV
, 0, "no MDV", "NOMDV", NULL
},
283 { UNIT_MSIZE
, 4000, NULL
, "4K", &cpu_set_size
},
284 { UNIT_MSIZE
, 8000, NULL
, "8K", &cpu_set_size
},
285 { UNIT_MSIZE
, 12000, NULL
, "12K", &cpu_set_size
},
286 { UNIT_MSIZE
, 16000, NULL
, "16K", &cpu_set_size
},
287 { MTAB_XTD
|MTAB_VDV
|MTAB_NMO
|MTAB_SHP
, 0, "HISTORY", "HISTORY",
288 &cpu_set_hist
, &cpu_show_hist
},
289 { MTAB_XTD
|MTAB_VDV
|MTAB_NMO
, 0, "CONVERSIONS", "NEWCONVERSIONS",
290 &cpu_set_conv
, &cpu_show_conv
},
291 { MTAB_XTD
|MTAB_VDV
|MTAB_NMO
, 1, NULL
, "OLDCONVERSIONS",
292 &cpu_set_conv
, NULL
},
297 "CPU", &cpu_unit
, cpu_reg
, cpu_mod
,
299 &cpu_ex
, &cpu_dep
, &cpu_reset
,
306 /* Opcode table - length, dispatch, and option flags. This table is
307 used by the symbolic input routine to validate instruction lengths */
309 const int32 op_table
[64] = {
311 L1
| L2
| L4
| L5
, /* read */
312 L1
| L2
| L4
| L5
, /* write */
313 L1
| L2
| L4
| L5
, /* write and read */
314 L1
| L2
| L4
| L5
, /* punch */
315 L1
| L4
, /* read and punch */
316 L1
| L2
| L4
| L5
, /* write and read */
317 L1
| L2
| L4
| L5
, /* write, read, punch */
318 L1
, /* 10: read feed */
321 L1
| L4
| L7
| AREQ
| BREQ
| MA
, /* modify address */
322 L1
| L4
| L7
| AREQ
| BREQ
| MDV
, /* multiply */
327 L1
| L4
| L7
| BREQ
| NOWM
, /* clear storage */
328 L1
| L4
| L7
| AREQ
| BREQ
, /* subtract */
330 L5
| IO
, /* magtape */
331 L1
| L8
| BREQ
, /* branch wm or zone */
332 L1
| L8
| BREQ
| BBE
, /* branch if bit eq */
334 L1
| L4
| L7
| AREQ
| BREQ
, /* 30: move zones */
335 L1
| L4
| L7
| AREQ
| BREQ
, /* move supress zero */
337 L1
| L4
| L7
| AREQ
| BREQ
| NOWM
, /* set word mark */
338 L1
| L4
| L7
| AREQ
| BREQ
| MDV
, /* divide */
344 L2
| L5
, /* select stacker */
345 L1
| L4
| L7
| L8
| BREQ
| MLS
| IO
, /* load */
346 L1
| L4
| L7
| L8
| BREQ
| MLS
| IO
, /* move */
347 HNOP
| L1
| L2
| L4
| L5
| L7
| L8
, /* nop */
349 L1
| L4
| L7
| AREQ
| BREQ
| MR
, /* move to record */
350 L1
| L4
| AREQ
| MLS
, /* 50: store A addr */
352 L1
| L4
| L7
| AREQ
| BREQ
, /* zero and subtract */
359 L1
| L4
| L7
| AREQ
| BREQ
, /* add */
360 L1
| L4
| L5
| L8
, /* branch */
361 L1
| L4
| L7
| AREQ
| BREQ
, /* compare */
362 L1
| L4
| L7
| AREQ
| BREQ
, /* move numeric */
363 L1
| L4
| L7
| AREQ
| BREQ
, /* move char edit */
364 L2
| L5
, /* carriage control */
366 L1
| L4
| L7
| AREQ
| MLS
, /* 70: store B addr */
368 L1
| L4
| L7
| AREQ
| BREQ
, /* zero and add */
369 HNOP
| L1
| L2
| L4
| L5
| L7
| L8
, /* halt */
370 L1
| L4
| L7
| AREQ
| BREQ
, /* clear word mark */
376 const int32 len_table
[9] = { 0, L1
, L2
, 0, L4
, L5
, 0, L7
, L8
};
378 /* Address character conversion tables. Illegal characters are marked by
379 the flag BA but also contain the post-adder value for indexing */
381 const int32 hun_table
[64] = {
382 BA
+000, 100, 200, 300, 400, 500, 600, 700,
383 800, 900, 000, BA
+300, BA
+400, BA
+500, BA
+600, BA
+700,
384 BA
+1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700,
385 1800, 1900, 1000, BA
+1300, BA
+1400, BA
+1500, BA
+1600, BA
+1700,
386 BA
+2000, 2100, 2200, 2300, 2400, 2500, 2600, 2700,
387 2800, 2900, 2000, BA
+2300, BA
+2400, BA
+2500, BA
+2600, BA
+2700,
388 BA
+3000, 3100, 3200, 3300, 3400, 3500, 3600, 3700,
389 3800, 3900, 3000, BA
+3300, BA
+3400, BA
+3500, BA
+3600, BA
+3700
392 const int32 ten_table
[64] = {
393 BA
+00, 10, 20, 30, 40, 50, 60, 70,
394 80, 90, 00, BA
+30, BA
+40, BA
+50, BA
+60, BA
+70,
395 X1
+00, X1
+10, X1
+20, X1
+30, X1
+40, X1
+50, X1
+60, X1
+70,
396 X1
+80, X1
+90, X1
+00, X1
+30, X1
+40, X1
+50, X1
+60, X1
+70,
397 X2
+00, X2
+10, X2
+20, X2
+30, X2
+40, X2
+50, X2
+60, X2
+70,
398 X2
+80, X2
+90, X2
+00, X2
+30, X2
+40, X2
+50, X2
+60, X2
+70,
399 X3
+00, X3
+10, X3
+20, X3
+30, X3
+40, X3
+50, X3
+60, X3
+70,
400 X3
+80, X3
+90, X3
+00, X3
+30, X3
+40, X3
+50, X3
+60, X3
+70
403 const int32 one_table
[64] = {
404 BA
+0, 1, 2, 3, 4, 5, 6, 7,
405 8, 9, 0, BA
+3, BA
+4, BA
+5, BA
+6, BA
+7,
406 BA
+4000, 4001, 4002, 4003, 4004, 4005, 4006, 4007,
407 4008, 4009, 4000, BA
+4003, BA
+4004, BA
+4005, BA
+4006, BA
+4007,
408 BA
+8000, 8001, 8002, 8003, 8004, 8005, 8006, 8007,
409 8008, 8009, 8000, BA
+8003, BA
+8004, BA
+8005, BA
+8006, BA
+8007,
410 BA
+12000, 12001, 12002, 12003, 12004, 12005, 12006, 12007,
411 12008, 12009, 12000, BA
+12003, BA
+12004, BA
+12005, BA
+12006, BA
+12007
414 const int32 bin_to_bcd
[16] = {
415 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
418 const int32 bcd_to_bin
[16] = {
419 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 3, 4, 5, 6, 7
422 /* Indicator resets - a 1 marks an indicator that resets when tested */
424 static const int32 ind_table
[64] = {
425 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 07 */
426 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 17 */
427 0, 0, 0, 0, 0, 0, 0, 0, /* 20 - 27 */
428 0, 1, 1, 0, 1, 0, 0, 0, /* 30 - 37 */
429 0, 0, 1, 0, 0, 0, 0, 0, /* 40 - 47 */
430 0, 0, 1, 0, 1, 0, 0, 0, /* 50 - 57 */
431 0, 0, 0, 0, 0, 0, 0, 0, /* 60 - 67 */
432 0, 0, 1, 0, 0, 0, 0, 0 /* 70 - 77 */
435 /* Character collation table for compare with HLE option */
437 static const int32 col_table
[64] = {
438 000, 067, 070, 071, 072, 073, 074, 075,
439 076, 077, 066, 024, 025, 026, 027, 030,
440 023, 015, 056, 057, 060, 061, 062, 063,
441 064, 065, 055, 016, 017, 020, 021, 022,
442 014, 044, 045, 046, 047, 050, 051, 052,
443 053, 054, 043, 007, 010, 011, 012, 013,
444 006, 032, 033, 034, 035, 036, 037, 040,
445 041, 042, 031, 001, 002, 003, 004, 005
448 /* Summing table for two decimal digits, converted back to BCD
449 Also used for multiplying two decimal digits, converted back to BCD,
453 static const int32 sum_table
[100] = {
454 BCD_ZERO
, BCD_ONE
, BCD_TWO
, BCD_THREE
, BCD_FOUR
,
455 BCD_FIVE
, BCD_SIX
, BCD_SEVEN
, BCD_EIGHT
, BCD_NINE
,
456 BCD_ZERO
, BCD_ONE
, BCD_TWO
, BCD_THREE
, BCD_FOUR
,
457 BCD_FIVE
, BCD_SIX
, BCD_SEVEN
, BCD_EIGHT
, BCD_NINE
,
458 BCD_ZERO
, BCD_ONE
, BCD_TWO
, BCD_THREE
, BCD_FOUR
,
459 BCD_FIVE
, BCD_SIX
, BCD_SEVEN
, BCD_EIGHT
, BCD_NINE
,
460 BCD_ZERO
, BCD_ONE
, BCD_TWO
, BCD_THREE
, BCD_FOUR
,
461 BCD_FIVE
, BCD_SIX
, BCD_SEVEN
, BCD_EIGHT
, BCD_NINE
,
462 BCD_ZERO
, BCD_ONE
, BCD_TWO
, BCD_THREE
, BCD_FOUR
,
463 BCD_FIVE
, BCD_SIX
, BCD_SEVEN
, BCD_EIGHT
, BCD_NINE
,
464 BCD_ZERO
, BCD_ONE
, BCD_TWO
, BCD_THREE
, BCD_FOUR
,
465 BCD_FIVE
, BCD_SIX
, BCD_SEVEN
, BCD_EIGHT
, BCD_NINE
,
466 BCD_ZERO
, BCD_ONE
, BCD_TWO
, BCD_THREE
, BCD_FOUR
,
467 BCD_FIVE
, BCD_SIX
, BCD_SEVEN
, BCD_EIGHT
, BCD_NINE
,
468 BCD_ZERO
, BCD_ONE
, BCD_TWO
, BCD_THREE
, BCD_FOUR
,
469 BCD_FIVE
, BCD_SIX
, BCD_SEVEN
, BCD_EIGHT
, BCD_NINE
,
470 BCD_ZERO
, BCD_ONE
, BCD_TWO
, BCD_THREE
, BCD_FOUR
,
471 BCD_FIVE
, BCD_SIX
, BCD_SEVEN
, BCD_EIGHT
, BCD_NINE
,
472 BCD_ZERO
, BCD_ONE
, BCD_TWO
, BCD_THREE
, BCD_FOUR
,
473 BCD_FIVE
, BCD_SIX
, BCD_SEVEN
, BCD_EIGHT
, BCD_NINE
476 static const int32 cry_table
[100] = {
477 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
478 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
479 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
480 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
481 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
482 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
483 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
484 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
485 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
486 9, 9, 9, 9, 9, 9, 9, 9, 9, 9
489 /* Legal modifier tables */
491 static const int32 r_mod
[] = { BCD_C
, -1 };
492 static const int32 p_mod
[] = { BCD_C
, -1 };
493 static const int32 w_mod
[] = { BCD_S
, BCD_SQUARE
, -1 };
494 static const int32 ss_mod
[] = { BCD_ONE
, BCD_TWO
, BCD_FOUR
, BCD_EIGHT
,
495 BCD_DOLLAR
, BCD_DECIMAL
, BCD_SQUARE
, -1 };
496 static const int32 mtf_mod
[] = { BCD_B
, BCD_E
, BCD_M
, BCD_R
, BCD_U
, -1 };
498 t_stat
sim_instr (void)
500 extern int32 sim_interval
;
501 int32 IS
, ilnt
, flags
;
502 int32 op
, xa
, t
, wm
, ioind
, dev
, unit
;
503 int32 a
, b
, i
, k
, asave
, bsave
;
504 int32 carry
, lowprd
, sign
, ps
;
505 int32 quo
, ahigh
, qs
;
506 int32 qzero
, qawm
, qbody
, qsign
, qdollar
, qaster
, qdecimal
;
507 t_stat reason
, r1
, r2
;
509 /* Restore saved state */
512 if (as_err
) AS
= AS
| BA
; /* flag bad addresses */
513 if (bs_err
) BS
= BS
| BA
;
514 as_err
= bs_err
= 0; /* reset error flags */
517 /* Main instruction fetch/decode loop */
519 while (reason
== 0) { /* loop until halted */
521 if (hb_pend
) { /* halt br pending? */
522 hb_pend
= 0; /* clear flag */
523 BRANCH
; /* execute branch */
526 saved_IS
= IS
; /* commit prev instr */
527 if (sim_interval
<= 0) { /* check clock queue */
528 if (reason
= sim_process_event ()) break;
531 if (sim_brk_summ
&& sim_brk_test (IS
, SWMASK ('E'))) { /* breakpoint? */
532 reason
= STOP_IBKPT
; /* stop simulation */
536 sim_interval
= sim_interval
- 1;
538 /* Instruction fetch - 1401 fetch works as follows:
540 - Each character fetched enters the B register. This register is not
541 visible; the variable t represents the B register.
542 - Except for the first and last cycles, each character fetched enters
543 the A register. This register is not visible; the variable D represents
544 the A register, because this is the instruction modifier for 2, 5, and 8
545 character instructions.
546 - At the start of the second cycle (first address character), the A-address
547 register and, for most instructions, the B-address register, are cleared
548 to blanks. The simulator represents addresses in binary and creates the
549 effect of blanks (address is bad) if less than three A-address characters
550 are found. Further, the simulator accumulates only the A-address, and
551 replicates it to the B-address at the appropriate point.
552 - At the start of the fifth cycle (fourth address character), the B-address
553 register is cleared to blanks. Again, the simulator creates the effect of
554 blanks (address is bad) if less than three B-address characters are found.
556 The 1401 does not explicitly check for valid instruction lengths. Most 2,
557 3, 5, 6 character instructions will be invalid because the A-address or
558 B-address (or both) are invalid.
561 if ((M
[IS
] & WM
) == 0) { /* I-Op: WM under op? */
562 reason
= STOP_NOWM
; /* no, error */
565 op
= M
[IS
] & CHAR
; /* get opcode */
566 flags
= op_table
[op
]; /* get op flags */
567 if ((flags
== 0) || (flags
& ALLOPT
& ~cpu_unit
.flags
)) {
568 reason
= STOP_NXI
; /* illegal inst? */
571 if (op
== OP_SAR
) BS
= AS
; /* SAR? save ASTAR */
574 if ((t
= M
[IS
]) & WM
) goto CHECK_LENGTH
; /* I-1: WM? 1 char inst */
575 D
= ioind
= t
; /* could be D char, % */
576 AS
= hun_table
[t
]; /* could be A addr */
577 PP (IS
); /* if %xy, BA is set */
579 if ((t
= M
[IS
]) & WM
) { /* I-2: WM? 2 char inst */
580 AS
= AS
| BA
; /* ASTAR bad */
581 if (!(flags
& MLS
)) BS
= AS
;
584 D
= dev
= t
; /* could be D char, dev */
585 AS
= AS
+ ten_table
[t
]; /* build A addr */
588 if ((t
= M
[IS
]) & WM
) { /* I-3: WM? 3 char inst */
589 AS
= AS
| BA
; /* ASTAR bad */
590 if (!(flags
& MLS
)) BS
= AS
;
593 D
= unit
= t
; /* could be D char, unit */
594 if (unit
== BCD_ZERO
) unit
= 0; /* convert unit to binary */
595 AS
= AS
+ one_table
[t
]; /* finish A addr */
596 xa
= (AS
>> V_INDEX
) & M_INDEX
; /* get index reg */
597 if (xa
&& (ioind
!= BCD_PERCNT
) && (cpu_unit
.flags
& XSA
)) { /* indexed? */
598 AS
= AS
+ hun_table
[M
[xa
] & CHAR
] + ten_table
[M
[xa
+ 1] & CHAR
] +
599 one_table
[M
[xa
+ 2] & CHAR
];
600 AS
= (AS
& INDEXMASK
) % MAXMEMSIZE
;
602 if (!(flags
& MLS
)) BS
= AS
; /* not MLS? B = A */
605 if ((t
= M
[IS
]) & WM
) goto CHECK_LENGTH
; /* I-4: WM? 4 char inst */
606 if ((op
== OP_B
) && (t
== BCD_BLANK
)) /* BR + space? */
608 D
= t
; /* could be D char */
609 BS
= hun_table
[t
]; /* could be B addr */
612 if ((t
= M
[IS
]) & WM
) { /* I-5: WM? 5 char inst */
613 BS
= BS
| BA
; /* BSTAR bad */
616 D
= t
; /* could be D char */
617 BS
= BS
+ ten_table
[t
]; /* build B addr */
620 if ((t
= M
[IS
]) & WM
) { /* I-6: WM? 6 char inst */
621 BS
= BS
| BA
; /* BSTAR bad */
624 D
= t
; /* could be D char */
625 BS
= BS
+ one_table
[t
]; /* finish B addr */
626 xa
= (BS
>> V_INDEX
) & M_INDEX
; /* get index reg */
627 if (xa
&& (cpu_unit
.flags
& XSA
)) { /* indexed? */
628 BS
= BS
+ hun_table
[M
[xa
] & CHAR
] + ten_table
[M
[xa
+ 1] & CHAR
] +
629 one_table
[M
[xa
+ 2] & CHAR
];
630 BS
= (BS
& INDEXMASK
) % MAXMEMSIZE
;
634 if (flags
& NOWM
) goto CHECK_LENGTH
; /* I-7: SWM? done */
635 if ((t
= M
[IS
]) & WM
) goto CHECK_LENGTH
; /* WM? 7 char inst */
636 D
= t
; /* last char is D */
637 while (((t
= M
[IS
]) & WM
) == 0) { /* I-8: repeats until WM */
638 D
= t
; /* last char is D */
641 if (reason
) break; /* addr err on last? */
644 if ((flags
& BREQ
) && ADDR_ERR (BS
)) { /* valid B? */
648 if ((flags
& AREQ
) && ADDR_ERR (AS
)) { /* valid A? */
652 ilnt
= IS
- saved_IS
; /* get lnt */
653 if (hst_lnt
) { /* history enabled? */
654 hst_p
= (hst_p
+ 1); /* next entry */
655 if (hst_p
>= hst_lnt
) hst_p
= 0;
656 hst
[hst_p
].is
= saved_IS
; /* save IS */
657 hst
[hst_p
].ilnt
= ilnt
;
658 for (i
= 0; (i
< MAX_L
) && (i
< ilnt
); i
++)
659 hst
[hst_p
].inst
[i
] = M
[saved_IS
+ i
];
661 if (DEBUG_PRS (cpu_dev
)) {
662 fprint_val (sim_deb
, saved_IS
, 10, 5, PV_RSPC
);
663 fprintf (sim_deb
, ": " );
664 for (i
= 0; i
< sim_emax
; i
++) sim_eval
[i
] = 0;
665 for (i
= 0, k
= saved_IS
; i
< sim_emax
; i
++, k
++) {
666 if (cpu_ex (&sim_eval
[i
], k
, &cpu_unit
, 0) != SCPE_OK
) break;
668 fprint_sym (sim_deb
, saved_IS
, sim_eval
, &cpu_unit
, SWMASK('M'));
669 fprintf (sim_deb
, "\n" );
671 switch (op
) { /* case on opcode */
673 /* Move/load character instructions A check B check
675 MCW copy A to B, preserving B WM, here fetch
676 until either A or B WM
677 LCA copy A to B, overwriting B WM, here fetch
683 2,3 invalid A-address
685 5,6 invalid B-address
690 case OP_MCW
: /* move char */
691 if ((ilnt
>= 4) && (ioind
== BCD_PERCNT
)) { /* I/O form? */
692 reason
= iodisp (dev
, unit
, MD_NORM
, D
); /* dispatch I/O */
695 if (ADDR_ERR (AS
)) { /* check A addr */
701 M
[BS
] = (M
[BS
] & WM
) | (M
[AS
] & CHAR
); /* move char */
702 MM (AS
); /* decr pointers */
704 } while ((wm
& WM
) == 0); /* stop on A,B WM */
707 case OP_LCA
: /* load char */
708 if ((ilnt
>= 4) && (ioind
== BCD_PERCNT
)) { /* I/O form? */
709 reason
= iodisp (dev
, unit
, MD_WM
, D
);
712 if (ADDR_ERR (AS
)) { /* check A addr */
717 wm
= M
[BS
] = M
[AS
]; /* move char + wmark */
718 MM (AS
); /* decr pointers */
720 } while ((wm
& WM
) == 0); /* stop on A WM */
723 /* Other move instructions A check B check
725 MCM copy A to B, preserving B WM, fetch fetch
726 until record or group mark
727 MCS copy A to B, clearing B WM, until A WM; fetch fetch
728 reverse scan and suppress leading zeroes
729 MN copy A char digit to B char digit, fetch fetch
730 preserving B zone and WM
731 MZ copy A char zone to B char zone, fetch fetch
732 preserving B digit and WM
737 2,3 invalid A-address
738 4 self (B-address = A-address)
739 5,6 invalid B-address
741 8+ normal + ignored modifier
744 case OP_MCM
: /* move to rec/group */
747 M
[BS
] = (M
[BS
] & WM
) | (M
[AS
] & CHAR
); /* move char */
748 PP (AS
); /* incr pointers */
750 } while (((t
& CHAR
) != BCD_RECMRK
) && (t
!= (BCD_GRPMRK
+ WM
)));
753 case OP_MCS
: /* move suppress zero */
754 bsave
= BS
; /* save B start */
755 qzero
= 1; /* set suppress */
758 M
[BS
] = M
[AS
] & ((BS
!= bsave
)? CHAR
: DIGIT
);/* copy char */
759 MM (AS
); MM (BS
); /* decr pointers */
760 } while ((wm
& WM
) == 0); /* stop on A WM */
761 if (reason
) break; /* addr err? stop */
764 t
= M
[BS
]; /* get B, cant be WM */
765 if ((t
== BCD_ZERO
) || (t
== BCD_COMMA
)) {
766 if (qzero
) M
[BS
] = 0;
768 else if ((t
== BCD_BLANK
) || (t
== BCD_MINUS
)) ;
769 else if (((t
== BCD_DECIMAL
) && (cpu_unit
.flags
& EPE
)) ||
770 (t
<= BCD_NINE
)) qzero
= 0;
772 } while (BS
< bsave
);
773 PP (BS
); /* BS end is B+1 */
776 case OP_MN
: /* move numeric */
777 M
[BS
] = (M
[BS
] & ~DIGIT
) | (M
[AS
] & DIGIT
); /* move digit */
778 MM (AS
); /* decr pointers */
782 case OP_MZ
: /* move zone */
783 M
[BS
] = (M
[BS
] & ~ZONE
) | (M
[AS
] & ZONE
); /* move high bits */
784 MM (AS
); /* decr pointers */
788 /* Branch instruction A check B check
792 1 branch if B char equals d, chained if branch here
793 2,3 invalid B-address if branch here
794 4 unconditional branch if branch
795 5 branch if indicator[d] is set if branch
796 6 invalid B-address if branch here
797 7 branch if B char equals d, if branch here
798 d is last character of B-address
799 8 branch if B char equals d if branch here
802 case OP_B
: /* branch */
803 if (ilnt
== 4) { BRANCH
; } /* uncond branch? */
804 else if (ilnt
== 5) { /* branch on ind? */
805 if (ind
[D
]) { BRANCH
; } /* test indicator */
806 if (ind_table
[D
]) ind
[D
] = 0; /* reset if needed */
808 else { /* branch char eq */
809 if (ADDR_ERR (BS
)) { /* validate B addr */
813 if ((M
[BS
] & CHAR
) == D
) { BRANCH
; } /* char equal? */
818 /* Other branch instructions A check B check
820 BWZ branch if (d<0>: B char WM) if branch fetch
821 (d<1>: B char zone = d zone)
822 BBE branch if B char & d non-zero if branch fetch
826 2,3 invalid A-address and B-address
827 4 self (B-address = A-address, d = last character of A-address)
828 5,6 invalid B-address
829 7 normal, d = last character of B-address
833 case OP_BWZ
: /* branch wm or zone */
834 if (((D
& 1) && (M
[BS
] & WM
)) || /* d1? test wm */
835 ((D
& 2) && ((M
[BS
] & ZONE
) == (D
& ZONE
)))) /* d2? test zone */
837 else { MM (BS
); } /* decr pointer */
840 case OP_BBE
: /* branch if bit eq */
841 if (M
[BS
] & D
& CHAR
) { BRANCH
; } /* any bits set? */
842 else { MM (BS
); } /* decr pointer */
845 /* Arithmetic instructions A check B check
847 ZA move A to B, normalizing A sign, fetch fetch
848 preserving B WM, until B WM
849 ZS move A to B, complementing A sign, fetch fetch
850 preserving B WM, until B WM
851 A add A to B fetch fetch
852 S subtract A from B fetch fetch
853 C compare A to B fetch fetch
858 2,3 invalid A-address
859 4 self (B-address = A-address)
860 5,6 invalid B-address
862 8+ normal + ignored modifier
865 case OP_ZA
: case OP_ZS
: /* zero and add/sub */
866 a
= i
= 0; /* clear flags */
868 if (a
& WM
) wm
= M
[BS
] = (M
[BS
] & WM
) | BCD_ZERO
;
870 a
= M
[AS
]; /* get A char */
871 t
= (a
& CHAR
)? bin_to_bcd
[a
& DIGIT
]: 0;
872 wm
= M
[BS
] = (M
[BS
] & WM
) | t
; /* move digit */
875 if (i
== 0) i
= M
[BS
] = M
[BS
] |
876 ((((a
& ZONE
) == BBIT
) ^ (op
== OP_ZS
))? BBIT
: ZONE
);
878 } while ((wm
& WM
) == 0); /* stop on B WM */
881 case OP_A
: case OP_S
: /* add/sub */
882 bsave
= BS
; /* save sign pos */
883 a
= M
[AS
]; /* get A digit/sign */
884 b
= M
[BS
]; /* get B digit/sign */
886 qsign
= ((a
& ZONE
) == BBIT
) ^ ((b
& ZONE
) == BBIT
) ^ (op
== OP_S
);
887 t
= bcd_to_bin
[a
& DIGIT
]; /* get A binary */
888 t
= bcd_to_bin
[b
& DIGIT
] + (qsign
? 10 - t
: t
); /* sum A + B */
889 carry
= (t
>= 10); /* get carry */
890 b
= (b
& ~DIGIT
) | sum_table
[t
]; /* get result */
891 if (qsign
&& ((b
& BBIT
) == 0)) b
= b
| ZONE
; /* normalize sign */
892 M
[BS
] = b
; /* store result */
894 if (b
& WM
) { /* b wm? done */
895 if (qsign
&& (carry
== 0)) M
[bsave
] = /* compl, no carry? */
896 WM
+ ((b
& ZONE
) ^ ABIT
) + sum_table
[10 - t
];
900 if (a
& WM
) a
= WM
; /* A WM? char = 0 */
902 a
= M
[AS
]; /* else get A */
905 b
= M
[BS
]; /* get B */
906 t
= bcd_to_bin
[a
& DIGIT
]; /* get A binary */
907 t
= bcd_to_bin
[b
& DIGIT
] + (qsign
? 9 - t
: t
) + carry
;
908 carry
= (t
>= 10); /* get carry */
909 if ((b
& WM
) && (qsign
== 0)) { /* last, no recomp? */
910 M
[BS
] = WM
+ sum_table
[t
] + /* zone add */
911 (((a
& ZONE
) + b
+ (carry
? ABIT
: 0)) & ZONE
);
912 ind
[IN_OVF
] = carry
; /* ovflo if carry */
914 else M
[BS
] = (b
& WM
) + sum_table
[t
]; /* normal add */
916 } while ((b
& WM
) == 0); /* stop on B WM */
917 if (reason
) break; /* address err? */
918 if (qsign
&& (carry
== 0)) { /* recompl, no carry? */
919 M
[bsave
] = M
[bsave
] ^ ABIT
; /* XOR sign */
920 for (carry
= 1; bsave
!= BS
; --bsave
) { /* rescan */
921 t
= 9 - bcd_to_bin
[M
[bsave
] & DIGIT
] + carry
;
923 M
[bsave
] = (M
[bsave
] & ~DIGIT
) | sum_table
[t
];
928 case OP_C
: /* compare */
929 if (ilnt
!= 1) { /* if not chained */
930 ind
[IN_EQU
] = 1; /* clear indicators */
931 ind
[IN_UNQ
] = ind
[IN_HGH
] = ind
[IN_LOW
] = 0;
934 a
= M
[AS
]; /* get characters */
936 wm
= a
| b
; /* get word marks */
937 if ((a
& CHAR
) != (b
& CHAR
)) { /* unequal? */
938 ind
[IN_EQU
] = 0; /* set indicators */
940 ind
[IN_HGH
] = col_table
[b
& CHAR
] > col_table
[a
& CHAR
];
941 ind
[IN_LOW
] = ind
[IN_HGH
] ^ 1;
943 MM (AS
); MM (BS
); /* decr pointers */
944 } while ((wm
& WM
) == 0); /* stop on A, B WM */
945 if ((a
& WM
) && !(b
& WM
)) { /* short A field? */
946 ind
[IN_EQU
] = ind
[IN_LOW
] = 0;
947 ind
[IN_UNQ
] = ind
[IN_HGH
] = 1;
949 if (!(cpu_unit
.flags
& HLE
)) /* no HLE? */
950 ind
[IN_EQU
] = ind
[IN_LOW
] = ind
[IN_HGH
] = 0;
953 /* I/O instructions A check B check
955 R read a card if branch
956 W write to line printer if branch
957 WR write and read if branch
958 P punch a card if branch
959 RP read and punch if branch
960 WP : write and punch if branch
961 WRP write read and punch if branch
964 SS select stacker if branch
965 CC carriage control if branch
970 2,3 normal, with modifier
971 4 branch; modifier, if any, is last character of branch address
973 6+ normal, with modifier
976 case OP_R
: /* read */
977 if (reason
= iomod (ilnt
, D
, r_mod
)) break; /* valid modifier? */
978 reason
= read_card (ilnt
, D
); /* read card */
979 BS
= CDR_BUF
+ CDR_WIDTH
;
980 if ((ilnt
== 4) || (ilnt
== 5)) { BRANCH
; } /* check for branch */
983 case OP_W
: /* write */
984 if (reason
= iomod (ilnt
, D
, w_mod
)) break; /* valid modifier? */
985 reason
= write_line (ilnt
, D
); /* print line */
986 BS
= LPT_BUF
+ LPT_WIDTH
;
987 if ((ilnt
== 4) || (ilnt
== 5)) { BRANCH
; } /* check for branch */
990 case OP_P
: /* punch */
991 if (reason
= iomod (ilnt
, D
, p_mod
)) break; /* valid modifier? */
992 reason
= punch_card (ilnt
, D
); /* punch card */
993 BS
= CDP_BUF
+ CDP_WIDTH
;
994 if ((ilnt
== 4) || (ilnt
== 5)) { BRANCH
; } /* check for branch */
997 case OP_WR
: /* write and read */
998 if (reason
= iomod (ilnt
, D
, w_mod
)) break; /* valid modifier? */
999 reason
= write_line (ilnt
, D
); /* print line */
1000 r1
= read_card (ilnt
, D
); /* read card */
1001 BS
= CDR_BUF
+ CDR_WIDTH
;
1002 if ((ilnt
== 4) || (ilnt
== 5)) { BRANCH
; } /* check for branch */
1003 if (reason
== SCPE_OK
) reason
= r1
; /* merge errors */
1006 case OP_WP
: /* write and punch */
1007 if (reason
= iomod (ilnt
, D
, w_mod
)) break; /* valid modifier? */
1008 reason
= write_line (ilnt
, D
); /* print line */
1009 r1
= punch_card (ilnt
, D
); /* punch card */
1010 BS
= CDP_BUF
+ CDP_WIDTH
;
1011 if ((ilnt
== 4) || (ilnt
== 5)) { BRANCH
; } /* check for branch */
1012 if (reason
== SCPE_OK
) reason
= r1
; /* merge errors */
1015 case OP_RP
: /* read and punch */
1016 if (reason
= iomod (ilnt
, D
, NULL
)) break; /* valid modifier? */
1017 reason
= read_card (ilnt
, D
); /* read card */
1018 r1
= punch_card (ilnt
, D
); /* punch card */
1019 BS
= CDP_BUF
+ CDP_WIDTH
;
1020 if ((ilnt
== 4) || (ilnt
== 5)) { BRANCH
; } /* check for branch */
1021 if (reason
== SCPE_OK
) reason
= r1
; /* merge errors */
1024 case OP_WRP
: /* write, read, punch */
1025 if (reason
= iomod (ilnt
, D
, w_mod
)) break; /* valid modifier? */
1026 reason
= write_line (ilnt
, D
); /* print line */
1027 r1
= read_card (ilnt
, D
); /* read card */
1028 r2
= punch_card (ilnt
, D
); /* punch card */
1029 BS
= CDP_BUF
+ CDP_WIDTH
;
1030 if ((ilnt
== 4) || (ilnt
== 5)) { BRANCH
; } /* check for branch */
1031 if (reason
== SCPE_OK
) reason
= (r1
== SCPE_OK
)? r2
: r1
;
1034 case OP_SS
: /* select stacker */
1035 if (reason
= iomod (ilnt
, D
, ss_mod
)) break; /* valid modifier? */
1036 if (reason
= select_stack (D
)) break; /* sel stack, error? */
1037 if ((ilnt
== 4) || (ilnt
== 5)) { BRANCH
; } /* check for branch */
1040 case OP_CC
: /* carriage control */
1041 if (reason
= carriage_control (D
)) break; /* car ctrl, error? */
1042 if ((ilnt
== 4) || (ilnt
== 5)) { BRANCH
; } /* check for branch */
1045 /* MTF - magtape functions - must be at least 4 characters
1047 Instruction lengths:
1049 1-3 invalid I/O address
1050 4 normal, d-character is unit
1052 6+ normal, d-character is last character
1055 case OP_MTF
: /* magtape function */
1056 if (ilnt
< 4) reason
= STOP_INVL
; /* too short? */
1057 else if (ioind
!= BCD_PERCNT
) reason
= STOP_INVA
;
1058 else if (reason
= iomod (ilnt
, D
, mtf_mod
)) break; /* valid modifier? */
1059 reason
= mt_func (unit
, D
); /* mt func, error? */
1060 break; /* can't branch */
1062 case OP_RF
: case OP_PF
: /* read, punch feed */
1065 /* Move character and edit
1068 qsign sign of A field (0 = +, 1 = minus)
1069 qawm A field WM seen and processed
1070 qzero zero suppression enabled
1071 qbody in body (copying A field characters)
1072 qdollar EPE only; $ seen in body
1073 qaster EPE only; * seen in body
1074 qdecimal EPE only; . seen on first rescan
1076 MCE operates in one to three scans, the first of which has three phases
1078 1 right to left qbody = 0, qawm = 0 => right status
1079 qbody = 1, qawm = 0 => body
1080 qbody = 0, qawm = 1 => left status
1082 3 right to left, extended print end only
1084 The first A field character is masked to its digit part, all others
1087 Instruction lengths:
1090 2,3 invalid A-address
1091 4 self (B-address = A-address)
1092 5,6 invalid B-address
1094 8+ normal + ignored modifier
1097 case OP_MCE
: /* edit */
1098 a
= M
[AS
]; /* get A char */
1099 b
= M
[BS
]; /* get B char */
1100 t
= a
& DIGIT
; /* get A digit */
1102 qsign
= ((a
& ZONE
) == BBIT
); /* get A field sign */
1103 qawm
= qzero
= qbody
= 0; /* clear other flags */
1104 qdollar
= qaster
= qdecimal
= 0; /* clear EPE flags */
1106 /* Edit pass 1 - from right to left, under B field control
1108 * in status or !epe, skip B; else, set qaster, repl with A
1109 $ in status or !epe, skip B; else, set qdollar, repl with A
1110 0 in right status or body, if !qzero, set A WM; set qzero, repl with A
1111 else, if !qzero, skip B; else, if (!B WM) set B WM
1112 blank in right status or body, repl with A; else, skip B
1113 C,R,- in status, blank B; else, skip B
1114 , in status, blank B, else, skip B
1119 b
= M
[BS
]; /* get B char */
1120 M
[BS
] = M
[BS
] & ~WM
; /* clr WM */
1121 switch (b
& CHAR
) { /* case on B char */
1123 case BCD_ASTER
: /* * */
1124 if (!qbody
|| qdollar
|| !(cpu_unit
.flags
& EPE
)) break;
1125 qaster
= 1; /* flag */
1126 goto A_CYCLE
; /* take A cycle */
1128 case BCD_DOLLAR
: /* $ */
1129 if (!qbody
|| qaster
|| !(cpu_unit
.flags
& EPE
)) break;
1130 qdollar
= 1; /* flag */
1131 goto A_CYCLE
; /* take A cycle */
1133 case BCD_ZERO
: /* 0 */
1134 if (qawm
) { /* left status? */
1135 if (!qzero
) M
[BS
] = M
[BS
] | WM
; /* first? set WM */
1136 qzero
= 1; /* flag suppress */
1139 if (!qzero
) t
= t
| WM
; /* body, first? WM */
1140 qzero
= 1; /* flag suppress */
1141 goto A_CYCLE
; /* take A cycle */
1143 case BCD_BLANK
: /* blank */
1144 if (qawm
) break; /* left status? */
1146 M
[BS
] = t
; /* copy char */
1147 if (a
& WM
) { /* end of A field? */
1148 qbody
= 0; /* end body */
1149 qawm
= 1; /* start left status */
1152 qbody
= 1; /* in body */
1153 a
= M
[AS
]; /* next A */
1155 t
= a
& CHAR
; /* use A char */
1159 case BCD_C
: case BCD_R
: case BCD_MINUS
: /* C, R, - */
1160 if (!qsign
&& !qbody
) M
[BS
] = BCD_BLANK
; /* + & status? blank */
1163 case BCD_COMMA
: /* , */
1164 if (!qbody
) M
[BS
] = BCD_BLANK
; /* status? blank */
1167 case BCD_AMPER
: /* & */
1168 M
[BS
] = BCD_BLANK
; /* blank */
1172 MM (BS
); /* decr B pointer */
1173 } while ((b
& WM
) == 0); /* stop on B WM */
1175 if (reason
) break; /* address err? */
1176 if (!qzero
) break; /* rescan? */
1178 /* Edit pass 2 - from left to right, suppressing zeroes */
1181 b
= M
[++BS
]; /* get B char */
1182 switch (b
& CHAR
) { /* case on B char */
1184 case BCD_ONE
: case BCD_TWO
: case BCD_THREE
:
1185 case BCD_FOUR
: case BCD_FIVE
: case BCD_SIX
:
1186 case BCD_SEVEN
: case BCD_EIGHT
: case BCD_NINE
:
1187 qzero
= 0; /* turn off supr */
1190 case BCD_ZERO
: case BCD_COMMA
: /* 0 or , */
1191 if (qzero
&& !qdecimal
) /* if supr, blank */
1192 M
[BS
] = qaster
? BCD_ASTER
: BCD_BLANK
;
1195 case BCD_BLANK
: /* blank */
1196 if (qaster
) M
[BS
] = BCD_ASTER
; /* if EPE *, repl */
1199 case BCD_DECIMAL
: /* . */
1200 if (qzero
&& (cpu_unit
.flags
& EPE
)) /* flag for EPE */
1204 case BCD_PERCNT
: case BCD_WM
: case BCD_BS
:
1205 case BCD_TS
: case BCD_MINUS
:
1208 default: /* other */
1209 qzero
= 1; /* restart supr */
1212 } while ((b
& WM
) == 0);
1214 M
[BS
] = M
[BS
] & ~WM
; /* clear B WM */
1215 if (!qdollar
&& !(qdecimal
&& qzero
)) { /* rescan again? */
1216 BS
++; /* BS = addr WM + 1 */
1219 if (qdecimal
&& qzero
) qdollar
= 0; /* no digits? clr $ */
1221 /* Edit pass 3 (extended print only) - from right to left */
1223 for (;; ) { /* until chars */
1224 b
= M
[BS
]; /* get B char */
1225 if ((b
== BCD_BLANK
) && qdollar
) { /* blank & flt $? */
1226 M
[BS
] = BCD_DOLLAR
; /* insert $ */
1227 break; /* exit for */
1229 if (b
== BCD_DECIMAL
) { /* decimal? */
1230 M
[BS
] = qaster
? BCD_ASTER
: BCD_BLANK
;
1231 break; /* exit for */
1233 if ((b
== BCD_ZERO
) && !qdollar
) /* 0 & ~flt $ */
1234 M
[BS
] = qaster
? BCD_ASTER
: BCD_BLANK
;
1237 break; /* done at last! */
1239 /* Multiply. Comments from the PDP-10 based simulator by Len Fehskens.
1241 Multiply, with variable length operands, is necessarily done the same
1242 way you do it with paper and pencil, except that partial products are
1243 added into the incomplete final product as they are computed, rather
1244 than at the end. The 1401 multiplier format allows the product to
1245 be developed in place, without scratch storage.
1247 The A field contains the multiplicand, length LD. The B field must be
1248 LD + 1 + length of multiplier. Locate the low order multiplier digit,
1249 and at the same time zero out the product field. Then compute the sign
1252 Instruction lengths:
1255 2,3 invalid A-address
1256 4 self (B-address = A-address)
1257 5,6 invalid B-address
1259 8+ normal + ignored modifier
1263 asave
= AS
; /* save AS, BS */
1264 bsave
= lowprd
= BS
;
1266 a
= M
[AS
]; /* get mpcd char */
1267 M
[BS
] = BCD_ZERO
; /* zero prod */
1268 MM (AS
); /* decr pointers */
1270 } while ((a
& WM
) == 0); /* until A WM */
1271 if (reason
) break; /* address err? */
1272 M
[BS
] = BCD_ZERO
; /* zero hi prod */
1273 MM (BS
); /* addr low mpyr */
1274 sign
= ((M
[asave
] & ZONE
) == BBIT
) ^ ((M
[BS
] & ZONE
) == BBIT
);
1276 /* Outer loop on multiplier (BS) and product digits (ps),
1277 inner loop on multiplicand digits (AS).
1278 AS and ps cannot produce an address error.
1282 ps
= bsave
; /* ptr to prod */
1283 AS
= asave
; /* ptr to mpcd */
1284 carry
= 0; /* init carry */
1285 b
= M
[BS
]; /* get mpyr char */
1287 a
= M
[AS
]; /* get mpcd char */
1288 t
= (bcd_to_bin
[a
& DIGIT
] * /* mpyr * mpcd */
1289 bcd_to_bin
[b
& DIGIT
]) + /* + c + partial prod */
1290 carry
+ bcd_to_bin
[M
[ps
] & DIGIT
];
1291 carry
= cry_table
[t
];
1292 M
[ps
] = (M
[ps
] & WM
) | sum_table
[t
];
1295 } while ((a
& WM
) == 0); /* until mpcd done */
1296 M
[BS
] = (M
[BS
] & WM
) | BCD_ZERO
; /* zero mpyr just used */
1297 t
= bcd_to_bin
[M
[ps
] & DIGIT
] + carry
; /* add carry to prod */
1298 M
[ps
] = (M
[ps
] & WM
) | sum_table
[t
]; /* store */
1299 bsave
--; /* adv prod ptr */
1300 MM (BS
); /* adv mpyr ptr */
1301 } while ((b
& WM
) == 0); /* until mpyr done */
1302 M
[lowprd
] = M
[lowprd
] | ZONE
; /* assume + */
1303 if (sign
) M
[lowprd
] = M
[lowprd
] & ~ABIT
; /* if minus, B only */
1306 /* Divide. Comments from the PDP-10 based simulator by Len Fehskens.
1308 Divide is done, like multiply, pretty much the same way you do it with
1309 pencil and paper; successive subtraction of the divisor from a substring
1310 of the dividend while counting up the corresponding quotient digit.
1312 Let LS be the length of the divisor, LD the length of the dividend:
1313 - AS points to the low order divisor digit.
1314 - BS points to the high order dividend digit.
1315 - The low order dividend digit is identified by sign (zone) bits.
1316 - To the left of the dividend is a zero field of length LS + 1.
1317 The low quotient is at low dividend - LS - 1. As BS points to the
1318 high dividend, the low dividend is at BS + LD - 1, so the low
1319 quotient is at BS + LD - LS - 2. The longest possible quotient is
1320 LD - LS + 1, so the first possible non-zero quotient bit will be
1323 This pointer calculation assumes that the divisor has no leading zeroes.
1324 For each leading zero, the start of the quotient will be one position
1327 Start by locating the high order non-zero digit of the divisor. This
1328 also tests for a divide by zero.
1330 Instruction lengths:
1333 2,3 invalid A-address
1334 4 self (B-address = A-address)
1335 5,6 invalid B-address
1337 8+ normal + ignored modifier
1344 a
= M
[AS
]; /* get dvr char */
1345 if ((a
& CHAR
) != BCD_ZERO
) ahigh
= AS
; /* mark non-zero */
1348 while ((a
& WM
) == 0);
1349 if (reason
) break; /* address err? */
1350 if (ahigh
< 0) { /* div by zero? */
1351 ind
[IN_OVF
] = 1; /* set ovf indic */
1352 qs
= bsave
= BS
; /* quo, dividend */
1354 b
= M
[bsave
]; /* find end divd */
1355 PP (bsave
); /* marked by zone */
1356 } while ((b
& ZONE
) == 0);
1357 if (reason
) break; /* address err? */
1358 if (ADDR_ERR (qs
)) { /* address err? */
1359 reason
= STOP_WRAP
; /* address wrap? */
1362 div_sign (M
[asave
], b
, qs
- 1, bsave
- 1); /* set signs */
1363 BS
= (BS
- 2) - (asave
- (AS
+ 1)); /* final bs */
1366 bsave
= BS
+ (asave
- ahigh
); /* end subdivd */
1367 qs
= (BS
- 2) - (ahigh
- (AS
+ 1)); /* quo start */
1369 /* Divide loop - done with subroutines to keep the code clean.
1372 asave = low order divisor
1373 bsave = low order subdividend
1374 qs = current quotient digit
1378 quo
= 0; /* clear quo digit */
1379 if (ADDR_ERR (qs
) || ADDR_ERR (bsave
)) {
1380 reason
= STOP_WRAP
; /* address wrap? */
1383 b
= M
[bsave
]; /* save low divd */
1385 t
= div_sub (asave
, bsave
, ahigh
); /* subtract */
1386 quo
++; /* incr quo digit */
1387 } while (t
== 0); /* until borrow */
1388 div_add (asave
, bsave
, ahigh
); /* restore */
1390 M
[qs
] = (M
[qs
] & WM
) | sum_table
[quo
]; /* store quo digit */
1391 bsave
++; /* adv divd, quo */
1393 } while ((b
& ZONE
) == 0); /* until B sign */
1394 if (reason
) break; /* address err? */
1398 AS = high order divisor - 1
1399 asave = unit position of divisor
1400 b = unit character of dividend
1401 bsave = unit position of remainder + 1
1402 qs = unit position of quotient + 1
1405 div_sign (M
[asave
], b
, qs
- 1, bsave
- 1); /* set signs */
1406 BS
= qs
- 2; /* BS = quo 10's pos */
1409 /* Word mark instructions A check B check
1411 SWM set WM on A char and B char fetch fetch
1412 CWM clear WM on A char and B char fetch fetch
1414 Instruction lengths:
1417 2,3 invalid A-address
1418 4 one operand (B-address = A-address)
1419 5,6 invalid B-address
1420 7 two operands (SWM cannot be longer than 7)
1421 8+ two operands + ignored modifier
1424 case OP_SWM
: /* set word mark */
1425 M
[BS
] = M
[BS
] | WM
; /* set A field mark */
1426 M
[AS
] = M
[AS
] | WM
; /* set B field mark */
1427 MM (AS
); /* decr pointers */
1431 case OP_CWM
: /* clear word mark */
1432 M
[BS
] = M
[BS
] & ~WM
; /* clear A field mark */
1433 M
[AS
] = M
[AS
] & ~WM
; /* clear B field mark */
1434 MM (AS
); /* decr pointers */
1438 /* Clear storage instruction A check B check
1440 CS clear from B down to nearest hundreds if branch fetch
1443 Instruction lengths:
1446 2,3 invalid A-address and B-address
1447 4 one operand (B-address = A-address)
1448 5,6 invalid B-address
1450 8+ one operand, branch ignored
1453 case OP_CS
: /* clear storage */
1454 t
= (BS
/ 100) * 100; /* lower bound */
1455 while (BS
>= t
) M
[BS
--] = 0; /* clear region */
1456 if (BS
< 0) BS
= BS
+ MEMSIZE
; /* wrap if needed */
1457 if (ilnt
== 7) { BRANCH
; } /* branch variant? */
1460 /* Modify address instruction A check B check
1462 MA add A addr and B addr, store at B addr fetch fetch
1464 Instruction lengths:
1466 2,3 invalid A-address and B-address
1467 4 self (B-address = A-address)
1468 5,6 invalid B-address
1470 8+ normal + ignored modifier
1473 case OP_MA
: /* modify address */
1474 a
= one_table
[M
[AS
] & CHAR
]; MM (AS
); /* get A address */
1475 a
= a
+ ten_table
[M
[AS
] & CHAR
]; MM (AS
);
1476 a
= a
+ hun_table
[M
[AS
] & CHAR
]; MM (AS
);
1477 b
= one_table
[M
[BS
] & CHAR
]; MM (BS
); /* get B address */
1478 b
= b
+ ten_table
[M
[BS
] & CHAR
]; MM (BS
);
1479 b
= b
+ hun_table
[M
[BS
] & CHAR
]; MM (BS
);
1480 t
= ((a
+ b
) & INDEXMASK
) % MAXMEMSIZE
; /* compute sum */
1481 M
[BS
+ 3] = (M
[BS
+ 3] & WM
) | store_addr_u (t
);
1482 M
[BS
+ 2] = (M
[BS
+ 2] & (WM
+ ZONE
)) | store_addr_t (t
);
1483 M
[BS
+ 1] = (M
[BS
+ 1] & WM
) | store_addr_h (t
);
1484 if (((a
% 4000) + (b
% 4000)) >= 4000) BS
= BS
+ 2; /* carry? */
1487 /* Store address instructions A-check B-check
1489 SAR store A* at A addr fetch
1490 SBR store B* at A addr fetch
1492 Instruction lengths:
1494 2,3 invalid A-address
1496 5+ B-address overwritten from instruction;
1497 invalid address ignored
1500 case OP_SAR
: case OP_SBR
: /* store A, B reg */
1501 M
[AS
] = (M
[AS
] & WM
) | store_addr_u (BS
);
1503 M
[AS
] = (M
[AS
] & WM
) | store_addr_t (BS
);
1505 M
[AS
] = (M
[AS
] & WM
) | store_addr_h (BS
);
1509 /* NOP - no validity checking, all instructions length ok */
1511 case OP_NOP
: /* nop */
1514 /* HALT - unless length = 4 (branch), no validity checking; all lengths ok */
1516 case OP_H
: /* halt */
1517 if (ilnt
== 4) hb_pend
= 1; /* set pending branch */
1518 reason
= STOP_HALT
; /* stop simulator */
1519 saved_IS
= IS
; /* commit instruction */
1523 reason
= STOP_NXI
; /* unimplemented */
1528 /* Simulation halted */
1530 as_err
= ADDR_ERR (AS
); /* get addr err flags */
1531 bs_err
= ADDR_ERR (BS
);
1532 AS
= AS
& ADDRMASK
; /* clean addresses */
1534 pcq_r
->qptr
= pcq_p
; /* update pc q ptr */
1536 } /* end sim_instr */
1538 /* store addr_x - convert address to BCD character in x position
1541 addr = address to convert
1543 char = converted address character
1546 int32
store_addr_h (int32 addr
)
1550 thous
= (addr
/ 1000) & 03;
1551 return bin_to_bcd
[(addr
% 1000) / 100] | (thous
<< V_ZONE
);
1554 int32
store_addr_t (int32 addr
)
1556 return bin_to_bcd
[(addr
% 100) / 10];
1559 int32
store_addr_u (int32 addr
)
1563 thous
= (addr
/ 1000) & 014;
1564 return bin_to_bcd
[addr
% 10] | (thous
<< (V_ZONE
- 2));
1567 /* div_add - add string for divide */
1569 int32
div_add (int32 ap
, int32 bp
, int32 aend
)
1573 c
= 0; /* init carry */
1575 a
= M
[ap
]; /* get operands */
1577 r
= bcd_to_bin
[b
& DIGIT
] + /* sum digits + c */
1578 bcd_to_bin
[a
& DIGIT
] + c
;
1579 c
= (r
>= 10); /* set carry out */
1580 M
[bp
] = sum_table
[r
]; /* store result */
1583 } while (ap
>= aend
);
1587 /* div_sub - substract string for divide */
1589 int32
div_sub (int32 ap
, int32 bp
, int32 aend
)
1593 c
= 0; /* init borrow */
1595 a
= M
[ap
]; /* get operands */
1597 r
= bcd_to_bin
[b
& DIGIT
] - /* a - b - borrow */
1598 bcd_to_bin
[a
& DIGIT
] - c
;
1599 c
= (r
< 0); /* set borrow out */
1600 M
[bp
] = sum_table
[r
+ 10]; /* store result */
1603 } while (ap
>= aend
);
1604 b
= M
[bp
] & CHAR
; /* borrow position */
1605 if (b
&& (b
!= BCD_ZERO
)) { /* non-zero? */
1606 r
= bcd_to_bin
[b
& DIGIT
] - c
; /* subtract borrow */
1607 M
[bp
] = sum_table
[r
]; /* store result */
1608 return 0; /* subtract worked */
1610 return c
; /* return borrow */
1613 /* div_sign - set signs for divide */
1615 void div_sign (int32 dvrc
, int32 dvdc
, int32 qp
, int32 rp
)
1617 int32 sign
= dvrc
& ZONE
; /* divisor sign */
1619 M
[rp
] = M
[rp
] | ZONE
; /* assume rem pos */
1620 if (sign
== BBIT
) M
[rp
] = M
[rp
] & ~ABIT
; /* if dvr -, rem - */
1621 M
[qp
] = M
[qp
] | ZONE
; /* assume quo + */
1622 if (((dvdc
& ZONE
) == BBIT
) ^ (sign
== BBIT
)) /* dvr,dvd diff? */
1623 M
[qp
] = M
[qp
] & ~ABIT
; /* make quo - */
1627 /* iomod - check on I/O modifiers
1630 ilnt = instruction length
1631 mod = modifier character
1632 tptr = pointer to table of modifiers, end is -1
1634 status = SCPE_OK if ok, STOP_INVM if invalid
1637 t_stat
iomod (int32 ilnt
, int32 mod
, const int32
*tptr
)
1639 if ((ilnt
!= 2) && (ilnt
!= 5) && (ilnt
< 8)) return SCPE_OK
;
1640 if (tptr
== NULL
) return STOP_INVM
;
1642 if (mod
== *tptr
++) return SCPE_OK
;
1643 } while (*tptr
>= 0);
1647 /* iodisp - dispatch load or move to I/O routine
1652 flag = move (MD_NORM) vs load (MD_WM)
1656 t_stat
iodisp (int32 dev
, int32 unit
, int32 flag
, int32 mod
)
1658 if (dev
== IO_INQ
) return inq_io (flag
, mod
); /* inq terminal? */
1659 if (dev
== IO_DP
) return dp_io (unit
, flag
, mod
); /* disk pack? */
1660 if (dev
== IO_MT
) return mt_io (unit
, flag
, mod
); /* magtape? */
1661 if (dev
== IO_MTB
) /* binary magtape? */
1662 return mt_io (unit
, flag
| MD_BIN
, mod
);
1663 return STOP_NXD
; /* not implemented */
1668 t_stat
cpu_reset (DEVICE
*dptr
)
1672 for (i
= 0; i
< 64; i
++) { /* clr indicators */
1673 if ((i
< IN_SSB
) || (i
> IN_SSG
)) ind
[i
] = 0; /* except SSB-SSG */
1675 ind
[IN_UNC
] = 1; /* ind[0] always on */
1676 AS
= 0; /* clear AS */
1677 BS
= 0; /* clear BS *
1680 D = 0; /* clear D */
1681 hb_pend
= 0; /* no halt br */
1682 pcq_r
= find_reg ("ISQ", NULL
, dptr
);
1683 if (pcq_r
) pcq_r
->qptr
= 0;
1684 else return SCPE_IERR
;
1685 sim_brk_types
= sim_brk_dflt
= SWMASK ('E');
1689 /* Memory examine */
1691 t_stat
cpu_ex (t_value
*vptr
, t_addr addr
, UNIT
*uptr
, int32 sw
)
1693 if (addr
>= MEMSIZE
) return SCPE_NXM
;
1694 if (vptr
!= NULL
) *vptr
= M
[addr
] & (WM
+ CHAR
);
1698 /* Memory deposit */
1700 t_stat
cpu_dep (t_value val
, t_addr addr
, UNIT
*uptr
, int32 sw
)
1702 if (addr
>= MEMSIZE
) return SCPE_NXM
;
1703 M
[addr
] = val
& (WM
+ CHAR
);
1707 /* Memory size change */
1709 t_stat
cpu_set_size (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
1714 if ((val
<= 0) || (val
> MAXMEMSIZE
) || ((val
% 1000) != 0))
1716 for (i
= val
; i
< MEMSIZE
; i
++) mc
= mc
| M
[i
];
1717 if ((mc
!= 0) && (!get_yn ("Really truncate memory [N]?", FALSE
)))
1720 for (i
= MEMSIZE
; i
< MAXMEMSIZE
; i
++) M
[i
] = 0;
1721 if (MEMSIZE
> 4000) cpu_unit
.flags
= cpu_unit
.flags
| MA
;
1722 else cpu_unit
.flags
= cpu_unit
.flags
& ~MA
;
1728 t_stat
cpu_set_hist (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
1734 for (i
= 0; i
< hst_lnt
; i
++) hst
[i
].ilnt
= 0;
1738 lnt
= (int32
) get_uint (cptr
, 10, HIST_MAX
, &r
);
1739 if ((r
!= SCPE_OK
) || (lnt
&& (lnt
< HIST_MIN
))) return SCPE_ARG
;
1747 hst
= (InstHistory
*) calloc (lnt
, sizeof (InstHistory
));
1748 if (hst
== NULL
) return SCPE_MEM
;
1756 t_stat
cpu_show_hist (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
)
1758 int32 i
, k
, di
, lnt
;
1759 char *cptr
= (char *) desc
;
1760 t_value sim_eval
[MAX_L
+ 1];
1763 extern t_stat
fprint_sym (FILE *ofile
, t_addr addr
, t_value
*val
,
1764 UNIT
*uptr
, int32 sw
);
1766 if (hst_lnt
== 0) return SCPE_NOFNC
; /* enabled? */
1768 lnt
= (int32
) get_uint (cptr
, 10, hst_lnt
, &r
);
1769 if ((r
!= SCPE_OK
) || (lnt
== 0)) return SCPE_ARG
;
1772 di
= hst_p
- lnt
; /* work forward */
1773 if (di
< 0) di
= di
+ hst_lnt
;
1774 fprintf (st
, "IS IR\n\n");
1775 for (k
= 0; k
< lnt
; k
++) { /* print specified */
1776 h
= &hst
[(++di
) % hst_lnt
]; /* entry pointer */
1777 if (h
->ilnt
) { /* instruction? */
1778 fprintf (st
, "%05d ", h
->is
);
1779 for (i
= 0; i
< h
->ilnt
; i
++)
1780 sim_eval
[i
] = h
->inst
[i
];
1781 sim_eval
[h
->ilnt
] = WM
;
1782 if ((fprint_sym (st
, h
->is
, sim_eval
, &cpu_unit
, SWMASK ('M'))) > 0) {
1783 fprintf (st
, "(undefined)");
1784 for (i
= 0; i
< h
->ilnt
; i
++)
1785 fprintf (st
, " %02o", h
->inst
[i
]);
1787 fputc ('\n', st
); /* end line */
1788 } /* end else instruction */
1793 /* Set conversions */
1795 t_stat
cpu_set_conv (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
1801 /* Show conversions */
1803 t_stat
cpu_show_conv (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
)
1805 if (conv_old
) fputs ("Old (pre-3.5-1) conversions\n", st
);
1806 else fputs ("New conversions\n", st
);