~ubuntu-branches/ubuntu/utopic/simh/utopic

« back to all changes in this revision

Viewing changes to i1401_cpu.c

  • Committer: Bazaar Package Importer
  • Author(s): Vince Mulhollon
  • Date: 2004-04-20 20:01:26 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20040420200126-ehsuleda8xcgi51h
Tags: 3.2.0-1
New upstream 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* i1401_cpu.c: IBM 1401 CPU simulator
2
 
 
3
 
   Copyright (c) 1996-1997,
4
 
   Robert M Supnik, Digital Equipment Corporation
5
 
   Commercial use prohibited
6
 
 
7
 
   The register state for the IBM 1401 is:
8
 
 
9
 
   IS           I storage address register (PC)
10
 
   AS           A storage address register (address of first operand)
11
 
   BS           B storage address register (address of second operand)
12
 
   ind[0:63]    indicators
13
 
   SSA          sense switch A
14
 
   IOCHK        I/O check
15
 
   PRCHK        process check
16
 
 
17
 
   The IBM 1401 is a variable instruction length, decimal data system.
18
 
   Memory consists of 4000, 8000, 12000, or 16000 BCD characters, each
19
 
   containing six bits of data and a word mark.  There are no general
20
 
   registers; all instructions are memory to memory, using explicit
21
 
   addresses or an address pointer from a prior instruction.
22
 
 
23
 
   BCD numeric data consists of the low four bits of a character (DIGIT),
24
 
   encoded as X, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, X, X, X, X, X.  The high
25
 
   two bits (ZONE) encode the sign of the data as +, +, -, +.  Character
26
 
   data uses all six bits of a character.  Numeric and character fields are
27
 
   delimited by a word mark.  Fields are typically processed in descending
28
 
   address order (low-order data to high-order data).
29
 
 
30
 
   The 1401 encodes a decimal address, and an index register number, in
31
 
   three characters:
32
 
 
33
 
        character               zone                    digit
34
 
        addr + 0                <1:0> of thousands      hundreds
35
 
        addr + 1                index register #        tens
36
 
        addr + 2                <3:2> of thousands      ones
37
 
 
38
 
   Normally the digit values 0, 11, 12, 13, 14, 15 are illegal in addresses.
39
 
   However, in indexing, digits are passed through the adder, and illegal
40
 
   values are normalized to legal counterparts.
41
 
 
42
 
   The 1401 has six instruction formats:
43
 
 
44
 
        op                      A and B addresses, if any, from AS and BS
45
 
        op d                    A and B addresses, if any, from AS and BS
46
 
        op aaa                  B address, if any, from BS
47
 
        op aaa d                B address, if any, from BS
48
 
        op aaa bbb
49
 
        op aaa bbb d
50
 
 
51
 
   where aaa is the A address, bbb is the B address, and d is a modifier.
52
 
   The opcode has word mark set; all other characters have word mark clear.
53
 
*/
54
 
 
55
 
/* This routine is the instruction decode routine for the IBM 1401.
56
 
   It is called from the simulator control program to execute
57
 
   instructions in simulated memory, starting at the simulated PC.
58
 
   It runs until 'reason' is set non-zero.
59
 
 
60
 
   General notes:
61
 
 
62
 
   1. Reasons to stop.  The simulator can be stopped by:
63
 
 
64
 
        HALT instruction
65
 
        breakpoint encountered
66
 
        illegal addresses or instruction formats
67
 
        I/O error in I/O simulator
68
 
 
69
 
   2. Interrupts.  The 1401 has no interrupt structure.
70
 
 
71
 
   3. Non-existent memory.  On the 1401, references to non-existent
72
 
      memory halt the processor.
73
 
 
74
 
   4. Adding I/O devices.  These modules must be modified:
75
 
 
76
 
        i1401_cpu.c     add IO dispatches to iodisp
77
 
        i1401_sys.c     add pointer to data structures to sim_devices
78
 
*/
79
 
 
80
 
#include "i1401_defs.h"
81
 
 
82
 
#define ILL_ADR_FLAG    100000                          /* invalid addr flag */
83
 
#define save_ibkpt      (cpu_unit.u3)                   /* saved bkpt addr */
84
 
#define ADDR_ERR(x)     ((x) >= MEMSIZE)                /* BA set || too big */
85
 
#define MM(x)           x = x - 1; \
86
 
                        if (x < 0) { \
87
 
                                x = BA + MAXMEMSIZE - 1; \
88
 
                                reason = STOP_WRAP; \
89
 
                                break;  }                       
90
 
#define PP(x)           x = x + 1; \
91
 
                        if (x >= MEMSIZE) { \
92
 
                                x = BA + (x % MAXMEMSIZE); \
93
 
                                reason = STOP_WRAP; \
94
 
                                break;  }
95
 
#define BRANCH          if (ADDR_ERR (AS)) { \
96
 
                                reason = STOP_INVBR; \
97
 
                                break;  } \
98
 
                        if (cpu_unit.flags & XSA) BS = IS; \
99
 
                        else BS = BA + 0; \
100
 
                        oldIS = saved_IS; \
101
 
                        IS = AS;
102
 
 
103
 
unsigned char M[MAXMEMSIZE] = { 0 };                    /* main memory */
104
 
int32 saved_IS = 0;                                     /* saved IS */
105
 
int32 AS = 0;                                           /* AS */
106
 
int32 BS = 0;                                           /* BS */
107
 
int32 as_err = 0, bs_err = 0;                           /* error flags */
108
 
int32 oldIS = 0;                                        /* previous IS */
109
 
int32 ind[64] = { 0 };                                  /* indicators */
110
 
int32 ssa = 1;                                          /* sense switch A */
111
 
int32 prchk = 0;                                        /* process check stop */
112
 
int32 iochk = 0;                                        /* I/O check stop */
113
 
int32 ibkpt_addr = ILL_ADR_FLAG + MAXMEMSIZE;           /* breakpoint addr */
114
 
extern int32 sim_int_char;
115
 
 
116
 
t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
117
 
t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
118
 
t_stat cpu_reset (DEVICE *dptr);
119
 
t_stat cpu_svc (UNIT *uptr);
120
 
t_stat cpu_set_size (UNIT *uptr, int32 value);
121
 
int32 store_addr_h (int32 addr);
122
 
int32 store_addr_t (int32 addr);
123
 
int32 store_addr_u (int32 addr);
124
 
t_stat iomod (int32 ilnt, int32 mod, const int32 *tptr);
125
 
t_stat iodisp (int32 dev, int32 unit, int32 flag, int32 mod);
126
 
 
127
 
extern t_stat read_card (int32 ilnt, int32 mod);
128
 
extern t_stat punch_card (int32 ilnt, int32 mod);
129
 
extern t_stat select_stack (int32 mod);
130
 
extern t_stat carriage_control (int32 mod);
131
 
extern t_stat write_line (int32 ilnt, int32 mod);
132
 
extern t_stat inq_io (int32 flag, int32 mod);
133
 
extern t_stat mt_io (int32 unit, int32 flag, int32 mod);
134
 
extern t_stat mt_func (int32 unit, int32 mod);
135
 
extern t_stat sim_activate (UNIT *uptr, int32 delay);
136
 
 
137
 
/* CPU data structures
138
 
 
139
 
   cpu_dev      CPU device descriptor
140
 
   cpu_unit     CPU unit descriptor
141
 
   cpu_reg      CPU register list
142
 
   cpu_mod      CPU modifier list
143
 
*/
144
 
 
145
 
UNIT cpu_unit = { UDATA (&cpu_svc, UNIT_FIX + UNIT_BCD + STDOPT,
146
 
        MAXMEMSIZE) };
147
 
 
148
 
REG cpu_reg[] = {
149
 
        { DRDATA (IS, saved_IS, 14), PV_LEFT },
150
 
        { DRDATA (AS, AS, 14), PV_LEFT },
151
 
        { DRDATA (BS, BS, 14), PV_LEFT },
152
 
        { FLDATA (ASERR, as_err, 0) },
153
 
        { FLDATA (BSERR, bs_err, 0) },
154
 
        { FLDATA (SSA, ssa, 0) },
155
 
        { FLDATA (SSB, ind[IN_SSB], 0) },
156
 
        { FLDATA (SSC, ind[IN_SSC], 0) },
157
 
        { FLDATA (SSD, ind[IN_SSD], 0) },
158
 
        { FLDATA (SSE, ind[IN_SSE], 0) },
159
 
        { FLDATA (SSF, ind[IN_SSF], 0) },
160
 
        { FLDATA (SSG, ind[IN_SSG], 0) },
161
 
        { FLDATA (EQU, ind[IN_EQU], 0) },
162
 
        { FLDATA (UNEQ, ind[IN_UNQ], 0) },
163
 
        { FLDATA (HIGH, ind[IN_HGH], 0) },
164
 
        { FLDATA (LOW, ind[IN_LOW], 0) },
165
 
        { FLDATA (OVF, ind[IN_OVF], 0) },
166
 
        { FLDATA (IOCHK, iochk, 0) },
167
 
        { FLDATA (PRCHK, prchk, 0) },
168
 
        { DRDATA (OLDIS, oldIS, 14), REG_RO + PV_LEFT },
169
 
        { DRDATA (BREAK, ibkpt_addr, 17), PV_LEFT },
170
 
        { ORDATA (WRU, sim_int_char, 8) },
171
 
        { NULL }  };
172
 
 
173
 
MTAB cpu_mod[] = {
174
 
        { XSA, XSA, "XSA", "XSA", NULL },
175
 
        { XSA, 0, "no XSA", "NOXSA", NULL },
176
 
        { HLE, HLE, "HLE", "HLE", NULL },
177
 
        { HLE, 0, "no HLE", "NOHLE", NULL },
178
 
        { BBE, BBE, "BBE", "BBE", NULL },
179
 
        { BBE, 0, "no BBE", "NOBBE", NULL },
180
 
        { MA, MA, "MA", 0, NULL },
181
 
        { MA, 0, "no MA", 0, NULL },
182
 
        { MR, MR, "MR", "MR", NULL },
183
 
        { MR, 0, "no MR", "NOMR", NULL },
184
 
        { EPE, EPE, "EPE", "EPE", NULL },
185
 
        { EPE, 0, "no EPE", "NOEPE", NULL },
186
 
        { UNIT_MSIZE, 4000, NULL, "4K", &cpu_set_size },
187
 
        { UNIT_MSIZE, 8000, NULL, "8K", &cpu_set_size },
188
 
        { UNIT_MSIZE, 12000, NULL, "12K", &cpu_set_size },
189
 
        { UNIT_MSIZE, 16000, NULL, "16K", &cpu_set_size },
190
 
        { 0 }  };
191
 
 
192
 
DEVICE cpu_dev = {
193
 
        "CPU", &cpu_unit, cpu_reg, cpu_mod,
194
 
        1, 10, 14, 1, 8, 7,
195
 
        &cpu_ex, &cpu_dep, &cpu_reset,
196
 
        NULL, NULL, NULL };
197
 
 
198
 
/* Opcode table - length, dispatch, and option flags.  This table is also
199
 
   used by the symbolic input routine to validate instruction lengths  */
200
 
 
201
 
const int32 op_table[64] = {
202
 
        0,                                              /* 00: illegal */
203
 
        L1 | L2 | L4 | L5,                              /* read */
204
 
        L1 | L2 | L4 | L5,                              /* write */
205
 
        L1 | L2 | L4 | L5,                              /* write and read */
206
 
        L1 | L2 | L4 | L5,                              /* punch */
207
 
        L1 | L4,                                        /* read and punch */
208
 
        L1 | L2 | L4 | L5,                              /* write and read */
209
 
        L1 | L2 | L4 | L5,                              /* write, read, punch */
210
 
        L1,                                             /* 10: read feed */
211
 
        L1,                                             /* punch feed */
212
 
        0,                                              /* illegal */
213
 
        L1 | L4 | L7 | AREQ | BREQ | MA,                /* modify address */
214
 
        L7 | AREQ | BREQ | MDV,                         /* multiply */
215
 
        0,                                              /* illegal */
216
 
        0,                                              /* illegal */
217
 
        0,                                              /* illegal */
218
 
        0,                                              /* 20: illegal */
219
 
        L1 | L4 | L7 | BREQ | NOWM,                     /* clear storage */
220
 
        L1 | L4 | L7 | AREQ | BREQ,                     /* subtract */
221
 
        0,                                              /* illegal */
222
 
        L5 | IO,                                        /* magtape */
223
 
        L1 | L8 | BREQ,                                 /* branch wm or zone */
224
 
        L1 | L8 | BREQ | BBE,                           /* branch if bit eq */
225
 
        0,                                              /* illegal */
226
 
        L1 | L4 | L7 | AREQ | BREQ,                     /* 30: move zones */
227
 
        L7 | AREQ | BREQ,                               /* move supress zero */
228
 
        0,                                              /* illegal */
229
 
        L1 | L4 | L7 | AREQ | BREQ | NOWM,              /* set word mark */
230
 
        L7 | AREQ | BREQ | MDV,                         /* divide */
231
 
        0,                                              /* illegal */
232
 
        0,                                              /* illegal */
233
 
        0,                                              /* illegal */
234
 
        0,                                              /* 40: illegal */
235
 
        0,                                              /* illegal */
236
 
        L2 | L5,                                        /* select stacker */
237
 
        L1 | L4 | L7 | L8 | BREQ | MLS | IO,            /* load */
238
 
        L1 | L4 | L7 | L8 | BREQ | MLS | IO,            /* move */
239
 
        HNOP | L1,                                      /* nop */
240
 
        0,                                              /* illegal */
241
 
        L1 | L4 | L7 | AREQ | BREQ | MR,                /* move to record */
242
 
        L1 | L4 | AREQ | MLS,                           /* 50: store A addr */
243
 
        0,                                              /* illegal */
244
 
        L1 | L4 | L7 | AREQ | BREQ,                     /* zero and subtract */
245
 
        0,                                              /* illegal */
246
 
        0,                                              /* illegal */
247
 
        0,                                              /* illegal */
248
 
        0,                                              /* illegal */
249
 
        0,                                              /* illegal */
250
 
        0,                                              /* 60: illegal */
251
 
        L1 | L4 | L7 | AREQ | BREQ,                     /* add */
252
 
        L1 | L4 | L5 | L8,                              /* branch */
253
 
        L1 | L4 | L7 | AREQ | BREQ,                     /* compare */
254
 
        L1 | L4 | L7 | AREQ | BREQ,                     /* move numeric */
255
 
        L1 | L4 | L7 | AREQ | BREQ,                     /* move char edit */
256
 
        L2 | L5,                                        /* carriage control */
257
 
        0,                                              /* illegal */
258
 
        L1 | L4 | L7 | AREQ | MLS,                      /* 70: store B addr */
259
 
        0,                                              /* illegal */
260
 
        L1 | L4 | L7 | AREQ | BREQ,                     /* zero and add */
261
 
        HNOP | L1 | L4,                                 /* halt */
262
 
        L1 | L4 | L7 | AREQ | BREQ,                     /* clear word mark */
263
 
        0,                                              /* illegal */
264
 
        0,                                              /* illegal */
265
 
        0 };                                            /* illegal */
266
 
 
267
 
const int32 len_table[9] = { 0, L1, L2, 0, L4, L5, 0, L7, L8 };
268
 
 
269
 
/* Address character conversion tables.  Illegal characters are marked by
270
 
   the flag BA but also contain the post-adder value for indexing  */
271
 
 
272
 
const int32 hun_table[64] = {
273
 
        BA+000, 100, 200, 300, 400, 500, 600, 700,
274
 
        800, 900, 000, BA+300, BA+400, BA+500, BA+600, BA+700,
275
 
        BA+1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700,
276
 
        1800, 1900, 1000, BA+1300, BA+1400, BA+1500, BA+1600, BA+1700,
277
 
        BA+2000, 2100, 2200, 2300, 2400, 2500, 2600, 2700,
278
 
        2800, 2900, 2000, BA+2300, BA+2400, BA+2500, BA+2600, BA+2700,
279
 
        BA+3000, 3100, 3200, 3300, 3400, 3500, 3600, 3700,
280
 
        3800, 3900, 3000, BA+3300, BA+3400, BA+3500, BA+3600, BA+3700 };
281
 
 
282
 
const int32 ten_table[64] = {
283
 
        BA+00, 10, 20, 30, 40, 50, 60, 70,
284
 
        80, 90, 00, BA+30, BA+40, BA+50, BA+60, BA+70,
285
 
        X1+00, X1+10, X1+20, X1+30, X1+40, X1+50, X1+60, X1+70,
286
 
        X1+80, X1+90, X1+00, X1+30, X1+40, X1+50, X1+60, X1+70,
287
 
        X2+00, X2+10, X2+20, X2+30, X2+40, X2+50, X2+60, X2+70,
288
 
        X2+80, X2+90, X2+00, X2+30, X2+40, X2+50, X2+60, X2+70,
289
 
        X3+00, X3+10, X3+20, X3+30, X3+40, X3+50, X3+60, X3+70,
290
 
        X3+80, X3+90, X3+00, X3+30, X3+40, X3+50, X3+60, X3+70 };
291
 
 
292
 
const int32 one_table[64] = {
293
 
        BA+0, 1, 2, 3, 4, 5, 6, 7,
294
 
        8, 9, 0, BA+3, BA+4, BA+5, BA+6, BA+7,
295
 
        BA+4000, 4001, 4002, 4003, 4004, 4005, 4006, 4007,
296
 
        4008, 4009, 4000, BA+4003, BA+4004, BA+4005, BA+4006, BA+4007,
297
 
        BA+8000, 8001, 8002, 8003, 8004, 8005, 8006, 8007,
298
 
        8008, 8009, 8000, BA+8003, BA+8004, BA+8005, BA+8006, BA+8007,
299
 
        BA+12000, 12001, 12002, 12003, 12004, 12005, 12006, 12007,
300
 
        12008, 12009, 12000, BA+12003, BA+12004, BA+12005, BA+12006, BA+12007 };
301
 
 
302
 
static const int32 bin_to_bcd[16] = {
303
 
        10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
304
 
 
305
 
static const int32 bcd_to_bin[16] = {
306
 
        0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 3, 4, 5, 6, 7 };
307
 
 
308
 
/* ASCII to BCD conversion */
309
 
 
310
 
const char ascii_to_bcd[128] = {
311
 
        000, 000, 000, 000, 000, 000, 000, 000,         /* 000 - 037 */
312
 
        000, 000, 000, 000, 000, 000, 000, 000,
313
 
        000, 000, 000, 000, 000, 000, 000, 000,
314
 
        000, 000, 000, 000, 000, 000, 000, 000,
315
 
        000, 052, 077, 013, 053, 034, 060, 032,         /* 040 - 077 */
316
 
        017, 074, 054, 037, 033, 040, 073, 021,
317
 
        012, 001, 002, 003, 004, 005, 006, 007,
318
 
        010, 011, 015, 056, 076, 035, 016, 072,
319
 
        014, 061, 062, 063, 064, 065, 066, 067,         /* 100 - 137 */
320
 
        070, 071, 041, 042, 043, 044, 045, 046,
321
 
        047, 050, 051, 022, 023, 024, 025, 026,
322
 
        027, 030, 031, 075, 036, 055, 020, 057,
323
 
        000, 061, 062, 063, 064, 065, 066, 067,         /* 140 - 177 */
324
 
        070, 071, 041, 042, 043, 044, 045, 046,
325
 
        047, 050, 051, 022, 023, 024, 025, 026,
326
 
        027, 030, 031, 000, 000, 000, 000, 000 };
327
 
 
328
 
/* BCD to ASCII conversion - also the "full" print chain */
329
 
 
330
 
char bcd_to_ascii[64] = {
331
 
        ' ', '1', '2', '3', '4', '5', '6', '7',
332
 
        '8', '9', '0', '#', '@', ':', '>', '(',
333
 
        '^', '/', 'S', 'T', 'U', 'V', 'W', 'X',
334
 
        'Y', 'Z', '\'', ',', '%', '=', '\\', '+',
335
 
        '-', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
336
 
        'Q', 'R', '!', '$', '*', ']', ';', '_',
337
 
        '&', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
338
 
        'H', 'I', '?', '.', ')', '[', '<', '"' };
339
 
 
340
 
t_stat sim_instr (void)
341
 
{
342
 
extern int32 sim_interval;
343
 
register int32 IS, D, ilnt, flags;
344
 
int32 op, xa, t, wm, dev, unit;
345
 
int32 a, b, i, bsave, carry;
346
 
int32 qzero, qawm, qbody, qsign, qdollar, qaster, qdecimal;
347
 
t_stat reason, r1, r2;
348
 
 
349
 
/* Indicator resets - a 1 marks an indicator that resets when tested */
350
 
 
351
 
static const int32 ind_table[64] = {
352
 
        0, 0, 0, 0, 0, 0, 0, 0,                         /* 00 - 07 */
353
 
        0, 0, 0, 0, 0, 0, 0, 0,                         /* 10 - 17 */
354
 
        0, 0, 0, 0, 0, 0, 0, 0,                         /* 20 - 27 */
355
 
        0, 1, 1, 0, 1, 0, 0, 0,                         /* 30 - 37 */
356
 
        0, 0, 1, 0, 0, 0, 0, 0,                         /* 40 - 47 */
357
 
        0, 0, 1, 0, 1, 0, 0, 0,                         /* 50 - 57 */
358
 
        0, 0, 0, 0, 0, 0, 0, 0,                         /* 60 - 67 */
359
 
        0, 0, 1, 0, 0, 0, 0, 0 };                       /* 70 - 77 */
360
 
 
361
 
/* Character collation table for compare with HLE option */
362
 
 
363
 
static const int32 col_table[64] = {
364
 
        000, 067, 070, 071, 072, 073, 074, 075,
365
 
        076, 077, 066, 024, 025, 026, 027, 030,
366
 
        023, 015, 056, 057, 060, 061, 062, 063,
367
 
        064, 065, 055, 016, 017, 020, 021, 022,
368
 
        014, 044, 045, 046, 047, 050, 051, 052,
369
 
        053, 054, 043, 007, 010, 011, 012, 013,
370
 
        006, 032, 033, 034, 035, 036, 037, 040,
371
 
        041, 042, 031, 001, 002, 003, 004, 005 };
372
 
 
373
 
/* Summing table for two decimal digits, converted back to BCD */
374
 
        
375
 
static const int32 sum_table[20] = {
376
 
        10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
377
 
 
378
 
/* Legal modifier tables */
379
 
 
380
 
static const int32 w_mod[] = { BCD_S, BCD_SQUARE, -1 };
381
 
static const int32 ss_mod[] = { 1, 2, 4, 8, -1 };
382
 
static const int32 mtf_mod[] = { BCD_B, BCD_E, BCD_M, BCD_R, BCD_U, -1 };
383
 
 
384
 
 
385
 
/* Restore saved state */
386
 
 
387
 
IS = saved_IS;
388
 
D = 0;
389
 
reason = 0;
390
 
 
391
 
/* Main instruction fetch/decode loop */
392
 
 
393
 
while (reason == 0) {                                   /* loop until halted */
394
 
saved_IS = IS;                                          /* commit prev instr */
395
 
if (sim_interval <= 0) {                                /* check clock queue */
396
 
        if (reason = sim_process_event ()) break;  }
397
 
 
398
 
if (IS == ibkpt_addr) {                                 /* breakpoint? */
399
 
        save_ibkpt = ibkpt_addr;                        /* save ibkpt */
400
 
        ibkpt_addr = ibkpt_addr + ILL_ADR_FLAG;         /* disable */
401
 
        sim_activate (&cpu_unit, 1);                    /* sched re-enable */
402
 
        reason = STOP_IBKPT;                            /* stop simulation */
403
 
        break;  }
404
 
 
405
 
sim_interval = sim_interval - 1;
406
 
 
407
 
/* Instruction fetch */
408
 
 
409
 
if ((M[IS] & WM) == 0) {                                /* WM under op? */
410
 
        reason = STOP_NOWM;                             /* no, error */
411
 
        break;  }
412
 
op = M[IS] & CHAR;                                      /* get opcode */
413
 
flags = op_table[op];                                   /* get op flags */
414
 
if ((flags == 0) || (flags & ALLOPT & ~cpu_unit.flags)) {
415
 
        reason = STOP_NXI;                              /* illegal inst? */
416
 
        break;  }
417
 
if (op == OP_SAR) BS = AS;                              /* SAR? save ASTAR */
418
 
PP (IS);
419
 
 
420
 
if ((t = M[IS]) & WM) goto CHECK_LENGTH;                /* WM? 1 char inst */
421
 
D = t;                                                  /* could be D char */
422
 
AS = hun_table[t];                                      /* could be A addr */
423
 
PP (IS);                                                /* if %xy, BA is set */
424
 
 
425
 
if ((t = M[IS]) & WM) {                                 /* WM? 2 char inst */
426
 
        AS = AS | BA;                                   /* ASTAR bad */
427
 
        if (!(flags & MLS)) BS = AS;
428
 
        goto CHECK_LENGTH;  }
429
 
AS = AS + ten_table[t];                                 /* build A addr */
430
 
dev = t;                                                /* save char as dev */
431
 
PP (IS);
432
 
 
433
 
if ((t = M[IS]) & WM) {                                 /* WM? 3 char inst */
434
 
        AS = AS | BA;                                   /* ASTAR bad */
435
 
        if (!(flags & MLS)) BS = AS;
436
 
        goto CHECK_LENGTH;  }
437
 
AS = AS + one_table[t];                                 /* finish A addr */
438
 
unit = (t == BCD_ZERO)? 0: t;                           /* save char as unit */
439
 
xa = (AS >> V_INDEX) & M_INDEX;                         /* get index reg */
440
 
if (xa && (D != BCD_PERCNT) && (cpu_unit.flags & XSA)) {        /* indexed? */
441
 
        AS = AS + hun_table[M[xa] & CHAR] + ten_table[M[xa + 1] & CHAR] +
442
 
                one_table[M[xa + 2] & CHAR];
443
 
        AS = (AS & INDEXMASK) % MAXMEMSIZE;  }
444
 
if (!(flags & MLS)) BS = AS;                            /* not MLS? B = A */
445
 
PP (IS);
446
 
 
447
 
if ((t = M[IS]) & WM) goto CHECK_LENGTH;                /* WM? 4 char inst */
448
 
if ((op == OP_B) && (t == BCD_BLANK)) goto CHECK_LENGTH; /* BR + space? */
449
 
D = t;                                                  /* could be D char */
450
 
BS = hun_table[t];                                      /* could be B addr */
451
 
PP (IS);
452
 
 
453
 
if ((t = M[IS]) & WM) {                                 /* WM? 5 char inst */
454
 
        BS = BS | BA;                                   /* BSTAR bad */
455
 
        goto CHECK_LENGTH;  }
456
 
BS = BS + ten_table[t];                                 /* build B addr */
457
 
PP (IS);
458
 
 
459
 
if ((t = M[IS]) & WM) {                                 /* WM? 6 char inst */
460
 
        BS = BS | BA;                                   /* BSTAR bad */
461
 
        goto CHECK_LENGTH;  }
462
 
BS = BS + one_table[t];                                 /* finish B addr */
463
 
xa = (BS >> V_INDEX) & M_INDEX;                         /* get index reg */
464
 
if (xa && (cpu_unit.flags & XSA)) {                     /* indexed? */
465
 
        BS = BS + hun_table[M[xa] & CHAR] + ten_table[M[xa + 1] & CHAR]
466
 
                + one_table[M[xa + 2] & CHAR];
467
 
        BS = (BS & INDEXMASK) % MAXMEMSIZE;  }
468
 
PP (IS);
469
 
 
470
 
if ((M[IS] & WM) || (flags & NOWM)) goto CHECK_LENGTH;  /* WM? 7 chr */
471
 
D = M[IS];                                              /* last char is D */
472
 
do { PP (IS);  } while ((M[IS] & WM) == 0);             /* find word mark */
473
 
 
474
 
CHECK_LENGTH:
475
 
ilnt = IS - saved_IS;                                   /* get lnt */
476
 
if (((flags & len_table [(ilnt <= 8)? ilnt: 8]) == 0) &&        /* valid lnt? */
477
 
        ((flags & HNOP) == 0)) reason = STOP_INVL;
478
 
if ((flags & BREQ) && ADDR_ERR (BS)) reason = STOP_INVB;        /* valid A? */
479
 
if ((flags & AREQ) && ADDR_ERR (AS)) reason = STOP_INVA;        /* valid B? */
480
 
if (reason) break;                                      /* error in fetch? */
481
 
switch (op) {                                           /* case on opcode */    
482
 
 
483
 
/* Move instructions                                    A check B check
484
 
 
485
 
   MCW: copy A to B, preserving B WM,                   here    fetch
486
 
        until either A or B WM
487
 
   LCA: copy A to B, overwriting B WM,                  here    fetch
488
 
        until A WM
489
 
   MCM: copy A to B, preserving B WM,                   fetch   fetch
490
 
        until record or group mark
491
 
   MSZ: copy A to B, clearing B WM, until A WM;         fetch   fetch
492
 
        reverse scan and suppress leading zeroes
493
 
   MN:  copy A char digit to B char digit,              fetch   fetch
494
 
        preserving B zone and WM
495
 
   MZ:  copy A char zone to B char zone,                fetch   fetch
496
 
        preserving B digit and WM
497
 
*/
498
 
 
499
 
case OP_MCW:                                            /* move char */
500
 
        if (ilnt >= 8) {                                /* I/O form? */
501
 
                reason = iodisp (dev, unit, MD_NORM, D);
502
 
                break;  }
503
 
        if (ADDR_ERR (AS)) {                            /* check A addr */
504
 
                reason = STOP_INVA;
505
 
                break;  }
506
 
        do {    M[BS] = (M[BS] & WM) | (M[AS] & CHAR);  /* move char */
507
 
                wm = M[AS] | M[BS];
508
 
                MM (AS); MM (BS);  }                    /* decr pointers */
509
 
        while ((wm & WM) == 0);                         /* stop on A,B WM */
510
 
        break;
511
 
case OP_LCA:                                            /* load char */
512
 
        if (ilnt >= 8) {                                /* I/O form? */
513
 
                reason = iodisp (dev, unit, MD_WM, D);
514
 
                break;  }
515
 
        if (ADDR_ERR (AS)) {                            /* check A addr */
516
 
                reason = STOP_INVA;
517
 
                break;  }
518
 
        do {    wm = M[BS] = M[AS];                     /* move char + wmark */
519
 
                MM (AS); MM (BS);  }                    /* decr pointers */
520
 
        while ((wm & WM) == 0);                         /* stop on A WM */
521
 
        break;
522
 
case OP_MCM:                                            /* move to rec/group */
523
 
        do {    M[BS] = (M[BS] & WM) | (M[AS] & CHAR);  /* move char */
524
 
                t = M[AS];
525
 
                PP (AS); PP (BS);  }                    /* incr pointers */
526
 
        while (((t & CHAR) != BCD_RECMRK) && (t != (BCD_GRPMRK + WM)));
527
 
        break;
528
 
case OP_MSZ:                                            /* move suppress zero */
529
 
        bsave = BS;                                     /* save B start */
530
 
        qzero = 1;                                      /* set suppress */
531
 
        do {    M[BS] = M[AS] & ((BS != bsave)? CHAR: DIGIT);   /* copy char */
532
 
                wm = M[AS];
533
 
                MM (AS); MM (BS);  }                    /* decr pointers */
534
 
        while ((wm & WM) == 0);                         /* stop on A WM */
535
 
        do {    PP (BS);                                /* adv B */
536
 
                t = M[BS];                              /* get B, cant be WM */
537
 
                if ((t == BCD_ZERO) || (t == BCD_COMMA)) {
538
 
                        if (qzero) M[BS] = 0;  }
539
 
                else if ((t == BCD_BLANK) || (t == BCD_MINUS)) ;
540
 
                else if (((t == BCD_DECIMAL) && (cpu_unit.flags & EPE)) ||
541
 
                         (t <= BCD_NINE)) qzero = 0;
542
 
                else qzero = 1;  }
543
 
        while (BS <= bsave);
544
 
        break;  
545
 
case OP_MN:                                             /* move numeric */
546
 
        M[BS] = (M[BS] & ~DIGIT) | (M[AS] & DIGIT);     /* move digit */
547
 
        MM (AS); MM (BS);                               /* decr pointers */
548
 
        break;
549
 
case OP_MZ:                                             /* move zone */
550
 
        M[BS] = (M[BS] & ~ZONE) | (M[AS] & ZONE);       /* move high bits */
551
 
        MM (AS); MM (BS);                               /* decr pointers */
552
 
        break;
553
 
 
554
 
/* Compare
555
 
 
556
 
   A and B are checked in fetch
557
 
*/
558
 
 
559
 
case OP_C:                                              /* compare */
560
 
        if (ilnt != 1) {                                /* if not chained */
561
 
                ind[IN_EQU] = 1;                        /* clear indicators */
562
 
                ind[IN_UNQ] = ind[IN_HGH] = ind[IN_LOW] = 0;  }
563
 
        do {    a = M[AS];                              /* get characters */
564
 
                b = M[BS];
565
 
                wm = a | b;                             /* get word marks */
566
 
                if ((a & CHAR) != (b & CHAR)) {         /* unequal? */
567
 
                        ind[IN_EQU] = 0;                /* set indicators */
568
 
                        ind[IN_UNQ] = 1;
569
 
                        ind[IN_HGH] = col_table[b & CHAR] > col_table [a & CHAR];
570
 
                        ind[IN_LOW] = ind[IN_HGH] ^ 1;  }
571
 
                MM (AS); MM (BS);  }                    /* decr pointers */
572
 
        while ((wm & WM) == 0);                         /* stop on A, B WM */
573
 
        if ((a & WM) && !(b & WM)) {                    /* short A field? */
574
 
                ind[IN_EQU] = ind[IN_LOW] = 0;
575
 
                ind[IN_UNQ] = ind[IN_HGH] = 1;  }
576
 
        if (!(cpu_unit.flags & HLE))                    /* no HLE? */
577
 
                ind[IN_EQU] = ind[IN_LOW] = ind[IN_HGH] = 0;
578
 
        break;
579
 
 
580
 
/* Branch instructions                                  A check     B check
581
 
 
582
 
   B 8 char:    branch if B char equals d               if branch   here
583
 
   B 5 char:    branch if indicator[d] is set           if branch
584
 
   B 4 char:    unconditional branch                    if branch
585
 
   BWZ:         branch if (d<0>: B char WM)             if branch   here
586
 
                (d<1>: B char zone = d zone)
587
 
   BBE:         branch if B char & d non-zero           if branch   here
588
 
*/
589
 
 
590
 
case OP_B:                                              /* branch */
591
 
        if (ilnt <= 4) { BRANCH; }                      /* uncond branch? */
592
 
        else if (ilnt == 5) {                           /* branch on ind? */
593
 
                if (ind[D]) { BRANCH;  }                /* test indicator */
594
 
                if (ind_table[D]) ind[D] = 0;  }        /* reset if needed */
595
 
        else {  if (ADDR_ERR (BS)) {                    /* branch char eq */
596
 
                        reason = STOP_INVB;             /* validate B addr */
597
 
                        break;  }
598
 
                if ((M[BS] & CHAR) == D) { BRANCH;  }   /* char equal? */
599
 
                else {  MM (BS);  }  }
600
 
        break;
601
 
case OP_BWZ:                                            /* branch wm or zone */
602
 
        if (((D & 1) && (M[BS] & WM)) ||                /* d1? test wm */
603
 
            ((D & 2) && ((M[BS] & ZONE) == (D & ZONE)))) /* d2? test zone */
604
 
                { BRANCH;  }
605
 
        else {  MM (BS);  }                             /* decr pointer */
606
 
        break;
607
 
case OP_BBE:                                            /* branch if bit eq */
608
 
        if (M[BS] & D & CHAR) { BRANCH;  }              /* any bits set? */
609
 
        else {  MM (BS);  }                             /* decr pointer */
610
 
        break;
611
 
 
612
 
/* Arithmetic instructions                              A check B check
613
 
 
614
 
   ZA:  move A to B, normalizing A sign,                fetch   fetch
615
 
        preserving B WM, until B WM
616
 
   ZS:  move A to B, complementing A sign,              fetch   fetch
617
 
        preserving B WM, until B WM
618
 
   A:   add A to B                                      fetch   fetch
619
 
   S:   subtract A from B                               fetch   fetch
620
 
*/
621
 
 
622
 
case OP_ZA: case OP_ZS:                                 /* zero and add/sub */
623
 
        a = i = 0;                                      /* clear flags */
624
 
        do {    if (a & WM) wm = M[BS] = (M[BS] & WM) | BCD_ZERO;
625
 
                else {  a = M[AS];                      /* get A char */
626
 
                        t = (a & CHAR)? bin_to_bcd[a & DIGIT]: 0;
627
 
                        wm = M[BS] = (M[BS] & WM) | t;  /* move digit */
628
 
                        MM (AS);  }
629
 
                if (i == 0) i = M[BS] = M[BS] |
630
 
                        ((((a & ZONE) == BBIT) ^ (op == OP_ZS))? BBIT: ZONE);
631
 
                MM (BS);  }
632
 
        while ((wm & WM) == 0);                         /* stop on B WM */
633
 
        break;
634
 
case OP_A: case OP_S:                                   /* add/sub */
635
 
        bsave = BS;                                     /* save sign pos */
636
 
        a = M[AS];                                      /* get A digit/sign */
637
 
        b = M[BS];                                      /* get B digit/sign */
638
 
        MM (AS);
639
 
        qsign = ((a & ZONE) == BBIT) ^ ((b & ZONE) == BBIT) ^ (op == OP_S);
640
 
        t = bcd_to_bin[a & DIGIT];                      /* get A binary */
641
 
        t = bcd_to_bin[b & DIGIT] + (qsign? 10 - t: t); /* sum A + B */
642
 
        carry = (t >= 10);                              /* get carry */
643
 
        b = (b & ~DIGIT) | sum_table[t];                /* get result */
644
 
        if (qsign && ((b & BBIT) == 0)) b = b | ZONE;   /* normalize sign */
645
 
        M[BS] = b;                                      /* store result */
646
 
        MM (BS);
647
 
        if (b & WM) {                                   /* b wm? done */
648
 
                if (qsign && (carry == 0)) M[bsave] =   /* compl, no carry? */
649
 
                        WM + ((b & ZONE) ^ ABIT) + sum_table[10 - t];
650
 
                break;  }
651
 
        do {    if (a & WM) a = WM;                     /* A WM? char = 0 */
652
 
                else {  a = M[AS];                      /* else get A */
653
 
                        MM (AS);  }
654
 
                b = M[BS];                              /* get B */
655
 
                t = bcd_to_bin[a & DIGIT];              /* get A binary */
656
 
                t = bcd_to_bin[b & DIGIT] + (qsign? 9 - t: t) + carry;
657
 
                carry = (t >= 10);                      /* get carry */
658
 
                if ((b & WM) && (qsign == 0)) {         /* last, no recomp? */
659
 
                        M[BS] = WM + sum_table[t] +     /* zone add */
660
 
                                (((a & ZONE) + b + (carry? ABIT: 0)) & ZONE);
661
 
                        ind[IN_OVF] = carry;  }         /* ovflo if carry */
662
 
                else M[BS] = (b & WM) + sum_table[t];   /* normal add */
663
 
                MM (BS);  }
664
 
        while ((b & WM) == 0);                          /* stop on B WM */
665
 
        if (qsign && (carry == 0)) {                    /* recompl, no carry? */
666
 
                M[bsave] = M[bsave] ^ ABIT;             /* XOR sign */
667
 
                for (carry = 1; bsave != BS; --bsave) { /* rescan */
668
 
                        t = 9 - bcd_to_bin[M[bsave] & DIGIT] + carry;
669
 
                        carry = (t >= 10);
670
 
                        M[bsave] = (M[bsave] & ~DIGIT) | sum_table[t];  }  }
671
 
        break;
672
 
 
673
 
/* I/O instructions                                     A check B check
674
 
 
675
 
   R:   read a card                                     if branch
676
 
   W:   write to line printer                           if branch
677
 
   WR:  write and read                                  if branch
678
 
   P:   punch a card                                    if branch
679
 
   RP:  read and punch                                  if branch
680
 
   WP:  write and punch                                 if branch
681
 
   WRP: write read and punch                            if branch
682
 
   RF:  read feed (nop)
683
 
   PF:  punch feed (nop)
684
 
   SS:  select stacker                                  if branch
685
 
   CC:  carriage control                                if branch
686
 
   MTF: magtape functions
687
 
*/
688
 
 
689
 
case OP_R:                                              /* read */
690
 
        if (reason = iomod (ilnt, D, NULL)) break;      /* valid modifier? */
691
 
        reason = read_card (ilnt, D);                   /* read card */
692
 
        BS = CDR_BUF + CDR_WIDTH;
693
 
        if (ilnt >= 4) { BRANCH;  }                     /* check for branch */
694
 
        break;
695
 
case OP_W:                                              /* write */
696
 
        if (reason = iomod (ilnt, D, w_mod)) break;     /* valid modifier? */
697
 
        reason = write_line (ilnt, D);                  /* print line */
698
 
        BS = LPT_BUF + LPT_WIDTH;
699
 
        if (ilnt >= 4) { BRANCH;  }                     /* check for branch */
700
 
        break;
701
 
case OP_P:                                              /* punch */
702
 
        if (reason = iomod (ilnt, D, NULL)) break;      /* valid modifier? */
703
 
        reason = punch_card (ilnt, D);                  /* punch card */
704
 
        BS = CDP_BUF + CDP_WIDTH;
705
 
        if (ilnt >= 4) { BRANCH;  }                     /* check for branch */
706
 
        break;
707
 
case OP_WR:                                             /* write and read */
708
 
        if (reason = iomod (ilnt, D, w_mod)) break;     /* valid modifier? */
709
 
        reason = write_line (ilnt, D);                  /* print line */
710
 
        r1 = read_card (ilnt, D);                       /* read card */
711
 
        BS = CDR_BUF + CDR_WIDTH;
712
 
        if (ilnt >= 4) { BRANCH;  }                     /* check for branch */
713
 
        if (reason == SCPE_OK) reason = r1;             /* merge errors */
714
 
        break;
715
 
case OP_WP:                                             /* write and punch */
716
 
        if (reason = iomod (ilnt, D, w_mod)) break;     /* valid modifier? */
717
 
        reason = write_line (ilnt, D);                  /* print line */
718
 
        r1 = punch_card (ilnt, D);                      /* punch card */
719
 
        BS = CDP_BUF + CDP_WIDTH;
720
 
        if (ilnt >= 4) { BRANCH;  }                     /* check for branch */
721
 
        if (reason == SCPE_OK) reason = r1;             /* merge errors */
722
 
        break;
723
 
case OP_RP:                                             /* read and punch */
724
 
        if (reason = iomod (ilnt, D, NULL)) break;      /* valid modifier? */
725
 
        reason = read_card (ilnt, D);                   /* read card */
726
 
        r1 = punch_card (ilnt, D);                      /* punch card */
727
 
        BS = CDP_BUF + CDP_WIDTH;  
728
 
        if (ilnt >= 4) { BRANCH;  }                     /* check for branch */
729
 
        if (reason == SCPE_OK) reason = r1;             /* merge errors */
730
 
        break;
731
 
case OP_WRP:                                            /* write, read, punch */
732
 
        if (reason = iomod (ilnt, D, w_mod)) break;     /* valid modifier? */
733
 
        reason = write_line (ilnt, D);                  /* print line */
734
 
        r1 = read_card (ilnt, D);                       /* read card */
735
 
        r2 = punch_card (ilnt, D);                      /* punch card */
736
 
        BS = CDP_BUF + CDP_WIDTH;
737
 
        if (ilnt >= 4) { BRANCH;  }                     /* check for branch */
738
 
        if (reason == SCPE_OK) reason = (r1 == SCPE_OK)? r2: r1;
739
 
        break;
740
 
case OP_SS:                                             /* select stacker */
741
 
        if (reason = iomod (ilnt, D, ss_mod)) break;    /* valid modifier? */
742
 
        if (reason = select_stack (D)) break;           /* sel stack, error? */
743
 
        if (ilnt >= 4) { BRANCH;  }                     /* check for branch */
744
 
        break;
745
 
case OP_CC:                                             /* carriage control */
746
 
        if (reason = carriage_control (D)) break;       /* car ctrl, error? */
747
 
        if (ilnt >= 4) { BRANCH;  }                     /* check for branch */
748
 
        break;
749
 
case OP_MTF:                                            /* magtape function */
750
 
        if (reason = iomod (ilnt, D, mtf_mod)) break;   /* valid modifier? */
751
 
        if (reason = mt_func (unit, D)) break;          /* mt func, error? */
752
 
        break;                                          /* can't branch */
753
 
case OP_RF: case OP_PF:                                 /* read, punch feed */
754
 
        break;                                          /* nop's */
755
 
 
756
 
/* Move character and edit
757
 
 
758
 
   Control flags
759
 
        qsign           sign of A field (0 = +, 1 = minus)
760
 
        qawm            A field WM seen and processed
761
 
        qzero           zero suppression enabled
762
 
        qbody           in body (copying A field characters)
763
 
        qdollar         EPE only; $ seen in body
764
 
        qaster          EPE only; * seen in body
765
 
        qdecimal        EPE only; . seen on first rescan
766
 
*/
767
 
 
768
 
case OP_MCE:                                            /* edit */
769
 
        a = M[AS];                                      /* get A char */
770
 
        b = M[BS];                                      /* get B char */
771
 
        if (a & WM) {                                   /* one char A field? */
772
 
                reason = STOP_MCE1;
773
 
                break;  }
774
 
        if (b & WM) {                                   /* one char B field? */
775
 
                reason = STOP_MCE2;
776
 
                break;  }
777
 
        t = a & DIGIT; MM (AS);                         /* get A digit */
778
 
        qsign = ((a & ZONE) == BBIT);                   /* get A field sign */
779
 
        qawm = qzero = qbody = 0;                       /* clear other flags */
780
 
        qdollar = qaster = qdecimal = 0;                /* clear EPE flags */
781
 
 
782
 
/* Edit pass 1 - from right to left, under B field control */
783
 
 
784
 
        do {    b = M[BS];                              /* get B char */
785
 
                M[BS] = M[BS] & ~WM;                    /* clr WM */
786
 
                switch (b & CHAR) {                     /* case on B char */
787
 
                case BCD_ASTER:                         /* * */
788
 
                        if (!qbody || qdollar || !(cpu_unit.flags & EPE)) break;
789
 
                        qaster = 1;                     /* flag */
790
 
                        goto A_CYCLE;                   /* take A cycle */
791
 
                case BCD_DOLLAR:                        /* $ */
792
 
                        if (!qbody || qaster || !(cpu_unit.flags & EPE)) break;
793
 
                        qdollar = 1;                    /* flag */
794
 
                        goto A_CYCLE;                   /* take A cycle */
795
 
                case BCD_ZERO:                          /* 0 */
796
 
                        if (qawm && !qzero && !(b & WM)) {
797
 
                                M[BS] = BCD_ZERO + WM;  /* mark with WM */
798
 
                                qzero = 1;              /* flag supress */
799
 
                                break;  }
800
 
                        if (!qzero) t = t | WM;         /* first? set WM */
801
 
                        qzero = 1;                      /* flag suppress */
802
 
                                                        /* fall through */
803
 
                case BCD_BLANK:                         /* blank */
804
 
                        if (qawm) break;                /* any A left? */
805
 
                A_CYCLE:
806
 
                        M[BS] = t;                      /* copy char */
807
 
                        if (a & WM) {                   /* end of A field? */
808
 
                                qbody = 0;              /* end body */
809
 
                                qawm = 1;  }
810
 
                        else {  qbody = 1;              /* in body */
811
 
                                a = M[AS]; MM (AS);     /* next A */
812
 
                                t = a & DIGIT;  }
813
 
                        break;
814
 
                case BCD_C: case BCD_R: case BCD_MINUS: /* C, R, - */
815
 
                        if (!qsign && !qbody) M[BS] = BCD_BLANK;
816
 
                        break;
817
 
                case BCD_COMMA:                         /* , */
818
 
                        if (!qbody) M[BS] = BCD_BLANK;  /* bl if status */
819
 
                        break;
820
 
                case BCD_AMPER:                         /* & */
821
 
                        M[BS] = BCD_BLANK;              /* blank B field */
822
 
                        break;  }                       /* end switch */
823
 
                MM (BS);  }                             /* decr B pointer */
824
 
        while ((b & WM) == 0);                          /* stop on B WM */
825
 
 
826
 
        if (!qawm || !qzero) {                          /* rescan? */
827
 
                if (qdollar) reason = STOP_MCE3;        /* error if $ */
828
 
                break;  }
829
 
 
830
 
/* Edit pass 2 - from left to right, suppressing zeroes */
831
 
 
832
 
        do {    b = M[++BS];                            /* get B char */
833
 
                switch (b & CHAR) {                     /* case on B char */
834
 
                case BCD_ONE: case BCD_TWO: case BCD_THREE:
835
 
                case BCD_FOUR: case BCD_FIVE: case BCD_SIX:
836
 
                case BCD_SEVEN: case BCD_EIGHT: case BCD_NINE:
837
 
                        qzero = 0;                      /* turn off supr */
838
 
                        break;
839
 
                case BCD_ZERO: case BCD_COMMA:          /* 0 or , */
840
 
                        if (qzero && !qdecimal)         /* if supr, blank */
841
 
                                M[BS] = qaster? BCD_ASTER: BCD_BLANK;
842
 
                        break;
843
 
                case BCD_BLANK:                         /* blank */
844
 
                        if (qaster) M[BS] = BCD_ASTER;  /* if EPE *, repl */
845
 
                        break;
846
 
                case BCD_DECIMAL:                       /* . */
847
 
                        if (qzero && (cpu_unit.flags & EPE))
848
 
                                 qdecimal = 1;          /* flag for EPE */
849
 
                case BCD_PERCNT: case BCD_WM: case BCD_BS:
850
 
                case BCD_TS: case BCD_MINUS:
851
 
                        break;                          /* ignore */
852
 
                default:                                /* other */
853
 
                        qzero = 1;                      /* restart supr */
854
 
                        break;  }  }                    /* end case, do */
855
 
        while ((b & WM) == 0);
856
 
 
857
 
        M[BS] = M[BS] & ~WM;                            /* clear B WM */
858
 
        if (!qdollar && !(qdecimal && qzero)) break;    /* rescan again? */
859
 
        if (qdecimal && qzero) qdollar = 0;             /* no digits? clr $ */
860
 
 
861
 
/* Edit pass 3 (extended print only) - from right to left */
862
 
 
863
 
        for (;; ) {                                     /* until chars */
864
 
                b = M[BS];                              /* get B char */
865
 
                if ((b == BCD_BLANK) && qdollar) {      /* blank & flt $? */
866
 
                        M[BS] = BCD_DOLLAR;             /* insert $ */
867
 
                        break;  }                       /* exit for */
868
 
                if (b == BCD_DECIMAL) {                 /* decimal? */
869
 
                        M[BS] = qaster? BCD_ASTER: BCD_BLANK;
870
 
                        break;  }                       /* exit for */
871
 
                if ((b == BCD_ZERO) && !qdollar)        /* 0 & ~flt $ */
872
 
                        M[BS] = qaster? BCD_ASTER: BCD_BLANK;
873
 
                BS--;  }                                /* end for */
874
 
        break;                                          /* done at last! */     
875
 
 
876
 
/* Miscellaneous instructions                           A check    B check
877
 
 
878
 
   SWM: set WM on A char and B char                     fetch      fetch
879
 
   CWM: clear WM on A char and B char                   fetch      fetch
880
 
   CS:  clear from B down to nearest hundreds address   if branch  fetch
881
 
   MA:  add A addr and B addr, store at B addr          fetch      fetch
882
 
   SAR: store A* at A addr                              fetch
883
 
   SBR: store B* at A addr                              fetch
884
 
   NOP: no operation
885
 
   H:   halt
886
 
*/
887
 
 
888
 
case OP_SWM:                                            /* set word mark */
889
 
        M[BS] = M[BS] | WM;                             /* set A field mark */
890
 
        M[AS] = M[AS] | WM;                             /* set B field mark */
891
 
        MM (AS); MM (BS);                               /* decr pointers */
892
 
        break;
893
 
case OP_CWM:                                            /* clear word mark */
894
 
        M[BS] = M[BS] & ~WM;                            /* clear A field mark */
895
 
        M[AS] = M[AS] & ~WM;                            /* clear B field mark */
896
 
        MM (AS); MM (BS);                               /* decr pointers */
897
 
        break;
898
 
case OP_CS:                                             /* clear storage */
899
 
        t = (BS / 100) * 100;                           /* lower bound */
900
 
        while (BS >= t) M[BS--] = 0;                    /* clear region */
901
 
        if (BS < 0) BS = BS + MEMSIZE;                  /* wrap if needed */
902
 
        if (ilnt >= 7) { BRANCH; }                      /* branch variant? */
903
 
        break;
904
 
case OP_MA:                                             /* modify address */
905
 
        a = one_table[M[AS] & CHAR]; MM (AS);           /* get A address */
906
 
        a = a + ten_table[M[AS] & CHAR]; MM (AS);
907
 
        a = a + hun_table[M[AS] & CHAR]; MM (AS);
908
 
        b = one_table[M[BS] & CHAR]; MM (BS);           /* get B address */
909
 
        b = b + ten_table[M[BS] & CHAR]; MM (BS);
910
 
        b = b + hun_table[M[BS] & CHAR]; MM (BS);
911
 
        t = ((a + b) & INDEXMASK) % MAXMEMSIZE;         /* compute sum */
912
 
        M[BS + 3] = (M[BS + 3] & WM) | store_addr_u (t);
913
 
        M[BS + 2] = (M[BS + 2] & (WM + ZONE)) | store_addr_t (t);
914
 
        M[BS + 1] = (M[BS + 1] & WM) | store_addr_h (t);
915
 
        if (((a % 4000) + (b % 4000)) >= 4000) BS = BS + 2;     /* carry? */
916
 
        break;
917
 
case OP_SAR: case OP_SBR:                               /* store A, B reg */
918
 
        M[AS] = (M[AS] & WM) | store_addr_u (BS); MM (AS);
919
 
        M[AS] = (M[AS] & WM) | store_addr_t (BS); MM (AS);
920
 
        M[AS] = (M[AS] & WM) | store_addr_h (BS); MM (AS);
921
 
        break;
922
 
case OP_NOP:                                            /* nop */
923
 
        break;
924
 
case OP_H:                                              /* halt */
925
 
        if (ilnt >= 4) { BRANCH;  }                     /* branch if called */
926
 
        reason = STOP_HALT;                             /* stop simulator */
927
 
        saved_IS = IS;                                  /* commit instruction */
928
 
        break;
929
 
default:
930
 
        reason = STOP_NXI;                              /* unimplemented */
931
 
        break;  }                                       /* end switch */
932
 
}                                                       /* end while */
933
 
 
934
 
/* Simulation halted */
935
 
 
936
 
as_err = (AS > ADDRMASK);
937
 
bs_err = (BS > ADDRMASK);
938
 
return reason;
939
 
}                                                       /* end sim_instr */
940
 
 
941
 
/* store addr_x - convert address to BCD character in x position
942
 
 
943
 
   Inputs:
944
 
        addr    =       address to convert
945
 
   Outputs:
946
 
        char    =       converted address character
947
 
*/
948
 
 
949
 
int32 store_addr_h (int32 addr)
950
 
{
951
 
int32 thous;
952
 
 
953
 
thous = (addr / 1000) & 03;
954
 
return  bin_to_bcd[(addr % 1000) / 100] | (thous << V_ZONE);
955
 
}
956
 
 
957
 
int32 store_addr_t (int32 addr)
958
 
{
959
 
return bin_to_bcd[(addr % 100) / 10];
960
 
}
961
 
 
962
 
int32 store_addr_u (int32 addr)
963
 
{
964
 
int32 thous;
965
 
 
966
 
thous = (addr / 1000) & 014;
967
 
return bin_to_bcd[addr % 10] | (thous << (V_ZONE - 2));
968
 
}
969
 
 
970
 
/* iomod - check on I/O modifiers
971
 
 
972
 
   Inputs:
973
 
        ilnt    =       instruction length
974
 
        mod     =       modifier character
975
 
        tptr    =       pointer to table of modifiers, end is -1
976
 
   Output:
977
 
        status  =       SCPE_OK if ok, STOP_INVM if invalid
978
 
*/
979
 
 
980
 
t_stat iomod (int32 ilnt, int32 mod, const int32 *tptr)
981
 
{
982
 
if ((ilnt != 2) && (ilnt != 5) && (ilnt < 8)) return SCPE_OK;
983
 
if (tptr == NULL) return STOP_INVM;
984
 
do {    if (mod == *tptr++) return SCPE_OK;  }
985
 
while (*tptr >= 0);
986
 
return STOP_INVM;
987
 
}
988
 
 
989
 
/* iodisp - dispatch load or move to I/O routine
990
 
 
991
 
   Inputs:
992
 
        dev     =       device number
993
 
        unit    =       unit number
994
 
        flag    =       move (MD_NORM) vs load (MD_WM)
995
 
        mod     =       modifier
996
 
*/
997
 
 
998
 
t_stat iodisp (int32 dev, int32 unit, int32 flag, int32 mod)
999
 
{
1000
 
if (dev == IO_INQ) return inq_io (flag, mod);           /* inq terminal? */
1001
 
if (dev == IO_MT) return mt_io (unit, flag, mod);       /* magtape? */
1002
 
if (dev == IO_MTB) {                                    /* binary? */
1003
 
        if (flag == MD_WM) return STOP_INVM;            /* invalid */
1004
 
        return mt_io (unit, MD_BIN, mod);  }
1005
 
return STOP_NXD;                                        /* not implemented */
1006
 
}
1007
 
 
1008
 
/* Reset routine */
1009
 
 
1010
 
t_stat cpu_reset (DEVICE *dptr)
1011
 
{
1012
 
int32 i;
1013
 
 
1014
 
for (i = 0; i < 64; i++) ind[i] = 0;
1015
 
ind[IN_UNC] = 1;
1016
 
AS = 0; as_err = 1;
1017
 
BS = 0; bs_err = 1;
1018
 
return cpu_svc (&cpu_unit);
1019
 
}
1020
 
 
1021
 
/* Breakpoint service */
1022
 
 
1023
 
t_stat cpu_svc (UNIT *uptr)
1024
 
{
1025
 
if ((ibkpt_addr - ILL_ADR_FLAG) == save_ibkpt) ibkpt_addr = save_ibkpt;
1026
 
save_ibkpt = -1;
1027
 
return SCPE_OK;
1028
 
}
1029
 
 
1030
 
/* Memory examine */
1031
 
 
1032
 
t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
1033
 
{
1034
 
if (addr >= MEMSIZE) return SCPE_NXM;
1035
 
if (vptr != NULL) *vptr = M[addr] & (WM + CHAR);
1036
 
return SCPE_OK;
1037
 
}
1038
 
 
1039
 
/* Memory deposit */
1040
 
 
1041
 
t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)
1042
 
{
1043
 
if (addr >= MEMSIZE) return SCPE_NXM;
1044
 
M[addr] = val & (WM + CHAR);
1045
 
return SCPE_OK;
1046
 
}
1047
 
 
1048
 
/* Memory size change */
1049
 
 
1050
 
t_stat cpu_set_size (UNIT *uptr, int32 value)
1051
 
{
1052
 
int32 i, mc = 0;
1053
 
 
1054
 
if ((value <= 0) || (value > MAXMEMSIZE) || ((value % 1000) != 0))
1055
 
        return SCPE_ARG;
1056
 
for (i = value; i < MEMSIZE; i++) mc = mc | M[i];
1057
 
if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE)))
1058
 
        return SCPE_OK;
1059
 
MEMSIZE = value;
1060
 
for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0;
1061
 
if (MEMSIZE > 4000) cpu_unit.flags = cpu_unit.flags | MA;
1062
 
else cpu_unit.flags = cpu_unit.flags & ~MA;
1063
 
return SCPE_OK;
1064
 
}