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

« back to all changes in this revision

Viewing changes to I1620/i1620_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
/* i1620_cpu.c: IBM 1620 CPU simulator
 
2
 
 
3
   Copyright (c) 2002-2004, Robert M. Supnik
 
4
 
 
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:
 
11
 
 
12
   The above copyright notice and this permission notice shall be included in
 
13
   all copies or substantial portions of the Software.
 
14
 
 
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.
 
21
 
 
22
   Except as contained in this notice, the name of Robert M Supnik shall not
 
23
   be 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.
 
25
 
 
26
   This CPU module incorporates code and comments from the 1620 simulator by
 
27
   Geoff Kuenning, with his permission.
 
28
 
 
29
   26-Mar-04    RMS     Fixed warnings with -std=c99
 
30
   02-Nov-03    RMS     Fixed bug in branch digit (found by Dave Babcock)
 
31
   21-Aug-03    RMS     Fixed bug in immediate index add (found by Michael Short)
 
32
   25-Apr-03    RMS     Changed t_addr to uint32 throughout
 
33
   18-Oct-02    RMS     Fixed bugs in invalid result testing (found by Hans Pufal)
 
34
 
 
35
   The simulated register state for the IBM 1620 is:
 
36
 
 
37
   1620         sim     comment
 
38
 
 
39
   IR1          [PC]    program counter
 
40
   IR2                  instruction register 2 (subroutine return address)
 
41
   OR1          [QAR]   Q address
 
42
   OR2          [PAR]   P address
 
43
   PR1                  manual save address
 
44
   ind[0:99]            indicators
 
45
 
 
46
   Additional internal registers OR3, PR2, and PR3 are not simulated.
 
47
 
 
48
   The IBM 1620 is a fixed instruction length, variable data length, decimal
 
49
   data system.  Memory consists of 20000 - 60000 BCD digits, each containing
 
50
   four bits of data and a flag.  There are no general registers; all
 
51
   instructions are memory to memory.
 
52
 
 
53
   The 1620 uses a fixed, 12 digit instruction format:
 
54
 
 
55
        oo ppppp qqqqq
 
56
 
 
57
   where
 
58
 
 
59
        oo      =       opcode
 
60
        ppppp   =       P (usually destination) address
 
61
        qqqqq   =       Q (usually source) address
 
62
 
 
63
   Immediate instructions use the qqqqq field as the second operand.
 
64
 
 
65
   The 1620 Model 1 uses table lookups for add and multiply; for that reason,
 
66
   it was nicknamed CADET (Can't Add, Doesn't Even Try).  The Model 2 does
 
67
   adds in hardware and uses the add table memory for index registers.
 
68
*/
 
69
 
 
70
/* This routine is the instruction decode routine for the IBM 1620.
 
71
   It is called from the simulator control program to execute
 
72
   instructions in simulated memory, starting at the simulated PC.
 
73
   It runs until 'reason' is set non-zero.
 
74
 
 
75
   General notes:
 
76
 
 
77
   1. Reasons to stop.  The simulator can be stopped by:
 
78
 
 
79
        HALT instruction
 
80
        breakpoint encountered
 
81
        illegal addresses or instruction formats
 
82
        I/O error in I/O simulator
 
83
 
 
84
   2. Interrupts.  The 1620 has no interrupt structure.
 
85
 
 
86
   3. Non-existent memory.  On the 1620, all memory references
 
87
      are modulo the memory size.
 
88
 
 
89
   4. Adding I/O devices.  These modules must be modified:
 
90
 
 
91
        i1620_cpu.c     add iodisp table entry
 
92
        i1620_sys.c     add sim_devices table entry
 
93
*/
 
94
 
 
95
#include "i1620_defs.h"
 
96
 
 
97
#define PCQ_SIZE        64                              /* must be 2**n */
 
98
#define PCQ_MASK        (PCQ_SIZE - 1)
 
99
#define PCQ_ENTRY       pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = saved_PC
 
100
 
 
101
uint8 M[MAXMEMSIZE] = { 0 };                            /* main memory */
 
102
uint32 saved_PC = 0;                                    /* saved PC */
 
103
uint32 IR2 = 1;                                         /* inst reg 2 */
 
104
uint32 PAR = 0;                                         /* P address */
 
105
uint32 QAR = 0;                                         /* Q address */
 
106
uint32 PR1 = 1;                                         /* proc reg 1 */
 
107
uint32 iae = 1;                                         /* ind addr enb */
 
108
uint32 idxe = 0;                                        /* index enable */
 
109
uint32 idxb = 0;                                        /* index band */
 
110
uint32 io_stop = 1;                                     /* I/O stop */
 
111
uint32 ar_stop = 1;                                     /* arith stop */
 
112
int32 ind_max = 16;                                     /* iadr nest limit */
 
113
uint16 pcq[PCQ_SIZE] = { 0 };                           /* PC queue */
 
114
int32 pcq_p = 0;                                        /* PC queue ptr */
 
115
REG *pcq_r = NULL;                                      /* PC queue reg ptr */
 
116
uint8 ind[NUM_IND] = { 0 };                             /* indicators */
 
117
 
 
118
extern int32 sim_int_char;
 
119
extern int32 sim_interval;
 
120
extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */
 
121
extern FILE *sim_log;
 
122
 
 
123
t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
 
124
t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
 
125
t_stat cpu_reset (DEVICE *dptr);
 
126
t_stat cpu_set_opt1 (UNIT *uptr, int32 val, char *cptr, void *desc);
 
127
t_stat cpu_set_opt2 (UNIT *uptr, int32 val, char *cptr, void *desc);
 
128
t_stat cpu_set_model (UNIT *uptr, int32 val, char *cptr, void *desc);
 
129
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
 
130
t_stat cpu_set_save (UNIT *uptr, int32 val, char *cptr, void *desc);
 
131
t_stat cpu_set_table (UNIT *uptr, int32 val, char *cptr, void *desc);
 
132
 
 
133
int32 get_2d (uint32 ad);
 
134
t_stat get_addr (uint32 alast, int32 lnt, t_bool indexok, uint32 *addr);
 
135
t_stat cvt_addr (uint32 alast, int32 lnt, t_bool signok, int32 *val);
 
136
t_stat get_idx (uint32 aidx);
 
137
t_stat xmt_field (uint32 d, uint32 s, uint32 skp);
 
138
t_stat xmt_record (uint32 d, uint32 s, t_bool cpy);
 
139
t_stat xmt_index (uint32 d, uint32 s);
 
140
t_stat xmt_divd (uint32 d, uint32 s);
 
141
t_stat xmt_tns (uint32 d, uint32 s);
 
142
t_stat xmt_tnf (uint32 d, uint32 s);
 
143
t_stat add_field (uint32 d, uint32 s, t_bool sub, t_bool sto, uint32 skp, int32 *sta);
 
144
uint32 add_one_digit (uint32 dst, uint32 src, uint32 *cry);
 
145
t_stat mul_field (uint32 mpc, uint32 mpy);
 
146
t_stat mul_one_digit (uint32 mpyd, uint32 mpcp, uint32 prop, uint32 last);
 
147
t_stat div_field (uint32 dvd, uint32 dvr, int32 *ez);
 
148
t_stat div_one_digit (uint32 dvd, uint32 dvr, uint32 max, uint32 *quod, uint32 *quop);
 
149
t_stat oct_to_dec (uint32 tbl, uint32 s);
 
150
t_stat dec_to_oct (uint32 d, uint32 tbl, int32 *ez);
 
151
t_stat or_field (uint32 d, uint32 s);
 
152
t_stat and_field (uint32 d, uint32 s);
 
153
t_stat xor_field (uint32 d, uint32 s);
 
154
t_stat com_field (uint32 d, uint32 s);
 
155
void upd_ind (void);
 
156
 
 
157
extern t_stat tty (uint32 op, uint32 pa, uint32 f0, uint32 f1);
 
158
extern t_stat ptp (uint32 op, uint32 pa, uint32 f0, uint32 f1);
 
159
extern t_stat ptr (uint32 op, uint32 pa, uint32 f0, uint32 f1);
 
160
extern t_stat cdp (uint32 op, uint32 pa, uint32 f0, uint32 f1);
 
161
extern t_stat cdr (uint32 op, uint32 pa, uint32 f0, uint32 f1);
 
162
extern t_stat dp (uint32 op, uint32 pa, uint32 f0, uint32 f1);
 
163
extern t_stat lpt (uint32 op, uint32 pa, uint32 f0, uint32 f1);
 
164
extern t_stat btp (uint32 op, uint32 pa, uint32 f0, uint32 f1);
 
165
extern t_stat btr (uint32 op, uint32 pa, uint32 f0, uint32 f1);
 
166
 
 
167
extern t_stat fp_add (uint32 d, uint32 s, t_bool sub);
 
168
extern t_stat fp_mul (uint32 d, uint32 s);
 
169
extern t_stat fp_div (uint32 d, uint32 s);
 
170
extern t_stat fp_fsl (uint32 d, uint32 s);
 
171
extern t_stat fp_fsr (uint32 d, uint32 s);
 
172
 
 
173
/* CPU data structures
 
174
 
 
175
   cpu_dev      CPU device descriptor
 
176
   cpu_unit     CPU unit descriptor
 
177
   cpu_reg      CPU register list
 
178
   cpu_mod      CPU modifier list
 
179
*/
 
180
 
 
181
UNIT cpu_unit = { UDATA (NULL, UNIT_FIX+UNIT_BCD+MI_STD, MAXMEMSIZE) };
 
182
 
 
183
REG cpu_reg[] = {
 
184
        { DRDATA (PC, saved_PC, 16), PV_LEFT },
 
185
        { DRDATA (IR2, IR2, 16), PV_LEFT },
 
186
        { DRDATA (PR1, PR1, 16), PV_LEFT },
 
187
        { DRDATA (PAR, PAR, 16), PV_LEFT + REG_RO },
 
188
        { DRDATA (QAR, QAR, 16), PV_LEFT + REG_RO },
 
189
        { FLDATA (SW1, ind[IN_SW1], 0) },
 
190
        { FLDATA (SW2, ind[IN_SW2], 0) },
 
191
        { FLDATA (SW3, ind[IN_SW3], 0) },
 
192
        { FLDATA (SW4, ind[IN_SW4], 0) },
 
193
        { FLDATA (HP, ind[IN_HP], 0) },
 
194
        { FLDATA (EZ, ind[IN_EZ], 0) },
 
195
        { FLDATA (OVF, ind[IN_OVF], 0) },
 
196
        { FLDATA (EXPCHK, ind[IN_EXPCHK], 0) },
 
197
        { FLDATA (RDCHK, ind[IN_RDCHK], 0) },
 
198
        { FLDATA (WRCHK, ind[IN_WRCHK], 0) },
 
199
        { FLDATA (ARSTOP, ar_stop, 0) },
 
200
        { FLDATA (IOSTOP, io_stop, 0) },
 
201
        { BRDATA (IND, ind, 10, 1, NUM_IND) },
 
202
        { FLDATA (IAE, iae, 0) },
 
203
        { FLDATA (IDXE, idxe, 0) },
 
204
        { FLDATA (IDXB, idxb, 0) },
 
205
        { DRDATA (INDMAX, ind_max, 16), REG_NZ + PV_LEFT },
 
206
        { BRDATA (PCQ, pcq, 10, 14, PCQ_SIZE), REG_RO+REG_CIRC },
 
207
        { ORDATA (PCQP, pcq_p, 6), REG_HRO },
 
208
        { ORDATA (WRU, sim_int_char, 8) },
 
209
        { NULL }  };
 
210
 
 
211
MTAB cpu_mod[] = {
 
212
        { IF_IA, IF_IA, "IA", "IA", &cpu_set_opt1 },
 
213
        { IF_IA, 0, "no IA", "NOIA", &cpu_set_opt1 },
 
214
        { IF_EDT, IF_EDT, "EDT", "EDT", &cpu_set_opt1 },
 
215
        { IF_EDT, 0, "no EDT", "NOEDT", &cpu_set_opt1 },
 
216
        { IF_DIV, IF_DIV, "DIV", "DIV", &cpu_set_opt1 },
 
217
        { IF_DIV, 0, "no DIV", "NODIV", &cpu_set_opt1 },
 
218
        { IF_FP, IF_FP, "FP", "FP", NULL },
 
219
        { IF_FP, 0, "no FP", "NOFP", NULL },
 
220
        { IF_BIN, IF_BIN, "BIN", "BIN", &cpu_set_opt2 },
 
221
        { IF_BIN, 0, "no BIN", "NOBIN", &cpu_set_opt2 },
 
222
        { IF_IDX, IF_IDX, "IDX", "IDX", &cpu_set_opt2 },
 
223
        { IF_IDX, 0, "no IDX", "NOIDX", &cpu_set_opt2 },
 
224
        { IF_MII, IF_MII, "Model 2", "MOD2", &cpu_set_model },
 
225
        { IF_MII, 0, "Model 1", "MOD1", &cpu_set_model },
 
226
        { UNIT_MSIZE, 20000, NULL, "20K", &cpu_set_size },
 
227
        { UNIT_MSIZE, 40000, NULL, "40K", &cpu_set_size },
 
228
        { UNIT_MSIZE, 60000, NULL, "60K", &cpu_set_size },
 
229
        { UNIT_MSIZE, 0, NULL, "SAVE", &cpu_set_save },
 
230
        { UNIT_MSIZE, 0, NULL, "TABLE", &cpu_set_table },
 
231
        { 0 }  };
 
232
 
 
233
DEVICE cpu_dev = {
 
234
        "CPU", &cpu_unit, cpu_reg, cpu_mod,
 
235
        1, 10, 18, 1, 16, 5,
 
236
        &cpu_ex, &cpu_dep, &cpu_reset,
 
237
        NULL, NULL, NULL };
 
238
 
 
239
/* Instruction table */
 
240
 
 
241
const int32 op_table[100] = {
 
242
        0,                                              /* 0 */
 
243
        IF_FP + IF_VPA + IF_VQA,                        /* FADD */
 
244
        IF_FP + IF_VPA + IF_VQA,                        /* FSUB */
 
245
        IF_FP + IF_VPA + IF_VQA,                        /* FMUL */
 
246
        0,
 
247
        IF_FP + IF_VPA + IF_VQA,                        /* FSL */
 
248
        IF_FP + IF_MII + IF_VPA + IF_VQA,               /* TFL */
 
249
        IF_FP + IF_MII + IF_VPA + IF_VQA,               /* BTFL */
 
250
        IF_FP + IF_VPA + IF_VQA,                        /* FSR */
 
251
        IF_FP + IF_VPA + IF_VQA,                        /* FDV */
 
252
        IF_MII + IF_VPA + IF_IMM,                       /* 10: BTAM */
 
253
        IF_VPA + IF_IMM,                                /* AM */
 
254
        IF_VPA + IF_IMM,                                /* SM */
 
255
        IF_VPA + IF_IMM,                                /* MM */
 
256
        IF_VPA + IF_IMM,                                /* CM */
 
257
        IF_VPA + IF_IMM,                                /* TDM */
 
258
        IF_VPA + IF_IMM,                                /* TFM */
 
259
        IF_VPA + IF_IMM,                                /* BTM */
 
260
        IF_DIV + IF_VPA + IF_IMM,                       /* LDM */
 
261
        IF_DIV + IF_VPA + IF_IMM,                       /* DM */
 
262
        IF_MII + IF_VPA + IF_VQA,                       /* 20: BTA */
 
263
        IF_VPA + IF_VQA,                                /* A */
 
264
        IF_VPA + IF_VQA,                                /* S */
 
265
        IF_VPA + IF_VQA,                                /* M */
 
266
        IF_VPA + IF_VQA,                                /* C */
 
267
        IF_VPA + IF_VQA,                                /* TD */
 
268
        IF_VPA + IF_VQA,                                /* TF */
 
269
        IF_VPA + IF_VQA,                                /* BT */
 
270
        IF_DIV + IF_VPA + IF_VQA,                       /* LD */
 
271
        IF_DIV + IF_VPA + IF_VQA,                       /* D */
 
272
        IF_MII + IF_VPA + IF_VQA,                       /* 30: TRNM */
 
273
        IF_VPA + IF_VQA,                                /* TR */
 
274
        IF_VPA,                                         /* SF */
 
275
        IF_VPA,                                         /* CF */
 
276
        IF_VPA,                                         /* K */
 
277
        IF_VPA,                                         /* DN */
 
278
        IF_VPA,                                         /* RN */
 
279
        IF_VPA,                                         /* RA */
 
280
        IF_VPA,                                         /* WN */
 
281
        IF_VPA,                                         /* WA */
 
282
        0,                                              /* 40 */
 
283
        0,                                              /* NOP */
 
284
        0,                                              /* BB */
 
285
        IF_VPA + IF_VQA,                                /* BD */
 
286
        IF_VPA + IF_VQA,                                /* BNF */
 
287
        IF_VPA + IF_VQA,                                /* BNR */
 
288
        IF_VPA,                                         /* BI */
 
289
        IF_VPA,                                         /* BNI */
 
290
        0,                                              /* H */
 
291
        IF_VPA,                                         /* B */
 
292
        0,                                              /* 50 */
 
293
        0,
 
294
        0,
 
295
        0,
 
296
        0,
 
297
        IF_VPA + IF_VQA,                                /* BNG - disk sys */
 
298
        0,
 
299
        0,
 
300
        0,
 
301
        0,
 
302
        IF_MII + IF_VPA,                                /* 60: BS */
 
303
        IF_IDX + IF_VPA + IF_NQX,                       /* BX */
 
304
        IF_IDX + IF_VPA + IF_IMM,                       /* BXM */
 
305
        IF_IDX + IF_VPA + IF_NQX,                       /* BCX */
 
306
        IF_IDX + IF_VPA + IF_IMM,                       /* BCXM */
 
307
        IF_IDX + IF_VPA + IF_NQX,                       /* BLX */
 
308
        IF_IDX + IF_VPA + IF_IMM,                       /* BLXM */
 
309
        IF_IDX + IF_VPA + IF_NQX,                       /* BSX */
 
310
        0,
 
311
        0,
 
312
        IF_IDX + IF_VPA + IF_VQA,                       /* 70: MA */
 
313
        IF_EDT + IF_VPA + IF_VQA,                       /* MF */
 
314
        IF_EDT + IF_VPA + IF_VQA,                       /* MF */
 
315
        IF_EDT + IF_VPA + IF_VQA,                       /* TNF */
 
316
        0,
 
317
        0,
 
318
        0,
 
319
        0,
 
320
        0,
 
321
        0,
 
322
        0,                                              /* 80 */
 
323
        0,
 
324
        0,
 
325
        0,
 
326
        0,
 
327
        0,
 
328
        0,
 
329
        0,
 
330
        0,
 
331
        0,
 
332
        IF_BIN + IF_VPA + IF_4QA,                       /* 90: BBT */
 
333
        IF_BIN + IF_VPA + IF_4QA,                       /* BMK */
 
334
        IF_BIN + IF_VPA + IF_VQA,                       /* ORF */
 
335
        IF_BIN + IF_VPA + IF_VQA,                       /* ANDF */
 
336
        IF_BIN + IF_VPA + IF_VQA,                       /* CPLF */
 
337
        IF_BIN + IF_VPA + IF_VQA,                       /* EORF */
 
338
        IF_BIN + IF_VPA + IF_VQA,                       /* OTD */
 
339
        IF_BIN + IF_VPA + IF_VQA,                       /* DTO */
 
340
        0,
 
341
        0
 
342
 };
 
343
 
 
344
/* IO dispatch table */
 
345
 
 
346
t_stat (*iodisp[NUM_IO])(uint32 op, uint32 pa, uint32 f0, uint32 f1) = {
 
347
        NULL, &tty, &ptp, &ptr, &cdp,                   /* 00 - 09 */
 
348
        &cdr, NULL, &dp,  NULL, &lpt,
 
349
        NULL, NULL, NULL, NULL, NULL,                   /* 10 - 19 */
 
350
        NULL, NULL, NULL, NULL, NULL,
 
351
        NULL, NULL, NULL, NULL, NULL,                   /* 20 - 29 */
 
352
        NULL, NULL, NULL, NULL, NULL,
 
353
        NULL, NULL, &btp, &btr, NULL,                   /* 30 - 39 */
 
354
        NULL, NULL, NULL, NULL, NULL,
 
355
        NULL, NULL, NULL, NULL, NULL,                   /* 40 - 49 */
 
356
        NULL, NULL, NULL, NULL, NULL,
 
357
        NULL, NULL, NULL, NULL, NULL,                   /* 50 - 59 */
 
358
        NULL, NULL, NULL, NULL, NULL,
 
359
        NULL, NULL, NULL, NULL, NULL,                   /* 60 - 69 */
 
360
        NULL, NULL, NULL, NULL, NULL,
 
361
        NULL, NULL, NULL, NULL, NULL,                   /* 70 - 79 */
 
362
        NULL, NULL, NULL, NULL, NULL,
 
363
        NULL, NULL, NULL, NULL, NULL,                   /* 80 - 89 */
 
364
        NULL, NULL, NULL, NULL, NULL,
 
365
        NULL, NULL, NULL, NULL, NULL,                   /* 90 - 99 */
 
366
        NULL, NULL, NULL, NULL, NULL  };
 
367
 
 
368
/* Indicator table: -1 = illegal, +1 = resets when tested */
 
369
 
 
370
const int32 ind_table[NUM_IND] = {
 
371
        -1,  0,  0,  0,  0, -1,  1,  1, -1,  1,         /* 00 - 09 */
 
372
        -1,  0,  0,  0,  1,  1,  1,  1, -1,  0,         /* 10 - 19 */
 
373
        -1, -1, -1, -1, -1,  0, -1, -1, -1, -1,         /* 20 - 29 */
 
374
         0,  0,  0,  1,  1,  0,  1,  1,  1,  0,         /* 30 - 39 */
 
375
        -1, -1,  1, -1, -1, -1, -1, -1, -1, -1,         /* 40 - 49 */
 
376
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,         /* 50 - 59 */
 
377
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,         /* 60 - 69 */
 
378
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,         /* 70 - 79 */
 
379
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,         /* 80 - 89 */
 
380
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1  };      /* 90 - 99 */
 
381
 
 
382
/* Add table for 1620 Model 1 */
 
383
 
 
384
const uint8 std_add_table[ADD_TABLE_LEN] = {
 
385
        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
 
386
        0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10,
 
387
        0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11,
 
388
        0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12,
 
389
        0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13,
 
390
        0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14,
 
391
        0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
 
392
        0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
 
393
        0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
 
394
        0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18  };
 
395
 
 
396
 
 
397
/* Add table for 1620 Model 2 ("hardware add") */
 
398
 
 
399
const uint8 sum_table[20] = {
 
400
        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
 
401
        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19  };
 
402
 
 
403
/* Multiply table */
 
404
 
 
405
const uint8 std_mul_table[MUL_TABLE_LEN] = {
 
406
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 
407
        0, 0, 1, 0, 2, 0, 3, 0, 4, 0,
 
408
        0, 0, 2, 0, 4, 0, 6, 0, 8, 0,
 
409
        0, 0, 3, 0, 6, 0, 9, 0, 2, 1,
 
410
        0, 0, 4, 0, 8, 0, 2, 1, 6, 1,
 
411
        0, 0, 5, 0, 0, 1, 5, 1, 0, 2,
 
412
        0, 0, 6, 0, 2, 1, 8, 1, 4, 2,
 
413
        0, 0, 7, 0, 4, 1, 1, 2, 8, 2,
 
414
        0, 0, 8, 0, 6, 1, 4, 2, 2, 3,
 
415
        0, 0, 9, 0, 8, 1, 7, 2, 6, 3,
 
416
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 
417
        5, 0, 6, 0, 7, 0, 8, 0, 9, 0,
 
418
        0, 1, 2, 1, 4, 1, 6, 1, 8, 1,
 
419
        5, 1, 8, 1, 1, 2, 4, 2, 7, 2,
 
420
        0, 2, 4, 2, 8, 2, 2, 3, 6, 3,
 
421
        5, 2, 0, 3, 5, 3, 0, 4, 5, 4,
 
422
        0, 3, 6, 3, 2, 4, 8, 4, 4, 5,
 
423
        5, 3, 2, 4, 9, 4, 6, 5, 3, 6,
 
424
        0, 4, 8, 4, 6, 5, 4, 6, 2, 7,
 
425
        5, 4, 4, 5, 3, 6, 2, 7, 1, 8  };
 
426
 
 
427
#define BRANCH(x)       PCQ_ENTRY; PC = (x)
 
428
#define GET_IDXADDR(x)  ((idxb? IDX_B: IDX_A) + ((x) * ADDR_LEN) + (ADDR_LEN - 1))
 
429
 
 
430
t_stat sim_instr (void)
 
431
{
 
432
uint32 PC, pla, qla, f0, f1;
 
433
int32 i, t, idx, flags, sta, dev, op;
 
434
t_stat reason;
 
435
 
 
436
/* Restore saved state */
 
437
 
 
438
PC = saved_PC;
 
439
if ((cpu_unit.flags & IF_IA) == 0) iae = 0;
 
440
if ((cpu_unit.flags & IF_IDX) == 0) idxe = idxb = 0;
 
441
upd_ind ();                                             /* update indicators */
 
442
reason = 0;
 
443
 
 
444
/* Main instruction fetch/decode loop */
 
445
 
 
446
while (reason == 0) {                                   /* loop until halted */
 
447
saved_PC = PC;                                          /* commit prev instr */
 
448
if (sim_interval <= 0) {                                /* check clock queue */
 
449
        if (reason = sim_process_event ()) break;  }
 
450
 
 
451
if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) {  /* breakpoint? */
 
452
        reason = STOP_IBKPT;                            /* stop simulation */
 
453
        break;  }
 
454
 
 
455
sim_interval = sim_interval - 1;
 
456
 
 
457
/* Instruction fetch and address decode */
 
458
 
 
459
if (PC & 1) {                                           /* PC odd? */
 
460
        reason = STOP_INVIAD;                           /* stop */
 
461
        break;  }
 
462
 
 
463
op = get_2d (PC);                                       /* get opcode */
 
464
if (op < 0) {                                           /* invalid? */
 
465
        reason = STOP_INVINS;
 
466
        break;  }
 
467
flags = op_table[op];                                   /* get op, flags */
 
468
if ((flags & ALLOPT) &&                                 /* need option? */
 
469
   !(flags & ALLOPT & cpu_unit.flags)) {                /* any set? */
 
470
        reason = STOP_INVINS;                           /* no, error */
 
471
        break;  }
 
472
 
 
473
pla = ADDR_A (PC, I_PL);                                /* P last addr */
 
474
qla = ADDR_A (PC, I_QL);                                /* Q last addr */
 
475
if (flags & IF_VPA) {                                   /* need P? */
 
476
        reason = get_addr (pla, 5, TRUE, &PAR);         /* get P addr */
 
477
        if (reason != SCPE_OK) break;  }                /* stop if error */
 
478
if (flags & (IF_VQA | IF_4QA | IF_NQX)) {               /* need Q? */
 
479
        reason = get_addr (qla,                         /* get Q addr */
 
480
            ((flags & IF_4QA)? 4: 5),                   /* 4 or 5 digits */
 
481
            ((flags & IF_NQX)? FALSE: TRUE),            /* not or indexed */
 
482
            &QAR);
 
483
        if (reason != SCPE_OK) {                        /* stop if invalid */
 
484
            reason = reason + (STOP_INVQDG - STOP_INVPDG);
 
485
            break;  }  }
 
486
else if (flags & IF_IMM) QAR = qla;                     /* immediate? */
 
487
PC = PC + INST_LEN;                                     /* advance PC */
 
488
switch (op) {                                           /* case on op */
 
489
 
 
490
/* Transmit digit - P,Q are valid */
 
491
 
 
492
case OP_TD:
 
493
case OP_TDM:
 
494
        M[PAR] = M[QAR] & (FLAG | DIGIT);               /* move dig, flag */
 
495
        break;
 
496
 
 
497
/* Transmit field - P,Q are valid */
 
498
 
 
499
case OP_TF:
 
500
case OP_TFM:
 
501
        reason = xmt_field (PAR, QAR, 1);               /* xmit field */
 
502
        break;
 
503
 
 
504
/* Transmit record - P,Q are valid */
 
505
 
 
506
case OP_TR:
 
507
        reason = xmt_record (PAR, QAR, TRUE);           /* xmit record */
 
508
        break;
 
509
 
 
510
/* Transmit record no record mark - P,Q are valid */
 
511
 
 
512
case OP_TRNM:
 
513
        reason = xmt_record (PAR, QAR, FALSE);          /* xmit record but */
 
514
        break;                                          /* not rec mark */
 
515
 
 
516
/* Set flag - P is valid */
 
517
 
 
518
case OP_SF:
 
519
        M[PAR] = M[PAR] | FLAG;                         /* set flag on P */
 
520
        break;
 
521
 
 
522
/* Clear flag - P is valid */
 
523
 
 
524
case OP_CF:
 
525
        M[PAR] = M[PAR] & ~FLAG;                        /* clear flag on P */
 
526
        break;
 
527
 
 
528
/* Branch - P is valid */
 
529
 
 
530
case OP_B:
 
531
        BRANCH (PAR);                                   /* branch to P */
 
532
        break;
 
533
 
 
534
/* Branch and transmit - P,Q are valid */
 
535
 
 
536
case OP_BT:
 
537
case OP_BTM:
 
538
        reason = xmt_field (ADDR_S (PAR, 1), QAR, 1);   /* xmit field to P-1 */
 
539
        IR2 = PC;                                       /* save PC */
 
540
        BRANCH (PAR);                                   /* branch to P */
 
541
        break;
 
542
 
 
543
/* Branch and transmit floating - P,Q are valid */
 
544
 
 
545
case OP_BTFL:
 
546
        reason = xmt_field (ADDR_S (PAR, 1), QAR, 3);   /* skip 3 flags */
 
547
        IR2 = PC;                                       /* save PC */
 
548
        BRANCH (PAR);                                   /* branch to P */
 
549
        break;
 
550
 
 
551
/* Branch and transmit address - P,Q are valid */
 
552
 
 
553
case OP_BTA:
 
554
case OP_BTAM:
 
555
        reason = xmt_field (ADDR_S (PAR, 1), QAR, 4);   /* skip 4 flags */
 
556
        IR2 = PC;                                       /* save PC */
 
557
        BRANCH (PAR);                                   /* branch to P */
 
558
        break;
 
559
 
 
560
/* Branch back */
 
561
 
 
562
case OP_BB:
 
563
        if (PR1 != 1) {                                 /* PR1 valid? */
 
564
            BRANCH (PR1);                               /* return to PR1 */
 
565
            PR1 = 1;  }                                 /* invalidate */
 
566
        else if (IR2 != 1) {                            /* IR2 valid? */
 
567
            BRANCH (IR2);                               /* return to IR2 */
 
568
            IR2 = 1;  }                                 /* invalidate */
 
569
        else reason = STOP_INVRTN;                      /* MAR check */
 
570
        break;
 
571
 
 
572
/* Branch on digit (not zero) - P,Q are valid */
 
573
 
 
574
case OP_BD:
 
575
        if ((M[QAR] & DIGIT) != 0) {                    /* digit != 0? */
 
576
            BRANCH (PAR);  }                            /* branch */
 
577
        break;
 
578
 
 
579
/* Branch no flag - P,Q are valid */
 
580
 
 
581
case OP_BNF:
 
582
        if ((M[QAR] & FLAG) == 0) {                     /* flag == 0? */
 
583
            BRANCH (PAR);  }                            /* branch */
 
584
        break;
 
585
 
 
586
/* Branch no record mark (8-2 not set) - P,Q are valid */
 
587
 
 
588
case OP_BNR:
 
589
        if ((M[QAR] & REC_MARK) != REC_MARK) {          /* not rec mark? */
 
590
            BRANCH (PAR);  }                            /* branch */
 
591
        break;
 
592
 
 
593
/* Branch no group mark - P,Q are valid */
 
594
 
 
595
case OP_BNG:
 
596
        if ((M[QAR] & DIGIT) != GRP_MARK) {             /* not grp mark? */
 
597
            BRANCH (PAR);  }                            /* branch */
 
598
        break;
 
599
 
 
600
/* Branch (no) indicator - P is valid */
 
601
 
 
602
case OP_BI:
 
603
case OP_BNI:
 
604
        upd_ind ();                                     /* update indicators */
 
605
        t = get_2d (ADDR_A (saved_PC, I_BR));           /* get ind number */
 
606
        if ((t < 0) || (ind_table[t] < 0)) {            /* not valid? */
 
607
            reason = STOP_INVIND;                       /* stop */
 
608
            break;  }
 
609
        if ((ind[t] != 0) ^ (op == OP_BNI)) {           /* ind value correct? */
 
610
            BRANCH (PAR);  }                            /* branch */
 
611
        if (ind_table[t] > 0) ind[t] = 0;               /* reset if needed */
 
612
        break;
 
613
 
 
614
/* Add/subtract/compare - P,Q are valid */
 
615
 
 
616
case OP_A:
 
617
case OP_AM:
 
618
        reason = add_field (PAR, QAR, FALSE, TRUE, 0, &sta); /* add, store */
 
619
        if (sta == ADD_CARRY) ind[IN_OVF] = 1;          /* cout => ovflo */
 
620
        if (ar_stop && ind[IN_OVF]) reason = STOP_OVERFL;
 
621
        break;
 
622
 
 
623
case OP_S:
 
624
case OP_SM:
 
625
        reason = add_field (PAR, QAR, TRUE, TRUE, 0, &sta); /* sub, store */
 
626
        if (sta == ADD_CARRY) ind[IN_OVF] = 1;          /* cout => ovflo */
 
627
        if (ar_stop && ind[IN_OVF]) reason = STOP_OVERFL;
 
628
        break;
 
629
 
 
630
case OP_C:
 
631
case OP_CM:
 
632
        reason = add_field (PAR, QAR, TRUE, FALSE, 0, &sta); /* sub, nostore */
 
633
        if (sta == ADD_CARRY) ind[IN_OVF] = 1;          /* cout => ovflo */
 
634
        if (ar_stop && ind[IN_OVF]) reason = STOP_OVERFL;
 
635
        break;
 
636
 
 
637
/* Multiply - P,Q are valid */
 
638
 
 
639
case OP_M:
 
640
case OP_MM:
 
641
        reason = mul_field (PAR, QAR);                  /* multiply */
 
642
        break;
 
643
 
 
644
/* IO instructions - P is valid */
 
645
 
 
646
case OP_RA:
 
647
case OP_WA:
 
648
        if ((PAR & 1) == 0) {                           /* P even? */
 
649
            reason = STOP_INVEAD;                       /* stop */
 
650
            break;  }
 
651
case OP_K:
 
652
case OP_DN:
 
653
case OP_RN:
 
654
case OP_WN:
 
655
        dev = get_2d (ADDR_A (saved_PC, I_IO));         /* get IO dev */
 
656
        f0 = M[ADDR_A (saved_PC, I_CTL)] & DIGIT;       /* get function */
 
657
        f1 = M[ADDR_A (saved_PC, I_CTL + 1)] & DIGIT;
 
658
        if ((dev < 0) || (iodisp[dev] == NULL))         /* undefined dev? */
 
659
            reason = STOP_INVIO;                        /* stop */
 
660
        else reason = iodisp[dev] (op, PAR, f0, f1);    /* call device */
 
661
        break;
 
662
 
 
663
/* Divide special feature instructions */
 
664
 
 
665
case OP_LD:
 
666
case OP_LDM:
 
667
        for (i = 0; i < PROD_AREA_LEN; i++)             /* clear prod area */
 
668
            M[PROD_AREA + i] = 0;
 
669
        t = M[QAR] & FLAG;                              /* save Q sign */
 
670
        reason = xmt_divd (PAR, QAR);                   /* xmit dividend */
 
671
        M[PROD_AREA + PROD_AREA_LEN - 1] |= t;          /* set sign */
 
672
        break;
 
673
 
 
674
/* Divide - P,Q are valid */
 
675
 
 
676
case OP_D:
 
677
case OP_DM:
 
678
        reason = div_field (PAR, QAR, &t);              /* divide */
 
679
        ind[IN_EZ] = t;                                 /* set indicator */
 
680
        if ((reason == STOP_OVERFL) && !ar_stop)        /* ovflo stop? */
 
681
                reason = SCPE_OK;                       /* no */
 
682
        break;
 
683
 
 
684
/* Edit special feature instructions */
 
685
 
 
686
/* Move flag - P,Q are valid */
 
687
 
 
688
case OP_MF:
 
689
        M[PAR] = (M[PAR] & ~FLAG) | (M[QAR] & FLAG);    /* copy Q flag */
 
690
        M[QAR] = M[QAR] & ~FLAG;                        /* clr Q flag */
 
691
        break;
 
692
 
 
693
/* Transmit numeric strip - P,Q are valid, P is source */
 
694
 
 
695
case OP_TNS:
 
696
        if ((PAR & 1) == 0) {                           /* P must be odd */
 
697
            reason = STOP_INVEAD;
 
698
            break;  }
 
699
        reason = xmt_tns (QAR, PAR);                    /* xmit and strip */
 
700
        break;
 
701
 
 
702
/* Transmit numeric fill - P,Q are valid */
 
703
 
 
704
case OP_TNF:
 
705
        if ((PAR & 1) == 0) {                           /* P must be odd */
 
706
            reason = STOP_INVEAD;
 
707
            break;  }
 
708
        reason = xmt_tnf (PAR, QAR);                    /* xmit and strip */
 
709
        break;
 
710
 
 
711
/* Index special feature instructions */
 
712
 
 
713
/* Move address - P,Q are valid */
 
714
 
 
715
case OP_MA:
 
716
        for (i = 0; i < ADDR_LEN; i++) {                /* move 5 digits */
 
717
            M[PAR] = (M[PAR] & FLAG) | (M[QAR] & DIGIT);
 
718
            MM (PAR); MM (QAR);  }
 
719
        break;
 
720
 
 
721
/* Branch load index - P,Q are valid, Q not indexed */
 
722
 
 
723
case OP_BLX:
 
724
case OP_BLXM:
 
725
        idx = get_idx (ADDR_A (saved_PC, I_QL - 1));    /* get index */
 
726
        if (idx < 0) {                                  /* disabled? */
 
727
            reason = STOP_INVIDX;                       /* stop */
 
728
            break;  }
 
729
        xmt_index (GET_IDXADDR (idx), QAR);             /* copy Q to idx */
 
730
        BRANCH (PAR);                                   /* branch to P */
 
731
        break;
 
732
 
 
733
/* Branch store index - P,Q are valid, Q not indexed */
 
734
 
 
735
case OP_BSX:
 
736
        idx = get_idx (ADDR_A (saved_PC, I_QL - 1));    /* get index */
 
737
        if (idx < 0) {                                  /* disabled? */
 
738
            reason = STOP_INVIDX;                       /* stop */
 
739
            break;  }
 
740
        xmt_index (QAR, GET_IDXADDR (idx));             /* copy idx to Q */
 
741
        BRANCH (PAR);                                   /* branch to P */
 
742
        break;
 
743
 
 
744
/* Branch and modify index - P,Q are valid, Q not indexed */
 
745
 
 
746
case OP_BX:
 
747
        idx = get_idx (ADDR_A (saved_PC, I_QL - 1));    /* get index */
 
748
        if (idx < 0) {                                  /* disabled? */
 
749
            reason = STOP_INVIDX;                       /* stop */
 
750
            break;  }
 
751
        reason = add_field (GET_IDXADDR (idx), QAR, FALSE, TRUE, 0, &sta);
 
752
        if (ar_stop && ind[IN_OVF]) reason = STOP_OVERFL;
 
753
        BRANCH (PAR);                                   /* branch to P */
 
754
        break;
 
755
 
 
756
case OP_BXM:
 
757
        idx = get_idx (ADDR_A (saved_PC, I_QL - 1));    /* get index */
 
758
        if (idx < 0) {                                  /* disabled? */
 
759
            reason = STOP_INVIDX;                       /* stop */
 
760
            break;  }
 
761
        reason = add_field (GET_IDXADDR (idx), QAR, FALSE, TRUE, 3, &sta);
 
762
        if (ar_stop && ind[IN_OVF]) reason = STOP_OVERFL;
 
763
        BRANCH (PAR);                                   /* branch to P */
 
764
        break;
 
765
 
 
766
/* Branch conditionally and modify index - P,Q are valid, Q not indexed */
 
767
 
 
768
case OP_BCX:
 
769
        idx = get_idx (ADDR_A (saved_PC, I_QL - 1));    /* get index */
 
770
        if (idx < 0) {                                  /* disabled? */
 
771
            reason = STOP_INVIDX;                       /* stop */
 
772
            break;  }
 
773
        reason = add_field (GET_IDXADDR (idx), QAR, FALSE, TRUE, 0, &sta);
 
774
        if (ar_stop && ind[IN_OVF]) reason = STOP_OVERFL;
 
775
        if ((ind[IN_EZ] == 0) && (sta == ADD_NOCRY)) {  /* ~z, ~c, ~sign chg? */
 
776
            BRANCH (PAR);  }                            /* branch */
 
777
        break;
 
778
 
 
779
case OP_BCXM:
 
780
        idx = get_idx (ADDR_A (saved_PC, I_QL - 1));    /* get index */
 
781
        if (idx < 0) {                                  /* disabled? */
 
782
            reason = STOP_INVIDX;                       /* stop */
 
783
            break;  }
 
784
        reason = add_field (GET_IDXADDR (idx), QAR, FALSE, TRUE, 3, &sta);
 
785
        if (ar_stop && ind[IN_OVF]) reason = STOP_OVERFL;
 
786
        if ((ind[IN_EZ] == 0) && (sta == ADD_NOCRY)) {  /* ~z, ~c, ~sign chg? */
 
787
            BRANCH (PAR);  }                            /* branch */
 
788
        break;
 
789
 
 
790
/* Branch and select - P is valid */
 
791
 
 
792
case OP_BS:
 
793
        t = M[ADDR_A (saved_PC, I_SEL)] & DIGIT;        /* get select */
 
794
        switch (t) {                                    /* case on select */
 
795
        case 0:
 
796
            idxe = idxb = 0;                            /* indexing off */
 
797
            break;
 
798
        case 1:
 
799
            idxe = 1; idxb = 0;                         /* index band A */
 
800
            break;
 
801
        case 2:
 
802
            idxe = idxb = 1;                            /* index band B */
 
803
            break;
 
804
        case 8:
 
805
            iae = 0;                                    /* indirect off */
 
806
            break;
 
807
        case 9:
 
808
            iae = 1;                                    /* indirect on */
 
809
            break;
 
810
        default:
 
811
            reason = STOP_INVSEL;                       /* undefined */
 
812
            break;  }
 
813
        BRANCH (PAR);
 
814
        break;
 
815
 
 
816
/* Binary special feature instructions */
 
817
 
 
818
/* Branch on bit - P,Q are valid, Q is 4d address */
 
819
 
 
820
case OP_BBT:
 
821
        t = M[ADDR_A (saved_PC, I_Q)];                  /* get Q0 digit */
 
822
        if (t & M[QAR] & DIGIT) {                       /* match to mem? */
 
823
            BRANCH (PAR);  }                            /* branch */
 
824
        break;
 
825
 
 
826
/* Branch on mask - P,Q are valid, Q is 4d address */
 
827
 
 
828
case OP_BMK:
 
829
        t = M[ADDR_A (saved_PC, I_Q)];                  /* get Q0 digit */
 
830
        if (((t ^ M[QAR]) &                             /* match to mem? */
 
831
            ((t & FLAG)? (FLAG + DIGIT): DIGIT)) == 0) {
 
832
            BRANCH (PAR);  }                            /* branch */
 
833
        break;
 
834
 
 
835
/* Or - P,Q are valid */
 
836
 
 
837
case OP_ORF:
 
838
        reason = or_field (PAR, QAR);                   /* OR fields */
 
839
        break;
 
840
 
 
841
/* AND - P,Q are valid */
 
842
 
 
843
case OP_ANDF:
 
844
        reason = and_field (PAR, QAR);                  /* AND fields */
 
845
        break;
 
846
 
 
847
/* Exclusive or - P,Q are valid */
 
848
 
 
849
case OP_EORF:
 
850
        reason = xor_field (PAR, QAR);                  /* XOR fields */
 
851
        break;
 
852
 
 
853
/* Complement - P,Q are valid */
 
854
 
 
855
case OP_CPLF:
 
856
        reason = com_field (PAR, QAR);                  /* COM field */
 
857
        break;
 
858
 
 
859
/* Octal to decimal - P,Q are valid */
 
860
 
 
861
case OP_OTD:
 
862
        reason = oct_to_dec (PAR, QAR);                 /* convert */
 
863
        break;
 
864
 
 
865
/* Decimal to octal - P,Q are valid */
 
866
 
 
867
case OP_DTO:
 
868
        reason = dec_to_oct (PAR, QAR, &t);             /* convert */
 
869
        ind[IN_EZ] = t;                                 /* set indicator */
 
870
        if (ar_stop && ind[IN_OVF]) reason = STOP_OVERFL;
 
871
        break;
 
872
 
 
873
/* Floating point special feature instructions */
 
874
 
 
875
case OP_FADD:
 
876
        reason = fp_add (PAR, QAR, FALSE);              /* add */
 
877
        if (ar_stop && ind[IN_EXPCHK]) reason = STOP_EXPCHK;
 
878
        break;
 
879
 
 
880
case OP_FSUB:
 
881
        reason = fp_add (PAR, QAR, TRUE);               /* subtract */
 
882
        if (ar_stop && ind[IN_EXPCHK]) reason = STOP_EXPCHK;
 
883
        break;
 
884
 
 
885
case OP_FMUL:
 
886
        reason = fp_mul (PAR, QAR);                     /* multiply */
 
887
        if (ar_stop && ind[IN_EXPCHK]) reason = STOP_EXPCHK;
 
888
        break;
 
889
 
 
890
case OP_FDIV:
 
891
        reason = fp_div (PAR, QAR);                     /* divide */
 
892
        if (ar_stop && ind[IN_OVF]) reason = STOP_FPDVZ;
 
893
        if (ar_stop && ind[IN_EXPCHK]) reason = STOP_EXPCHK;
 
894
        break;
 
895
 
 
896
case OP_FSL:
 
897
        reason = fp_fsl (PAR, QAR);                     /* shift left */
 
898
        break;
 
899
 
 
900
case OP_FSR:
 
901
        reason = fp_fsr (PAR, QAR);                     /* shift right */
 
902
        break;
 
903
 
 
904
/* Halt */
 
905
 
 
906
case OP_H:
 
907
        saved_PC = PC;                                  /* commit inst */
 
908
        reason = STOP_HALT;                             /* stop */
 
909
        break;
 
910
 
 
911
/* NOP */
 
912
 
 
913
case OP_NOP:
 
914
        break;
 
915
 
 
916
/* Invalid instruction code */
 
917
 
 
918
default:
 
919
        reason = STOP_INVINS;                           /* stop */
 
920
        break;  }                                       /* end switch */
 
921
        }                                               /* end while */
 
922
 
 
923
/* Simulation halted */
 
924
 
 
925
pcq_r->qptr = pcq_p;                                    /* update pc q ptr */
 
926
upd_ind ();
 
927
return reason;
 
928
}
 
929
 
 
930
/* Utility routines */
 
931
 
 
932
/* Get 2 digit field
 
933
 
 
934
   Inputs:
 
935
        ad      =       address of high digit
 
936
   Outputs:
 
937
        val     =       field converted to binary
 
938
                        -1 if bad digit
 
939
*/
 
940
 
 
941
int32 get_2d (uint32 ad)
 
942
{
 
943
int32 d, d1;
 
944
 
 
945
d = M[ad] & DIGIT;                                      /* get 1st digit */
 
946
d1 = M[ADDR_A (ad, 1)] & DIGIT;                         /* get 2nd digit */
 
947
if (BAD_DIGIT (d) || BAD_DIGIT (d1)) return -1;         /* bad? error */
 
948
return ((d * 10) + d1);                                 /* cvt to binary */
 
949
}
 
950
 
 
951
/* Get address routine
 
952
 
 
953
   Inputs:
 
954
        alast   =       address of low digit
 
955
        lnt     =       length
 
956
        indexok =       TRUE if indexing allowed
 
957
        &addr   =       pointer to address output
 
958
   Output:
 
959
        return  =       error status (in terms of P address)
 
960
        addr    =       address converted to binary
 
961
 
 
962
   Notes:
 
963
   - If indexing produces a negative result, the effective address is
 
964
     the 10's complement of the result
 
965
   - An address that exceeds memory produces a MAR check stop
 
966
*/
 
967
 
 
968
t_stat get_addr (uint32 alast, int32 lnt, t_bool indexok, uint32 *reta)
 
969
{
 
970
uint8 indir;
 
971
int32 cnt, idx, idxa, idxv, addr;
 
972
 
 
973
if (iae) indir = FLAG;                                  /* init indirect */
 
974
else indir = 0;
 
975
 
 
976
cnt = 0;                                                /* count depth */
 
977
do {    indir = indir & M[alast];                       /* get indirect */
 
978
        if (cvt_addr (alast, lnt, FALSE, &addr))        /* cvt addr to bin */
 
979
            return STOP_INVPDG;                         /* bad? */
 
980
        idx = get_idx (ADDR_S (alast, 1));              /* get index reg num */
 
981
        if (indexok && (idx > 0)) {                     /* indexable? */
 
982
            idxa = GET_IDXADDR (idx);                   /* get idx reg addr */
 
983
            if (cvt_addr (idxa, ADDR_LEN, TRUE, &idxv)) /* cvt idx reg */
 
984
                return STOP_INVPDG;
 
985
            addr = addr + idxv;                         /* add in index */
 
986
            if (addr < 0) addr = addr + 100000;  }      /* -? 10's comp */
 
987
        if (addr >= (int32) MEMSIZE) return STOP_INVPAD;/* invalid addr? */
 
988
        alast = addr;                                   /* new address */
 
989
        lnt = ADDR_LEN;  }                              /* std len */
 
990
while (indir && (cnt++ < ind_max));
 
991
if (cnt > ind_max) return STOP_INVPIA;                  /* indir too deep? */
 
992
*reta = addr;                                           /* return address */
 
993
return SCPE_OK;
 
994
}
 
995
 
 
996
/* Convert address to binary
 
997
 
 
998
   Inputs:
 
999
        alast   =       address of low digit
 
1000
        lnt     =       length
 
1001
        signok  =       TRUE if signed
 
1002
        val     =       address of output
 
1003
   Outputs:
 
1004
        status  =       0 if ok, != 0 if error
 
1005
*/
 
1006
 
 
1007
t_stat cvt_addr (uint32 alast, int32 lnt, t_bool signok, int32 *val)
 
1008
{
 
1009
int32 sign = 0, addr = 0, t;
 
1010
 
 
1011
if (signok && (M[alast] & FLAG)) sign = 1;              /* signed? */
 
1012
alast = alast - lnt;                                    /* find start */
 
1013
do {    PP (alast);                                     /* incr mem addr */
 
1014
        t = M[alast] & DIGIT;                           /* get digit */
 
1015
        if (BAD_DIGIT (t)) return STOP_INVDIG;          /* bad? error */
 
1016
        addr = (addr * 10) + t;  }                      /* cvt to bin */
 
1017
while (--lnt > 0);
 
1018
if (sign) *val = -addr;                                 /* minus? */
 
1019
else *val = addr;
 
1020
return SCPE_OK;
 
1021
}
 
1022
 
 
1023
/* Get index register number
 
1024
 
 
1025
   Inputs:
 
1026
        aidx    =       address of low digit
 
1027
   Outputs:
 
1028
        index   =       >0 if indexed
 
1029
                        =0 if not indexed
 
1030
                        <0 if indexing disabled
 
1031
*/
 
1032
 
 
1033
t_stat get_idx (uint32 aidx)
 
1034
{
 
1035
int32 i, idx;
 
1036
 
 
1037
if (idxe == 0) return -1;                               /* indexing off? */
 
1038
for (i = idx = 0; i < 3; i++) {                         /* 3 flags worth */
 
1039
        if (M[aidx] & FLAG) idx = idx | (1 << i);       /* test flag */
 
1040
        MM (aidx);  }                                   /* next digit */
 
1041
return idx;
 
1042
}
 
1043
 
 
1044
/* Update indicators routine */
 
1045
 
 
1046
void upd_ind (void)
 
1047
{
 
1048
ind[IN_HPEZ] = ind[IN_HP] | ind[IN_EZ];                 /* HPEZ = HP | EZ */
 
1049
ind[IN_DERR] = ind[IN_DACH] | ind[IN_DWLR] | ind[IN_DCYO];
 
1050
ind[IN_ANYCHK] = ind[IN_RDCHK] | ind[IN_WRCHK] |        /* ANYCHK = all chks */
 
1051
        ind[IN_MBREVEN] | ind[IN_MBRODD] |
 
1052
        ind[IN_PRCHK] | ind[IN_DACH];
 
1053
ind[IN_IXN] = ind[IN_IXA] = ind[IN_IXB] = 0;            /* clr index indics */
 
1054
if (!idxe) ind[IN_IXN] = 1;                             /* off? */
 
1055
else if (!idxb) ind[IN_IXA] = 1;                        /* on, band A? */
 
1056
else ind[IN_IXB] = 1;                                   /* no, band B */
 
1057
return;
 
1058
}
 
1059
 
 
1060
/* Transmit routines */
 
1061
 
 
1062
/* Transmit field from 's' to 'd' - ignore first 'skp' flags */
 
1063
 
 
1064
t_stat xmt_field (uint32 d, uint32 s, uint32 skp)
 
1065
{
 
1066
uint32 cnt = 0;
 
1067
uint8 t;
 
1068
 
 
1069
do {    t = M[d] = M[s] & (FLAG | DIGIT);               /* copy src to dst */
 
1070
        MM (d); MM (s);                                 /* decr mem addrs */
 
1071
        if (cnt++ >= MEMSIZE) return STOP_FWRAP;  }     /* (stop runaway) */
 
1072
while (((t & FLAG) == 0) || (cnt <= skp));              /* until flag */
 
1073
return SCPE_OK;
 
1074
}
 
1075
 
 
1076
/* Transmit record from 's' to 'd' - copy record mark if 'cpy' = TRUE */
 
1077
 
 
1078
t_stat xmt_record (uint32 d, uint32 s, t_bool cpy)
 
1079
{
 
1080
uint32 cnt = 0;
 
1081
 
 
1082
while ((M[s] & REC_MARK) != REC_MARK) {                 /* until rec mark */
 
1083
        M[d] = M[s] & (FLAG | DIGIT);                   /* copy src to dst */
 
1084
        PP (d); PP (s);                                 /* incr mem addrs */
 
1085
        if (cnt++ >= MEMSIZE) return STOP_RWRAP;  }     /* (stop runaway) */
 
1086
if (cpy) M[d] = M[s] & (FLAG | DIGIT);                  /* copy rec mark */
 
1087
return SCPE_OK;
 
1088
}
 
1089
 
 
1090
/* Transmit index from 's' to 'd' - fixed five character field */
 
1091
 
 
1092
t_stat xmt_index (uint32 d, uint32 s)
 
1093
{
 
1094
int32 i;
 
1095
 
 
1096
M[d] = M[s] & (FLAG | DIGIT);                           /* preserve sign */
 
1097
MM (d); MM (s);                                         /* decr mem addrs */
 
1098
for (i = 0; i < ADDR_LEN - 2; i++) {                    /* copy 3 digits */
 
1099
        M[d] = M[s] & DIGIT;                            /* without flags */
 
1100
        MM (d); MM (s);  }                              /* decr mem addrs */
 
1101
M[d] = (M[s] & DIGIT) | FLAG;                           /* set flag on last */
 
1102
return SCPE_OK;
 
1103
}
 
1104
 
 
1105
/* Transmit dividend from 'd' to 's' - clear flag on first digit */
 
1106
 
 
1107
t_stat xmt_divd (uint32 d, uint32 s)
 
1108
{
 
1109
uint32 cnt = 0;
 
1110
 
 
1111
M[d] = M[s] & DIGIT;                                    /* first w/o flag */
 
1112
do {    MM (d); MM (s);                                 /* decr mem addrs */
 
1113
        M[d] = M[s] & (FLAG | DIGIT);                   /* copy src to dst */
 
1114
        if (cnt++ >= MEMSIZE) return STOP_FWRAP;  }     /* (stop runaway) */
 
1115
while ((M[d] & FLAG) == 0);                             /* until src flag */
 
1116
return SCPE_OK;
 
1117
}
 
1118
 
 
1119
/* Transmit numeric strip from 's' to 'd' - s is odd */
 
1120
 
 
1121
t_stat xmt_tns (uint32 d, uint32 s)
 
1122
{
 
1123
uint32 cnt = 0;
 
1124
uint8 t, z;
 
1125
 
 
1126
t = M[s] & DIGIT;                                       /* get units */
 
1127
z = M[s - 1] & DIGIT;                                   /* get zone */
 
1128
if ((z == 1) || (z == 5) || ((z == 2) && (t == 0)))     /* 1x, 5x, 20? */
 
1129
        M[d] = t | FLAG;                                /* set flag */
 
1130
else M[d] = t;                                          /* else clear flag */
 
1131
do {    MM (d);                                         /* decr mem addrs */
 
1132
        s = ADDR_S (s, 2);
 
1133
        t = M[d] & FLAG;                                /* save dst flag */
 
1134
        M[d] = M[s] & (FLAG | DIGIT);                   /* copy src to dst */
 
1135
        if (cnt >= MEMSIZE) return STOP_FWRAP;          /* (stop runaway) */
 
1136
        cnt = cnt + 2;  }
 
1137
while (t == 0);                                         /* until dst flag */
 
1138
M[d] = M[d] | FLAG;                                     /* set flag at end */
 
1139
return SCPE_OK;
 
1140
}
 
1141
 
 
1142
/* Transmit numeric fill from 's' to 'd' - d is odd */
 
1143
 
 
1144
t_stat xmt_tnf (uint32 d, uint32 s)
 
1145
{
 
1146
uint32 cnt = 0;
 
1147
uint8 t;
 
1148
 
 
1149
t = M[s];                                               /* get 1st digit */
 
1150
M[d] = t & DIGIT;                                       /* store */
 
1151
M[d - 1] = (t & FLAG)? 5: 7;                            /* set sign from flag */
 
1152
do {    MM (s);                                         /* decr mem addr */
 
1153
        d = ADDR_S (d, 2);
 
1154
        t = M[s];                                       /* get src digit */
 
1155
        M[d] = t & DIGIT;                               /* move to dst, no flag */
 
1156
        M[d - 1] = 7;                                   /* set zone */
 
1157
        if (cnt >= MEMSIZE) return STOP_FWRAP;          /* (stop runaway) */
 
1158
        cnt = cnt + 2;  }
 
1159
while ((t & FLAG) == 0);                                /* until src flag */
 
1160
return SCPE_OK;
 
1161
}
 
1162
 
 
1163
/* Add routine
 
1164
 
 
1165
   Inputs:
 
1166
        d       =       destination field low (P)
 
1167
        s       =       source field low (Q)
 
1168
        sub     =       TRUE if subtracting
 
1169
        sto     =       TRUE if storing
 
1170
        skp     =       number of source field flags, beyond sign, to ignore
 
1171
   Output:
 
1172
        return  =       status
 
1173
        sta     =       ADD_NOCRY: no carry out, no sign change
 
1174
                        ADD_SCHNG: sign change
 
1175
                        ADD_CARRY: carry out
 
1176
 
 
1177
   Reference Manual: "When the sum is zero, the sign of the P field
 
1178
   is retained."
 
1179
*/
 
1180
 
 
1181
t_stat add_field (uint32 d, uint32 s, t_bool sub, t_bool sto, uint32 skp, int32 *sta)
 
1182
{
 
1183
uint32 cry, src, dst, res, comp, dp, dsv;
 
1184
uint32 src_f = 0, cnt = 0, dst_f;
 
1185
 
 
1186
*sta = ADD_NOCRY;                                       /* assume no cry */
 
1187
dsv = d;                                                /* save dst */
 
1188
comp = ((M[d] ^ M[s]) & FLAG) ^ (sub? FLAG: 0);         /* set compl flag */
 
1189
cry = 0;                                                /* clr carry */
 
1190
ind[IN_HP] = ((M[d] & FLAG) == 0);                      /* set sign from res */
 
1191
ind[IN_EZ] = 1;                                         /* assume zero */
 
1192
 
 
1193
dst = M[d] & DIGIT;                                     /* 1st digits */
 
1194
src = M[s] & DIGIT;
 
1195
if (BAD_DIGIT (dst) || BAD_DIGIT (src))                 /* bad digit? */
 
1196
     return STOP_INVDIG;
 
1197
if (comp) src = 10 - src;                               /* complement? */
 
1198
res = add_one_digit (dst, src, &cry);                   /* add */
 
1199
if (sto) M[d] = (M[d] & FLAG) | res;                    /* store */
 
1200
MM (d); MM (s);                                         /* decr mem addrs */
 
1201
do {    dst = M[d] & DIGIT;                             /* get dst digit */
 
1202
        dst_f = M[d] & FLAG;                            /* get dst flag */
 
1203
        if (src_f) src = 0;                             /* src done? src = 0 */
 
1204
        else {
 
1205
            src = M[s] & DIGIT;                         /* get src digit */
 
1206
            if (cnt >= skp) src_f = M[s] & FLAG;        /* get src flag */
 
1207
            MM (s);  }                                  /* decr src addr */
 
1208
        if (BAD_DIGIT (dst) || BAD_DIGIT (src))         /* bad digit? */
 
1209
            return STOP_INVDIG;
 
1210
        if (comp) src = 9 - src;                        /* complement? */
 
1211
        res = add_one_digit (dst, src, &cry);           /* add */
 
1212
        if (sto) M[d] = dst_f | res;                    /* store */
 
1213
        MM (d);                                         /* decr dst addr */
 
1214
        if (cnt++ >= MEMSIZE) return STOP_FWRAP;  }     /* (stop runaway) */
 
1215
while (dst_f == 0);                                     /* until dst done */
 
1216
if (!src_f) ind[IN_OVF] = 1;                            /* !src done? ovf */
 
1217
if (comp && !cry && !ind[IN_EZ]) {                      /* recomp needed? */
 
1218
        ind[IN_HP] = ind[IN_HP] ^ 1;                    /* flip indicator */
 
1219
        if (sto) {                                      /* storing? */
 
1220
            for (cry = 1, dp = dsv; dp != d; ) {        /* rescan */
 
1221
                dst = M[dp] & DIGIT;                    /* get dst digit */
 
1222
                res = add_one_digit (9 - dst, 0, &cry); /* "add" */
 
1223
                M[dp] = (M[dp] & FLAG) | res;           /* store */
 
1224
                MM (dp);  }                             /* decr dst addr */
 
1225
            M[dsv] = M[dsv] ^ FLAG;  }                  /* compl sign */
 
1226
        *sta = ADD_SIGNC;                               /* sign changed */
 
1227
        return SCPE_OK;  }                              /* end if recomp */
 
1228
if (ind[IN_EZ]) ind[IN_HP] = 0;                         /* res = 0? clr HP */
 
1229
if (!comp && cry) *sta = ADD_CARRY;                     /* set status */
 
1230
return SCPE_OK;
 
1231
}
 
1232
 
 
1233
/* Add one digit via table (Model 1) or "hardware" (Model 2) */
 
1234
 
 
1235
uint32 add_one_digit (uint32 dst, uint32 src, uint32 *cry)
 
1236
{
 
1237
uint32 res;
 
1238
 
 
1239
if (*cry) src = src + 1;                                /* cry in? incr src */
 
1240
if (src >= 10) {                                        /* src > 10? */
 
1241
        src = src - 10;                                 /* src -= 10 */
 
1242
        *cry = 1;  }                                    /* carry out */
 
1243
else *cry = 0;                                          /* else no carry */
 
1244
if (cpu_unit.flags & IF_MII)                            /* Model 2? */
 
1245
        res = sum_table[dst + src];                     /* "hardware" */
 
1246
else res = M[ADD_TABLE + (dst * 10) + src];             /* table lookup */
 
1247
if (res & FLAG) *cry = 1;                               /* carry out? */
 
1248
if (res & DIGIT) ind[IN_EZ] = 0;                        /* nz? clr ind */
 
1249
return res & DIGIT;
 
1250
}
 
1251
 
 
1252
/* Multiply routine 
 
1253
 
 
1254
   Inputs:
 
1255
        mpc     =       multiplicand address
 
1256
        mpy     =       multiplier address
 
1257
   Outputs:
 
1258
        return  =       status
 
1259
 
 
1260
   Reference manual: "A zero product may have a negative or positive sign,
 
1261
   depending on the signs of the fields at the P and Q addresses."
 
1262
*/
 
1263
 
 
1264
t_stat mul_field (uint32 mpc, uint32 mpy)
 
1265
{
 
1266
int32 i;
 
1267
uint32 pro;                                             /* prod pointer */
 
1268
uint32 mpyd, mpyf;                                      /* mpy digit, flag */
 
1269
uint32 cnt = 0;                                         /* counter */
 
1270
uint8 sign;                                             /* final sign */
 
1271
t_stat r;
 
1272
 
 
1273
PR1 = 1;                                                /* step on PR1 */
 
1274
for (i = 0; i < PROD_AREA_LEN; i++)                     /* clr prod area */
 
1275
        M[PROD_AREA + i] = 0;
 
1276
sign = (M[mpc] & FLAG) ^ (M[mpy] & FLAG);               /* get final sign */
 
1277
ind[IN_HP] = (sign == 0);                               /* set indicators */
 
1278
ind[IN_EZ] = 1;
 
1279
pro = PROD_AREA + PROD_AREA_LEN - 1;                    /* product ptr */
 
1280
 
 
1281
/* Loop on multiplier (mpy) and product (pro) digits */
 
1282
 
 
1283
do {    mpyd = M[mpy] & DIGIT;                          /* multiplier digit */
 
1284
        mpyf = (M[mpy] & FLAG) && (cnt != 0);           /* last digit flag */
 
1285
        if (BAD_DIGIT (mpyd)) return STOP_INVDIG;       /* bad? */
 
1286
        r = mul_one_digit (mpyd, mpc, pro, mpyf);       /* prod += mpc*mpy_dig */
 
1287
        if (r != SCPE_OK) return r;                     /* error? */
 
1288
        MM (mpy); MM (pro);                             /* decr mpyr, prod addrs */
 
1289
        if (cnt++ > MEMSIZE) return STOP_FWRAP;  }      /* (stop runaway) */
 
1290
while ((mpyf == 0) || (cnt <= 1));                      /* until mpyr flag */
 
1291
 
 
1292
if (ind[IN_EZ]) ind[IN_HP] = 0;                         /* res = 0? clr HP */
 
1293
M[PROD_AREA + PROD_AREA_LEN - 1] |= sign;               /* set final sign */
 
1294
return SCPE_OK;
 
1295
}
 
1296
 
 
1297
/* Multiply step
 
1298
 
 
1299
   Inputs:
 
1300
        mpyd    =       multiplier digit (tested valid)
 
1301
        mpcp    =       multiplicand low address
 
1302
        prop    =       product low address
 
1303
        last    =       last iteration flag (set flag on high product)
 
1304
   Outputs:
 
1305
        prod    +=      multiplicand * multiplier_digit
 
1306
        return  =       status
 
1307
 
 
1308
   The multiply table address is constructed as follows:
 
1309
   - double the multiplier digit
 
1310
   - use the 10's digit of the doubled result, + 1, as the 100's digit
 
1311
     of the table address
 
1312
   - use the multiplicand digit as the 10's digit of the table address
 
1313
   - use the unit digit of the doubled result as the unit digit of the
 
1314
     table address
 
1315
   EZ indicator is cleared if a non-zero digit is ever generated
 
1316
*/
 
1317
 
 
1318
t_stat mul_one_digit (uint32 mpyd, uint32 mpcp, uint32 prop, uint32 last)
 
1319
{
 
1320
uint32 mpta, mptb;                                      /* mult table */
 
1321
uint32 mptd;                                            /* mult table digit */
 
1322
uint32 mpcd, mpcf;                                      /* mpc digit, flag */
 
1323
uint32 prwp;                                            /* prod working ptr */
 
1324
uint32 prod;                                            /* product digit */
 
1325
uint32 cry;                                             /* carry */
 
1326
uint32 mpcc, cryc;                                      /* counters */
 
1327
 
 
1328
mptb = MUL_TABLE + ((mpyd <= 4)? (mpyd * 2):            /* set mpy table 100's, */
 
1329
        (((mpyd - 5) * 2) + 100));                      /* 1's digits */
 
1330
 
 
1331
/* Inner loop on multiplicand (mpcp) and product (prop) digits */
 
1332
 
 
1333
mpcc = 0;                                               /* multiplicand ctr */
 
1334
do {    prwp = prop;                                    /* product working ptr */
 
1335
        mpcd = M[mpcp] & DIGIT;                         /* multiplicand digit */
 
1336
        mpcf = M[mpcp] & FLAG;                          /* multiplicand flag */
 
1337
        if (BAD_DIGIT (mpcd)) return STOP_INVDIG;       /* bad? */
 
1338
        mpta = mptb + (mpcd * 10);                      /* mpy table 10's digit */
 
1339
        cry = 0;                                        /* init carry */
 
1340
        mptd = M[mpta] & DIGIT;                         /* mpy table digit */
 
1341
        if (BAD_DIGIT (mptd)) return STOP_INVDIG;       /* bad? */
 
1342
        prod = M[prwp] & DIGIT;                         /* product digit */
 
1343
        if (BAD_DIGIT (prod)) return STOP_INVDIG;       /* bad? */
 
1344
        M[prwp] = add_one_digit (prod, mptd, &cry);     /* add mpy tbl to prod */
 
1345
        MM (prwp);                                      /* decr working ptr */
 
1346
        mptd = M[mpta + 1] & DIGIT;                     /* mpy table digit */
 
1347
        if (BAD_DIGIT (mptd)) return STOP_INVDIG;       /* bad? */
 
1348
        prod = M[prwp] & DIGIT;                         /* product digit */
 
1349
        if (BAD_DIGIT (prod)) return STOP_INVDIG;       /* bad? */
 
1350
        M[prwp] = add_one_digit (prod, mptd, &cry);     /* add mpy tbl to prod */
 
1351
        cryc = 0;                                       /* (stop runaway) */
 
1352
        while (cry) {                                   /* propagate carry */
 
1353
            MM (prwp);                                  /* decr working ptr */
 
1354
            prod = M[prwp] & DIGIT;                     /* product digit */
 
1355
            if (BAD_DIGIT (prod)) return STOP_INVDIG;   /* bad? */
 
1356
            M[prwp] = add_one_digit (prod, 0, &cry);    /* add cry */
 
1357
            if (cryc++ > MEMSIZE) return STOP_FWRAP;  }
 
1358
        MM (mpcp); MM (prop);                           /* decr mpc, prod ptrs */
 
1359
        if (mpcc++ > MEMSIZE) return STOP_FWRAP;  }
 
1360
while ((mpcf == 0) || (mpcc <= 1));                     /* until mpcf flag */
 
1361
if (last) 
 
1362
        M[prop] = M[prop] | FLAG;                       /* flag high product */
 
1363
return SCPE_OK;
 
1364
}
 
1365
 
 
1366
/* Divide routine - comments from Geoff Kuenning's 1620 simulator
 
1367
 
 
1368
   The destination of the divide is given by:
 
1369
 
 
1370
        100 - <# digits in quotient>
 
1371
 
 
1372
   Which is more easily calculated as:
 
1373
 
 
1374
        100 - <# digits in divisor> - <# digits in dividend>
 
1375
 
 
1376
   The quotient goes into 99 minus the divisor length.  The
 
1377
   remainder goes into 99.  The load dividend instruction (above)
 
1378
   should have specified a P address of 99 minus the size of the
 
1379
   divisor.
 
1380
 
 
1381
   Note that this all implies that "dest" points to the *leftmost*
 
1382
   digit of the dividend.
 
1383
 
 
1384
   After the division, the assumed decimal point will be as many
 
1385
   positions to the left as there are digits in the divisor.  In
 
1386
   other words, a 4-digit divisor will produce 4 (assumed) decimal
 
1387
   places.
 
1388
 
 
1389
   There are other ways to do these things.  In particular, the
 
1390
   load-dividend instruction doesn't have to specify the above
 
1391
   formula; if it's done differently, then you don't have to get
 
1392
   decimal places.  This is not well-explained in the books I have.
 
1393
 
 
1394
   How to divide on a 1620:
 
1395
 
 
1396
   The dividend is the field at 99:
 
1397
 
 
1398
            90 = _1234567890
 
1399
 
 
1400
   The divisor is somewhere else in memory:
 
1401
 
 
1402
            _03
 
1403
 
 
1404
   The divide operation specifies the left-most digit of the
 
1405
   dividend as the place to begin trial subtractions:
 
1406
 
 
1407
            DM  90,3
 
1408
 
 
1409
   The loop works as follows:
 
1410
 
 
1411
        1.  Call the left-most digit of the dividend "current_dividend".
 
1412
            Call the location current_dividend - <divisor_length>
 
1413
            "quotient_digit".
 
1414
        2.  Clear the flag at current_dividend, and set one at
 
1415
            quotient_digit.
 
1416
 
 
1417
                88 = _001234567890, q_d = 88, c_d = 90
 
1418
            [Not actually done; divisor length controls subtract.]
 
1419
        3.  Subtract the divisor from the field at current-dividend,
 
1420
            using normal 1620 rules, except that signs are ignored.
 
1421
            Continue these subtractions until either 10 subtractions
 
1422
            have been done, or you get a negative result:
 
1423
 
 
1424
                88 = _00_2234567890, q_d = 88, c_d = 90
 
1425
        4.  If 10 subtractions have been done, set the overflow
 
1426
            indicator and abort.  Otherwise, add the divisor back to
 
1427
            correct for the oversubtraction:
 
1428
 
 
1429
                88 = _001234567890, q_d = 88, c_d = 90
 
1430
        5.  Store the (net) number of subtractions in quotient_digit:
 
1431
 
 
1432
                88 = _001234567890, q_d = 88, c_d = 90
 
1433
        6.  If this is not the first pass, clear the flag at
 
1434
            quotient_digit.  Increment quotient_digit and
 
1435
            current_dividend, and set a flag at the new
 
1436
            quotient_digit:
 
1437
 
 
1438
                88 = _0_01234567890, q_d = 89, c_d = 91
 
1439
            [If first pass, set a flag at quotient digit.]
 
1440
        7.  If current_dividend is not 100, repeat steps 3 through 7.
 
1441
        8.  Set flags at 99 and quotient_digit - 1 according to the
 
1442
            rules of algebra:  the quotient's sign is the exclusive-or
 
1443
            of the signs of the divisor and dividend, and the
 
1444
            remainder has the sign of the dividend:
 
1445
 
 
1446
                 10 /  3 =  3 remainder  1
 
1447
                 10 / -3 = -3 remainder  1
 
1448
                -10 /  3 = -3 remainder -1
 
1449
                -10 / -3 =  3 remainder -1
 
1450
  
 
1451
            This preserves the relationship dd = q * dv + r.
 
1452
 
 
1453
   Our example continues as follows for steps 3 through 7:
 
1454
  
 
1455
            3.  88 = _0_00_334567890, q_d = 89, c_d = 91
 
1456
            4.  88 = _0_00034567890
 
1457
            5.  88 = _0_40034567890
 
1458
            6.  88 = _04_0034567890, q_d = 90, c_d = 92
 
1459
            3.  88 = _04_00_34567890
 
1460
            4.  88 = _04_0004567890
 
1461
            5.  88 = _04_1004567890
 
1462
            6.  88 = _041_004567890, q_d = 91, c_d = 93
 
1463
            3.  88 = _041_00_2567890
 
1464
            4.  88 = _041_001567890
 
1465
            5.  88 = _041_101567890
 
1466
            6.  88 = _0411_01567890, q_d = 92, c_d = 94
 
1467
            3.  88 = _0411_00_367890
 
1468
            4.  88 = _0411_00067890
 
1469
            5.  88 = _0411_50067890
 
1470
            6.  88 = _04115_0067890, q_d = 93, c_d = 95
 
1471
            3.  88 = _04115_00_37890
 
1472
            4.  88 = _04115_0007890
 
1473
            5.  88 = _04115_2007890
 
1474
            6.  88 = _041152_007890, q_d = 94, c_d = 96
 
1475
            3.  88 = _041152_00_2890
 
1476
            4.  88 = _041152_001890
 
1477
            5.  88 = _041152_201890
 
1478
            6.  88 = _0411522_01890, q_d = 95, c_d = 97
 
1479
            3.  88 = _0411522_00_390
 
1480
            4.  88 = _0411522_00090
 
1481
            5.  88 = _0411522_60090
 
1482
            6.  88 = _04115226_0090, q_d = 96, c_d = 98
 
1483
            3.  88 = _04115226_00_30
 
1484
            4.  88 = _04115226_0000
 
1485
            5.  88 = _04115226_3000
 
1486
            6.  88 = _041152263_000, q_d = 97, c_d = 99
 
1487
            3.  88 = _041152263_00_3
 
1488
            4.  88 = _041152263_000
 
1489
            5.  88 = _041152263_000
 
1490
            6.  88 = _0411522630_00, q_d = 98, c_d = 100
 
1491
 
 
1492
   In the actual code below, we elide several of these steps in
 
1493
   various ways for convenience and efficiency.
 
1494
 
 
1495
   Note that the EZ indicator is NOT valid for divide, because it
 
1496
   is cleared by any non-zero result in an intermediate add.  The
 
1497
   code maintains its own EZ indicator for the quotient.
 
1498
*/
 
1499
 
 
1500
t_stat div_field (uint32 dvd, uint32 dvr, int32 *ez)
 
1501
{
 
1502
uint32 quop, quod, quos;                                /* quo ptr, dig, sign */
 
1503
uint32 dvds;                                            /* dvd sign */
 
1504
t_bool first = TRUE;                                    /* first pass */
 
1505
t_stat r;
 
1506
 
 
1507
dvds = (M[PROD_AREA + PROD_AREA_LEN - 1]) & FLAG;       /* dividend sign */
 
1508
quos = dvds ^ (M[dvr] & FLAG);                          /* quotient sign */
 
1509
ind[IN_HP] = (quos == 0);                               /* set indicators */
 
1510
*ez = 1;
 
1511
 
 
1512
/* Loop on current dividend, high order digit at dvd */
 
1513
 
 
1514
do {    r = div_one_digit (dvd, dvr, 10, &quod, &quop); /* dev quo digit */
 
1515
        if (r != SCPE_OK) return r;                     /* error? */
 
1516
 
 
1517
/* Store quotient digit and advance current dividend pointer */
 
1518
 
 
1519
        if (first) {                                    /* first pass? */
 
1520
            if (quod >= 10) {                           /* overflow? */
 
1521
                ind[IN_OVF] = 1;                        /* set indicator */
 
1522
                return STOP_OVERFL;  }                  /* stop */
 
1523
            M[quop] = FLAG | quod;                      /* set flag on quo */
 
1524
            first = FALSE;  }
 
1525
        else M[quop] = quod;                            /* store quo digit */
 
1526
        if (quod) *ez = 0;                              /* if nz, clr ind */
 
1527
        PP (dvd);  }                                    /* incr dvd ptr */
 
1528
while (dvd != (PROD_AREA + PROD_AREA_LEN));             /* until end prod */
 
1529
 
 
1530
/* Division done.  Set signs of quo, rem, set flag on high order remainder */
 
1531
 
 
1532
if (*ez) ind[IN_HP] = 0;                                /* res = 0? clr HP */
 
1533
M[PROD_AREA + PROD_AREA_LEN - 1] |= dvds;               /* remainder sign */
 
1534
M[quop] = M[quop] | quos;                               /* quotient sign */
 
1535
PP (quop);                                              /* high remainder */
 
1536
M[quop] = M[quop] | FLAG;                               /* set flag */
 
1537
return SCPE_OK;
 
1538
}
 
1539
 
 
1540
/* Divide step
 
1541
 
 
1542
   Inputs:
 
1543
        dvd     =       current dividend address (high digit)
 
1544
        dvr     =       divisor address (low digit)
 
1545
        max     =       max number of iterations before overflow
 
1546
        &quod   =       address to store quotient digit
 
1547
        &quop   =       address to store quotient pointer (can be NULL)
 
1548
   Outputs:
 
1549
        return  =       status
 
1550
 
 
1551
   Divide step calculates a quotient digit by repeatedly subtracting the
 
1552
   divisor from the current dividend.  The divisor's length controls the
 
1553
   subtraction; dividend flags are ignored.
 
1554
*/
 
1555
 
 
1556
t_stat div_one_digit (uint32 dvd, uint32 dvr, uint32 max,
 
1557
                     uint32 *quod, uint32 *quop)
 
1558
{
 
1559
uint32 dvrp, dvrd, dvrf;                                /* dvr ptr, dig, flag */
 
1560
uint32 dvdp, dvdd;                                      /* dvd ptr, dig */
 
1561
uint32 qd, cry;                                         /* quo dig, carry */
 
1562
uint32 cnt;
 
1563
 
 
1564
for (qd = 0; qd < max; qd++) {                          /* devel quo dig */
 
1565
        dvrp = dvr;                                     /* divisor ptr */
 
1566
        dvdp = dvd;                                     /* dividend ptr */
 
1567
        cnt = 0;
 
1568
        cry = 1;                                        /* carry in = 1 */
 
1569
        do {                                            /* sub dvr fm dvd */
 
1570
            dvdd = M[dvdp] & DIGIT;                     /* dividend digit */
 
1571
            if (BAD_DIGIT (dvdd)) return STOP_INVDIG;   /* bad? */
 
1572
            dvrd = M[dvrp] & DIGIT;                     /* divisor digit */
 
1573
            dvrf = M[dvrp] & FLAG;                      /* divisor flag */
 
1574
            if (BAD_DIGIT (dvrd)) return STOP_INVDIG;   /* bad? */
 
1575
            M[dvdp] = add_one_digit (dvdd, 9 - dvrd, &cry);     /* sub */
 
1576
            MM (dvdp); MM (dvrp);                       /* decr ptrs */
 
1577
            if (cnt++ > MEMSIZE) return STOP_FWRAP;  }  /* (stop runaway) */
 
1578
        while ((dvrf == 0) || (cnt <= 1));              /* until dvr flag */
 
1579
        if (!cry) {                                     /* !cry = borrow */
 
1580
            dvdd = M[dvdp] & DIGIT;                     /* borrow digit */
 
1581
            if (BAD_DIGIT (dvdd)) return STOP_INVDIG;   /* bad? */
 
1582
            M[dvdp] = add_one_digit (dvdd, 9, &cry);  } /* sub */
 
1583
        if (!cry) break;  }                             /* !cry = negative */
 
1584
 
 
1585
/* Add back the divisor to correct for the negative result */
 
1586
 
 
1587
dvrp = dvr;                                             /* divisor ptr */
 
1588
dvdp = dvd;                                             /* dividend ptr */
 
1589
cnt = 0;
 
1590
cry = 0;                                                /* carry in = 0 */
 
1591
do {    dvdd = M[dvdp] & DIGIT;                         /* dividend digit */
 
1592
        dvrd = M[dvrp] & DIGIT;                         /* divisor digit */
 
1593
        dvrf = M[dvrp] & FLAG;                          /* divisor flag */
 
1594
        M[dvdp] = add_one_digit (dvdd, dvrd, &cry);     /* add */
 
1595
        MM (dvdp); MM (dvrp); cnt++;  }                 /* decr ptrs */
 
1596
while ((dvrf == 0) || (cnt <= 1));                      /* until dvr flag */
 
1597
if (cry) {                                              /* carry out? */
 
1598
        dvdd = M[dvdp] & DIGIT;                         /* borrow digit */
 
1599
        M[dvdp] = add_one_digit (dvdd, 0, &cry);  }     /* add */
 
1600
if (quop != NULL) *quop = dvdp;                         /* set quo addr */
 
1601
*quod = qd;                                             /* set quo digit */
 
1602
return SCPE_OK;
 
1603
}
 
1604
 
 
1605
/* Logical operation routines (and, or, xor, complement)
 
1606
 
 
1607
   Inputs:
 
1608
        d       =       destination address
 
1609
        s       =       source address
 
1610
   Output:
 
1611
        return  =       status
 
1612
 
 
1613
   Destination flags are preserved; EZ reflects the result.
 
1614
   COM does not obey normal field length restrictions.
 
1615
*/
 
1616
 
 
1617
t_stat or_field (uint32 d, uint32 s)
 
1618
{
 
1619
uint32 cnt = 0;
 
1620
int32 t;
 
1621
 
 
1622
ind[IN_EZ] = 1;                                         /* assume result zero */
 
1623
do {    t = M[s];                                       /* get src */
 
1624
        M[d] = (M[d] & FLAG) | ((M[d] | t) & 07);       /* OR src to dst */
 
1625
        if (M[d] & DIGIT) ind[IN_EZ] = 0;               /* nz dig? clr ind */
 
1626
        MM (d); MM (s);                                 /* decr pointers */
 
1627
        if (cnt++ >= MEMSIZE) return STOP_FWRAP;  }     /* (stop runaway) */
 
1628
while (((t & FLAG) == 0) || (cnt <= 1));                /* until src flag */
 
1629
return SCPE_OK;
 
1630
}
 
1631
 
 
1632
t_stat and_field (uint32 d, uint32 s)
 
1633
{
 
1634
uint32 cnt = 0;
 
1635
int32 t;
 
1636
 
 
1637
ind[IN_EZ] = 1;                                         /* assume result zero */
 
1638
do {    t = M[s];                                       /* get src */
 
1639
        M[d] = (M[d] & FLAG) | ((M[d] & t) & 07);       /* AND src to dst */
 
1640
        if (M[d] & DIGIT) ind[IN_EZ] = 0;               /* nz dig? clr ind */
 
1641
        MM (d); MM (s);                                 /* decr pointers */
 
1642
        if (cnt++ >= MEMSIZE) return STOP_FWRAP;  }     /* (stop runaway) */
 
1643
while (((t & FLAG) == 0) || (cnt <= 1));                /* until src flag */
 
1644
return SCPE_OK;
 
1645
}
 
1646
 
 
1647
t_stat xor_field (uint32 d, uint32 s)
 
1648
{
 
1649
uint32 cnt = 0;
 
1650
int32 t;
 
1651
 
 
1652
ind[IN_EZ] = 1;                                         /* assume result zero */
 
1653
do {    t = M[s];                                       /* get src */
 
1654
        M[d] = (M[d] & FLAG) | ((M[d] ^ t) & 07);       /* XOR src to dst */
 
1655
        if (M[d] & DIGIT) ind[IN_EZ] = 0;               /* nz dig? clr ind */
 
1656
        MM (d); MM (s);                                 /* decr pointers */
 
1657
        if (cnt++ >= MEMSIZE) return STOP_FWRAP;  }     /* (stop runaway) */
 
1658
while (((t & FLAG) == 0) || (cnt <= 1));                /* until src flag */
 
1659
return SCPE_OK;
 
1660
}
 
1661
 
 
1662
t_stat com_field (uint32 d, uint32 s)
 
1663
{
 
1664
uint32 cnt = 0;
 
1665
int32 t;
 
1666
 
 
1667
ind[IN_EZ] = 1;                                         /* assume result zero */
 
1668
do {    t = M[s];                                       /* get src */
 
1669
        M[d] = (t & FLAG) | ((t ^ 07) & 07);            /* comp src to dst */
 
1670
        if (M[d] & DIGIT) ind[IN_EZ] = 0;               /* nz dig? clr ind */
 
1671
        MM (d); MM (s);                                 /* decr pointers */
 
1672
        if (cnt++ >= MEMSIZE) return STOP_FWRAP;  }     /* (stop runaway) */
 
1673
while ((t & FLAG) == 0);                                /* until src flag */
 
1674
return SCPE_OK;
 
1675
}
 
1676
 
 
1677
/* Octal to decimal
 
1678
 
 
1679
   Inputs:
 
1680
        tbl     =       conversion table address (low digit)
 
1681
        s       =       source address
 
1682
   Outputs:
 
1683
        product area =  converted source
 
1684
        result  =       status
 
1685
 
 
1686
   OTD is a cousin of multiply.  The octal digits in the source are
 
1687
   multiplied by successive values in the conversion table, and the
 
1688
   results are accumulated in the product area.  Although the manual
 
1689
   does not say, this code assumes that EZ and HP are affected.
 
1690
 */
 
1691
 
 
1692
t_stat oct_to_dec (uint32 tbl, uint32 s)
 
1693
{
 
1694
uint32 cnt = 0, tblc;
 
1695
uint32 i, sd, sf, tf, sign;
 
1696
t_stat r;
 
1697
 
 
1698
for (i = 0; i < PROD_AREA_LEN; i++)                     /* clr prod area */
 
1699
        M[PROD_AREA + i] = 0;
 
1700
sign = M[s] & FLAG;                                     /* save sign */
 
1701
ind[IN_EZ] = 1;                                         /* set indicators */
 
1702
ind[IN_HP] = (sign == 0);
 
1703
do {    sd = M[s] & DIGIT;                              /* src digit */
 
1704
        sf = M[s] & FLAG;                               /* src flag */
 
1705
        r = mul_one_digit (sd, tbl, PROD_AREA + PROD_AREA_LEN - 1, sf);
 
1706
        if (r != SCPE_OK) return r;                     /* err? */
 
1707
        MM (s);                                         /* decr src addr */
 
1708
        MM (tbl);                                       /* skip 1st tbl dig */
 
1709
        tblc = 0;                                       /* count */
 
1710
        do {
 
1711
            tf = M[tbl] & FLAG;                         /* get next */
 
1712
            MM (tbl);                                   /* decr ptr */
 
1713
            if (tblc++ > MEMSIZE) return STOP_FWRAP;  }
 
1714
        while (tf == 0);                                /* until flag */
 
1715
        if (cnt++ > MEMSIZE) return STOP_FWRAP;  }      /* (stop runaway) */
 
1716
while (sf == 0);
 
1717
if (ind[IN_EZ]) ind[IN_HP] = 0;                         /* res = 0? clr HP */
 
1718
M[PROD_AREA + PROD_AREA_LEN - 1] |= sign;               /* set sign */
 
1719
return SCPE_OK;
 
1720
}
 
1721
 
 
1722
/* Decimal to octal 
 
1723
 
 
1724
   Inputs:
 
1725
        d       =       destination address
 
1726
        tbl     =       conversion table address (low digit of highest power)
 
1727
        &ez     =       address of soft EZ indicator
 
1728
        product area =  field to convert
 
1729
   Outputs:
 
1730
        return  =       status
 
1731
 
 
1732
   DTO is a cousin to divide.  The number in the product area is repeatedly
 
1733
   divided by successive values in the conversion table, and the quotient
 
1734
   digits are stored in the destination.  Although the manual does not say,
 
1735
   this code assumes that EZ and HP are affected.
 
1736
 */
 
1737
 
 
1738
t_stat dec_to_oct (uint32 d, uint32 tbl, int32 *ez)
 
1739
{
 
1740
uint32 sign, octd, t;
 
1741
t_bool first = TRUE;
 
1742
uint32 ctr = 0;
 
1743
t_stat r;
 
1744
 
 
1745
sign = M[PROD_AREA + PROD_AREA_LEN - 1] & FLAG;         /* input sign */
 
1746
*ez = 1;                                                /* set indicators */
 
1747
ind[IN_HP] = (sign == 0);
 
1748
for ( ;; ) {
 
1749
        r = div_one_digit (PROD_AREA + PROD_AREA_LEN - 1, /* divide */
 
1750
            tbl, 8, &octd, NULL);
 
1751
        if (r != SCPE_OK) return r;                     /* error? */
 
1752
        if (first) {                                    /* first pass? */
 
1753
            if (octd >= 8) {                            /* overflow? */
 
1754
                ind[IN_OVF] = 1;                        /* set indicator */
 
1755
                return SCPE_OK;  }                      /* stop */
 
1756
            M[d] = FLAG | octd;                         /* set flag on quo */
 
1757
            first = FALSE;  }
 
1758
        else M[d] = octd;                               /* store quo digit */
 
1759
        if (octd) *ez = 0;                              /* if nz, clr ind */
 
1760
        PP (tbl);                                       /* incr tbl addr */
 
1761
        if ((M[tbl] & REC_MARK) == REC_MARK) break;     /* record mark? */
 
1762
        PP (tbl);                                       /* skip flag */
 
1763
        if ((M[tbl] & REC_MARK) == REC_MARK) break;     /* record mark? */
 
1764
        do {    PP (tbl);                               /* look for F, rec mk */
 
1765
                t = M[tbl];  }
 
1766
        while (((t & FLAG) == 0) && ((t & REC_MARK) != REC_MARK));
 
1767
        MM (tbl);                                       /* step back one */
 
1768
        PP (d);                                         /* incr quo addr */
 
1769
        if (ctr++ > MEMSIZE) return STOP_FWRAP;  }      /* (stop runaway) */
 
1770
if (*ez) ind[IN_HP] = 0;                                /* res = 0? clr HP */
 
1771
M[d] = M[d] | sign;                                     /* set result sign */   
 
1772
return SCPE_OK;
 
1773
}
 
1774
 
 
1775
/* Reset routine */
 
1776
 
 
1777
t_stat cpu_reset (DEVICE *dptr)
 
1778
{
 
1779
int32 i;
 
1780
static t_bool one_time = TRUE;
 
1781
 
 
1782
PR1 = IR2 = 1;                                          /* invalidate PR1,IR2 */
 
1783
ind[0] = 0;
 
1784
for (i = IN_SW4 + 1; i < NUM_IND; i++) ind[i] = 0;      /* init indicators */
 
1785
if (cpu_unit.flags & IF_IA) iae = 1;                    /* indirect enabled? */
 
1786
else iae = 0;
 
1787
idxe = idxb = 0;                                        /* indexing off */
 
1788
pcq_r = find_reg ("PCQ", NULL, dptr);                   /* init old PC queue */
 
1789
if (pcq_r) pcq_r->qptr = 0;
 
1790
else return SCPE_IERR;
 
1791
sim_brk_types = sim_brk_dflt = SWMASK ('E');            /* init breakpoints */
 
1792
upd_ind ();                                             /* update indicators */
 
1793
if (one_time) cpu_set_table (&cpu_unit, 1, NULL, NULL); /* set default tables */
 
1794
one_time = FALSE;
 
1795
return SCPE_OK;
 
1796
}
 
1797
 
 
1798
/* Memory examine */
 
1799
 
 
1800
t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
 
1801
{
 
1802
if (addr >= MEMSIZE) return SCPE_NXM;
 
1803
if (vptr != NULL) *vptr = M[addr] & (FLAG | DIGIT);
 
1804
return SCPE_OK;
 
1805
}
 
1806
 
 
1807
/* Memory deposit */
 
1808
 
 
1809
t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)
 
1810
{
 
1811
if (addr >= MEMSIZE) return SCPE_NXM;
 
1812
M[addr] = val & (FLAG | DIGIT);
 
1813
return SCPE_OK;
 
1814
}
 
1815
 
 
1816
/* Memory size change */
 
1817
 
 
1818
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
 
1819
{
 
1820
int32 mc = 0;
 
1821
uint32 i;
 
1822
 
 
1823
if ((val <= 0) || (val > MAXMEMSIZE) || ((val % 1000) != 0))
 
1824
        return SCPE_ARG;
 
1825
for (i = val; i < MEMSIZE; i++) mc = mc | M[i];
 
1826
if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE)))
 
1827
        return SCPE_OK;
 
1828
MEMSIZE = val;
 
1829
for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0;
 
1830
return SCPE_OK;
 
1831
}
 
1832
 
 
1833
/* Model change */
 
1834
 
 
1835
t_stat cpu_set_model (UNIT *uptr, int32 val, char *cptr, void *desc)
 
1836
{
 
1837
if (val) cpu_unit.flags = (cpu_unit.flags & (UNIT_SCP | UNIT_BCD | MII_OPT)) |
 
1838
        IF_DIV | IF_IA | IF_EDT;
 
1839
else cpu_unit.flags = cpu_unit.flags & (UNIT_SCP | UNIT_BCD | MI_OPT);
 
1840
return SCPE_OK;
 
1841
}
 
1842
 
 
1843
/* Set/clear Model 1 option */
 
1844
 
 
1845
t_stat cpu_set_opt1 (UNIT *uptr, int32 val, char *cptr, void *desc)
 
1846
{
 
1847
if (cpu_unit.flags & IF_MII) {
 
1848
        printf ("Feature is standard on 1620 Model 2\n");
 
1849
        if (sim_log) fprintf (sim_log, "Feature is standard on 1620 Model 2\n");
 
1850
        return SCPE_NOFNC;  }
 
1851
return SCPE_OK;
 
1852
}
 
1853
 
 
1854
/* Set/clear Model 2 option */
 
1855
 
 
1856
t_stat cpu_set_opt2 (UNIT *uptr, int32 val, char *cptr, void *desc)
 
1857
{
 
1858
if (!(cpu_unit.flags & IF_MII)) {
 
1859
        printf ("Feature is not available on 1620 Model 1\n");
 
1860
        if (sim_log) fprintf (sim_log, "Feature is not available on 1620 Model 1\n");
 
1861
        return SCPE_NOFNC;  }
 
1862
return SCPE_OK;
 
1863
}
 
1864
 
 
1865
/* Front panel save */
 
1866
 
 
1867
t_stat cpu_set_save (UNIT *uptr, int32 val, char *cptr, void *desc)
 
1868
{
 
1869
if (saved_PC & 1) return SCPE_NOFNC;
 
1870
PR1 = saved_PC;
 
1871
return SCPE_OK;
 
1872
}
 
1873
 
 
1874
/* Set standard add/multiply tables */
 
1875
 
 
1876
t_stat cpu_set_table (UNIT *uptr, int32 val, char *cptr, void *desc)
 
1877
{
 
1878
int32 i;
 
1879
 
 
1880
for (i = 0; i < MUL_TABLE_LEN; i++)                     /* set mul table */
 
1881
        M[MUL_TABLE + i] = std_mul_table[i];
 
1882
if (((cpu_unit.flags & IF_MII) == 0) || val) {          /* set add table */
 
1883
        for (i = 0; i < ADD_TABLE_LEN; i++)
 
1884
                M[ADD_TABLE + i] = std_add_table[i];  }
 
1885
return SCPE_OK;
 
1886
}