1 /*
2 * Copyright (c) 2007-2013 Michael Mondy
3 * Copyright (c) 2012-2016 Harry Reed
4 * Copyright (c) 2013-2016 Charles Anthony
5 * Copyright (c) 2021 The DPS8M Development Team
6 *
7 * All rights reserved.
8 *
9 * This software is made available under the terms of the ICU
10 * License, version 1.8.1 or later. For more details, see the
11 * LICENSE.md file at the top-level directory of this distribution.
12 */
13
14 #include <stdio.h>
15 #include <string.h>
16 #include <ctype.h>
17
18 #include "dps8.h"
19 #include "dps8_sys.h"
20 #include "dps8_faults.h"
21 #include "dps8_scu.h"
22 #include "dps8_iom.h"
23 #include "dps8_cable.h"
24 #include "dps8_cpu.h"
25 #include "dps8_ins.h"
26 #include "dps8_opcodetable.h"
27 #include "dps8_utils.h"
28
29 #define DBG_CTR 1
30
31 /*
32 * misc utility routines used by simulator
33 */
34
dump_flags(char * buffer,word18 flags)35 char * dump_flags(char * buffer, word18 flags)
36 {
37 sprintf(buffer, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
38 #ifdef DPS8M
39 flags & I_HEX ? "Hex " : "",
40 #endif
41 #ifdef L68
42 "",
43 #endif
44 flags & I_ABS ? "Abs " : "",
45 flags & I_MIF ? "MIF " : "",
46 flags & I_TRUNC ? "Trunc " : "",
47 flags & I_NBAR ? "~BAR " : "",
48 flags & I_PMASK ? "PMask " : "",
49 flags & I_PERR ? "PErr" : "",
50 flags & I_TALLY ? "Tally " : "",
51 flags & I_OMASK ? "OMASK " : "",
52 flags & I_EUFL ? "EUFL " : "",
53 flags & I_EOFL ? "EOFL " : "",
54 flags & I_OFLOW ? "Ovr " : "",
55 flags & I_CARRY ? "Carry " : "",
56 flags & I_NEG ? "Neg " : "",
57 flags & I_ZERO ? "Zero " : ""
58 );
59 return buffer;
60
61 }
62
dps8_strupr(char * str)63 static char * dps8_strupr(char *str)
64 {
65 char *s;
66
67 for(s = str; *s; s++)
68 *s = (char) toupper((unsigned char)*s);
69 return str;
70 }
71
72 //! get instruction info for IWB ...
73
74 static struct opcode_s unimplented = {"(unimplemented)", 0, 0, 0, 0};
75
get_iwb_info(DCDstruct * i)76 struct opcode_s * get_iwb_info (DCDstruct * i)
77 {
78 struct opcode_s * p = &opcodes10[i->opcode10];
79 return p->mne ? p : &unimplented;
80 }
81
disassemble(char * result,word36 instruction)82 char *disassemble(char * result, word36 instruction)
83 {
84 uint32 opcode = GET_OP(instruction); ///< get opcode
85 uint32 opcodeX = GET_OPX(instruction); ///< opcode extension
86 uint32 opcode10 = opcode | (opcodeX ? 01000 : 0);
87 word18 address = GET_ADDR(instruction);
88 word1 a = GET_A(instruction);
89 //int32 i = GET_I(instruction);
90 word6 tag = GET_TAG(instruction);
91
92 //static char result[132] = "???";
93 strcpy(result, "???");
94
95 // get mnemonic ...
96 if (opcodes10[opcode10].mne)
97 strcpy(result, opcodes10[opcode10].mne);
98
99 // XXX need to reconstruct multi-word EIS instruction.
100
101 char buff[64];
102
103 if (a)
104 {
105 int n = (address >> 15) & 07;
106 int offset = address & 077777;
107
108 sprintf(buff, " pr%d|%o", n, offset);
109 strcat (result, buff);
110 // return dps8_strupr(result);
111 } else {
112 sprintf(buff, " %06o", address);
113 strcat (result, buff);
114 }
115 // get mod
116 strcpy(buff, "");
117 for(uint n = 0 ; n < 0100 ; n++)
118 if (extMods[n].mod)
119 if(n == tag)
120 {
121 strcpy(buff, extMods[n].mod);
122 break;
123 }
124
125 if (strlen(buff))
126 {
127 strcat(result, ",");
128 strcat(result, buff);
129 }
130
131 return dps8_strupr(result);
132 }
133
134 /*
135 * get_mod__string ()
136 *
137 * Convert instruction address modifier tag to printable string
138 * WARNING: returns pointer to statically allocated string
139 *
140 */
141
get_mod_string(char * msg,word6 tag)142 char *get_mod_string(char * msg, word6 tag)
143 {
144 strcpy(msg, "none");
145
146 if (tag >= 0100)
147 {
148 sprintf(msg, "getModReg(tag out-of-range %o)", tag);
149 } else {
150 for(uint n = 0 ; n < 0100 ; n++)
151 if (extMods[n].mod)
152 if(n == tag)
153 {
154 strcpy(msg, extMods[n].mod);
155 break;
156 }
157
158 }
159 return msg;
160 }
161
162
163 /*
164 * 36-bit arithmetic stuff ...
165 */
166 /* Single word integer routines */
167
Add36b(word36 op1,word36 op2,word1 carryin,word18 flagsToSet,word18 * flags,bool * ovf)168 word36 Add36b (word36 op1, word36 op2, word1 carryin, word18 flagsToSet, word18 * flags, bool * ovf)
169 {
170 CPT (cpt2L, 17); // Add36b
171 sim_debug (DBG_TRACEEXT, & cpu_dev, "Add36b op1 %012"PRIo64" op2 %012"PRIo64" carryin %o flagsToSet %06o flags %06o\n", op1, op2, carryin, flagsToSet, * flags);
172 // https://en.wikipedia.org/wiki/Two%27s_complement#Addition
173 //
174 // In general, any two N-bit numbers may be added without overflow, by first
175 // sign-extending both of them to N + 1 bits, and then adding as above. The
176 // N + 1 bits result is large enough to represent any possible sum (N = 5 two's
177 // complement can represent values in the range −16 to 15) so overflow will
178 // never occur. It is then possible, if desired, to 'truncate' the result back
179 // to N bits while preserving the value if and only if the discarded bit is a
180 // proper sign extension of the retained result bits. This provides another
181 // method of detecting overflow—which is equivalent to the method of comparing
182 // the carry bits—but which may be easier to implement in some situations,
183 // because it does not require access to the internals of the addition.
184
185 // 37 bit arithmetic for the above N+1 algorithm
186 word38 op1e = op1 & MASK36;
187 word38 op2e = op2 & MASK36;
188 word38 ci = carryin ? 1 : 0;
189
190 // extend sign bits
191 if (op1e & SIGN36)
192 op1e |= BIT37;
193 if (op2e & SIGN36)
194 op2e |= BIT37;
195
196 // Do the math
197 word38 res = op1e + op2e + ci;
198
199 // Extract the overflow bits
200 bool r37 = res & BIT37 ? true : false;
201 bool r36 = res & SIGN36 ? true : false;
202
203 // Extract the carry bit
204 bool r38 = res & BIT38 ? true : false;
205
206 // Check for overflow
207 * ovf = r37 ^ r36;
208
209 // Check for carry
210 bool cry = r38;
211
212 // Truncate the result
213 res &= MASK36;
214
215 #ifdef PANEL
216 if (cry) CPT (cpt2L, 28); // carry
217 if (ovf) CPT (cpt2L, 29); // ovf
218 if (!res) CPT (cpt2L, 30); // zero
219 if (res & SIGN36) CPT (cpt2L, 31); // neg
220 #endif
221
222 if (flagsToSet & I_CARRY)
223 {
224 if (cry)
225 SETF (* flags, I_CARRY);
226 else
227 CLRF (* flags, I_CARRY);
228 }
229
230 if (chkOVF () && (flagsToSet & I_OFLOW))
231 {
232 if (* ovf)
233 SETF (* flags, I_OFLOW); // overflow
234 }
235
236 if (flagsToSet & I_ZERO)
237 {
238 if (res)
239 CLRF (* flags, I_ZERO);
240 else
241 SETF (* flags, I_ZERO); // zero result
242 }
243
244 if (flagsToSet & I_NEG)
245 {
246 if (res & SIGN36)
247 SETF (* flags, I_NEG);
248 else
249 CLRF (* flags, I_NEG);
250 }
251
252 sim_debug (DBG_TRACEEXT, & cpu_dev, "Add36b res %012"PRIo64" flags %06o ovf %o\n", res, * flags, * ovf);
253 return res;
254 }
255
Sub36b(word36 op1,word36 op2,word1 carryin,word18 flagsToSet,word18 * flags,bool * ovf)256 word36 Sub36b (word36 op1, word36 op2, word1 carryin, word18 flagsToSet, word18 * flags, bool * ovf)
257 {
258 CPT (cpt2L, 18); // Sub36b
259
260 // https://en.wikipedia.org/wiki/Two%27s_complement
261 //
262 // As for addition, overflow in subtraction may be avoided (or detected after
263 // the operation) by first sign-extending both inputs by an extra bit.
264 //
265 // AL39:
266 //
267 // If carry indicator ON, then C(A) - C(Y) -> C(A)
268 // If carry indicator OFF, then C(A) - C(Y) - 1 -> C(A)
269
270 // 38 bit arithmetic for the above N+1 algorithm
271 word38 op1e = op1 & MASK36;
272 word38 op2e = op2 & MASK36;
273 // Note that carryin has an inverted sense for borrow
274 word38 ci = carryin ? 0 : 1;
275
276 // extend sign bits
277 if (op1e & SIGN36)
278 op1e |= BIT37;
279 if (op2e & SIGN36)
280 op2e |= BIT37;
281
282 // Do the math
283 word38 res = op1e - op2e - ci;
284
285 // Extract the overflow bits
286 bool r37 = (res & BIT37) ? true : false;
287 bool r36 = (res & SIGN36) ? true : false;
288
289 // Extract the carry bit
290 bool r38 = res & BIT38 ? true : false;
291
292 // Truncate the result
293 res &= MASK36;
294
295 // Check for overflow
296 * ovf = r37 ^ r36;
297
298 // Check for carry
299 bool cry = r38;
300
301 #ifdef PANEL
302 if (cry) CPT (cpt2L, 28); // carry
303 if (ovf) CPT (cpt2L, 29); // ovf
304 if (!res) CPT (cpt2L, 30); // zero
305 if (res & SIGN36) CPT (cpt2L, 31); // neg
306 #endif
307
308 if (flagsToSet & I_CARRY)
309 {
310 if (cry) // Note inverted logic for subtraction
311 CLRF (* flags, I_CARRY);
312 else
313 SETF (* flags, I_CARRY);
314 }
315
316 if (chkOVF () && (flagsToSet & I_OFLOW))
317 {
318 if (* ovf)
319 SETF (* flags, I_OFLOW); // overflow
320 }
321
322 if (flagsToSet & I_ZERO)
323 {
324 if (res)
325 CLRF (* flags, I_ZERO);
326 else
327 SETF (* flags, I_ZERO); // zero result
328 }
329
330 if (flagsToSet & I_NEG)
331 {
332 if (res & SIGN36)
333 SETF (* flags, I_NEG);
334 else
335 CLRF (* flags, I_NEG);
336 }
337
338 return res;
339 }
340
Add18b(word18 op1,word18 op2,word1 carryin,word18 flagsToSet,word18 * flags,bool * ovf)341 word18 Add18b (word18 op1, word18 op2, word1 carryin, word18 flagsToSet, word18 * flags, bool * ovf)
342 {
343 CPT (cpt2L, 19); // Add18b
344
345 // https://en.wikipedia.org/wiki/Two%27s_complement#Addition
346 //
347 // In general, any two N-bit numbers may be added without overflow, by first
348 // sign-extending both of them to N + 1 bits, and then adding as above. The
349 // N + 1 bits result is large enough to represent any possible sum (N = 5 two's
350 // complement can represent values in the range −16 to 15) so overflow will
351 // never occur. It is then possible, if desired, to 'truncate' the result back
352 // to N bits while preserving the value if and only if the discarded bit is a
353 // proper sign extension of the retained result bits. This provides another
354 // method of detecting overflow—which is equivalent to the method of comparing
355 // the carry bits—but which may be easier to implement in some situations,
356 // because it does not require access to the internals of the addition.
357
358 // 19 bit arithmetic for the above N+1 algorithm
359 word20 op1e = op1 & MASK18;
360 word20 op2e = op2 & MASK18;
361 word20 ci = carryin ? 1 : 0;
362
363 // extend sign bits
364 if (op1e & SIGN18)
365 op1e |= BIT19;
366 if (op2e & SIGN18)
367 op2e |= BIT19;
368
369 // Do the math
370 word20 res = op1e + op2e + ci;
371
372 // Extract the overflow bits
373 bool r19 = (res & BIT19) ? true : false;
374 bool r18 = (res & SIGN18) ? true : false;
375
376 // Extract the carry bit
377 bool r20 = res & BIT20 ? true : false;
378
379 // Truncate the result
380 res &= MASK18;
381
382 // Check for overflow
383 * ovf = r19 ^ r18;
384
385 // Check for carry
386 bool cry = r20;
387
388 #ifdef PANEL
389 if (cry) CPT (cpt2L, 28); // carry
390 if (ovf) CPT (cpt2L, 29); // ovf
391 if (!res) CPT (cpt2L, 30); // zero
392 if (res & SIGN36) CPT (cpt2L, 31); // neg
393 #endif
394
395 if (flagsToSet & I_CARRY)
396 {
397 if (cry)
398 SETF (* flags, I_CARRY);
399 else
400 CLRF (* flags, I_CARRY);
401 }
402
403 if (chkOVF () && (flagsToSet & I_OFLOW))
404 {
405 if (* ovf)
406 SETF (* flags, I_OFLOW); // overflow
407 }
408
409 if (flagsToSet & I_ZERO)
410 {
411 if (res)
412 CLRF (* flags, I_ZERO);
413 else
414 SETF (* flags, I_ZERO); // zero result
415 }
416
417 if (flagsToSet & I_NEG)
418 {
419 if (res & SIGN18)
420 SETF (* flags, I_NEG);
421 else
422 CLRF (* flags, I_NEG);
423 }
424
425 return (word18) res;
426 }
427
Sub18b(word18 op1,word18 op2,word1 carryin,word18 flagsToSet,word18 * flags,bool * ovf)428 word18 Sub18b (word18 op1, word18 op2, word1 carryin, word18 flagsToSet, word18 * flags, bool * ovf)
429 {
430 CPT (cpt2L, 20); // Sub18b
431
432 // https://en.wikipedia.org/wiki/Two%27s_complement
433 //
434 // As for addition, overflow in subtraction may be avoided (or detected after
435 // the operation) by first sign-extending both inputs by an extra bit.
436 //
437 // AL39:
438 //
439 // If carry indicator ON, then C(A) - C(Y) -> C(A)
440 // If carry indicator OFF, then C(A) - C(Y) - 1 -> C(A)
441
442 // 19 bit arithmetic for the above N+1 algorithm
443 word20 op1e = op1 & MASK18;
444 word20 op2e = op2 & MASK18;
445 // Note that carryin has an inverted sense for borrow
446 word20 ci = carryin ? 0 : 1;
447
448 // extend sign bits
449 if (op1e & SIGN18)
450 op1e |= BIT19;
451 if (op2e & SIGN18)
452 op2e |= BIT19;
453
454 // Do the math
455 word20 res = op1e - op2e - ci;
456
457 // Extract the overflow bits
458 bool r19 = res & BIT19 ? true : false;
459 bool r18 = res & SIGN18 ? true : false;
460
461 // Extract the carry bit
462 bool r20 = res & BIT20 ? true : false;
463
464 // Truncate the result
465 res &= MASK18;
466
467 // Check for overflow
468 * ovf = r19 ^ r18;
469
470 // Check for carry
471 bool cry = r20;
472
473 #ifdef PANEL
474 if (cry) CPT (cpt2L, 28); // carry
475 if (ovf) CPT (cpt2L, 29); // ovf
476 if (!res) CPT (cpt2L, 30); // zero
477 if (res & SIGN36) CPT (cpt2L, 31); // neg
478 #endif
479
480 if (flagsToSet & I_CARRY)
481 {
482 if (cry) // Note inverted logic for subtraction
483 CLRF (* flags, I_CARRY);
484 else
485 SETF (* flags, I_CARRY);
486 }
487
488 if (chkOVF () && (flagsToSet & I_OFLOW))
489 {
490 if (* ovf)
491 SETF (* flags, I_OFLOW); // overflow
492 }
493
494 if (flagsToSet & I_ZERO)
495 {
496 if (res)
497 CLRF (* flags, I_ZERO);
498 else
499 SETF (* flags, I_ZERO); // zero result
500 }
501
502 if (flagsToSet & I_NEG)
503 {
504 if (res & SIGN18)
505 SETF (* flags, I_NEG);
506 else
507 CLRF (* flags, I_NEG);
508 }
509
510 return res;
511 }
512
Add72b(word72 op1,word72 op2,word1 carryin,word18 flagsToSet,word18 * flags,bool * ovf)513 word72 Add72b (word72 op1, word72 op2, word1 carryin, word18 flagsToSet, word18 * flags, bool * ovf)
514 {
515 CPT (cpt2L, 21); // Add72b
516
517 // https://en.wikipedia.org/wiki/Two%27s_complement#Addition
518 //
519 // In general, any two N-bit numbers may be added without overflow, by first
520 // sign-extending both of them to N + 1 bits, and then adding as above. The
521 // N + 1 bits result is large enough to represent any possible sum (N = 5 two's
522 // complement can represent values in the range −16 to 15) so overflow will
523 // never occur. It is then possible, if desired, to 'truncate' the result back
524 // to N bits while preserving the value if and only if the discarded bit is a
525 // proper sign extension of the retained result bits. This provides another
526 // method of detecting overflow—which is equivalent to the method of comparing
527 // the carry bits—but which may be easier to implement in some situations,
528 // because it does not require access to the internals of the addition.
529
530 // 73 bit arithmetic for the above N+1 algorithm
531 #ifdef NEED_128
532 word74 op1e = and_128 (op1, MASK72);
533 word74 op2e = and_128 (op2, MASK72);
534 word74 ci = construct_128 (0, carryin ? 1 : 0);
535 #else
536 word74 op1e = op1 & MASK72;
537 word74 op2e = op2 & MASK72;
538 word74 ci = carryin ? 1 : 0;
539 #endif
540
541 // extend sign bits
542 #ifdef NEED_128
543 if (isnonzero_128 (and_128 (op1e, SIGN72)))
544 op1e = or_128 (op1e, BIT73);
545 if (isnonzero_128 (and_128 (op2e, SIGN72)))
546 op2e = or_128 (op2e, BIT73);
547 #else
548 if (op1e & SIGN72)
549 op1e |= BIT73;
550 if (op2e & SIGN72)
551 op2e |= BIT73;
552 #endif
553
554 // Do the math
555 #ifdef NEED_128
556 word74 res = add_128 (op1e, add_128 (op2e, ci));
557 #else
558 word74 res = op1e + op2e + ci;
559 #endif
560
561 // Extract the overflow bits
562 #ifdef NEED_128
563 bool r73 = isnonzero_128 (and_128 (res, BIT73));
564 bool r72 = isnonzero_128 (and_128 (res, SIGN72));
565 #else
566 bool r73 = res & BIT73 ? true : false;
567 bool r72 = res & SIGN72 ? true : false;
568 #endif
569
570 // Extract the carry bit
571 #ifdef NEED_128
572 bool r74 = isnonzero_128 (and_128 (res, BIT74));
573 #else
574 bool r74 = res & BIT74 ? true : false;
575 #endif
576
577 // Truncate the result
578 #ifdef NEED_128
579 res = and_128 (res, MASK72);
580 #else
581 res &= MASK72;
582 #endif
583
584 // Check for overflow
585 * ovf = r73 ^ r72;
586
587 // Check for carry
588 bool cry = r74;
589
590 #ifdef PANEL
591 if (cry) CPT (cpt2L, 28); // carry
592 if (ovf) CPT (cpt2L, 29); // ovf
593 if (!res) CPT (cpt2L, 30); // zero
594 if (res & SIGN36) CPT (cpt2L, 31); // neg
595 #endif
596
597 if (flagsToSet & I_CARRY)
598 {
599 if (cry)
600 SETF (* flags, I_CARRY);
601 else
602 CLRF (* flags, I_CARRY);
603 }
604
605 if (chkOVF () && (flagsToSet & I_OFLOW))
606 {
607 if (* ovf)
608 SETF (* flags, I_OFLOW); // overflow
609 }
610
611 if (flagsToSet & I_ZERO)
612 {
613 #ifdef NEED_128
614 if (isnonzero_128 (res))
615 #else
616 if (res)
617 #endif
618 CLRF (* flags, I_ZERO);
619 else
620 SETF (* flags, I_ZERO); // zero result
621 }
622
623 if (flagsToSet & I_NEG)
624 {
625 #ifdef NEED_128
626 if (isnonzero_128 (and_128 (res, SIGN72)))
627 #else
628 if (res & SIGN72)
629 #endif
630 SETF (* flags, I_NEG);
631 else
632 CLRF (* flags, I_NEG);
633 }
634
635 return res;
636 }
637
638
Sub72b(word72 op1,word72 op2,word1 carryin,word18 flagsToSet,word18 * flags,bool * ovf)639 word72 Sub72b (word72 op1, word72 op2, word1 carryin, word18 flagsToSet, word18 * flags, bool * ovf)
640 {
641 CPT (cpt2L, 22); // Sub72b
642 #ifdef NEED_128
643 sim_debug (DBG_TRACEEXT, & cpu_dev, "Sub72b op1 %012"PRIo64"%012"PRIo64" op2 %012"PRIo64"%012"PRIo64" carryin %o flagsToSet %06o flags %06o\n",
644 (word36) ((rshift_128 (op1, 36).l) & MASK36), (word36) (op1.l & MASK36), (word36) (rshift_128 (op2, 36).l & MASK36), (word36) (op2.l & MASK36), carryin, flagsToSet, * flags);
645 #else
646 sim_debug (DBG_TRACEEXT, & cpu_dev, "Sub72b op1 %012"PRIo64"%012"PRIo64" op2 %012"PRIo64"%012"PRIo64" carryin %o flagsToSet %06o flags %06o\n",
647 (word36) ((op1 >> 36) & MASK36), (word36) (op1 & MASK36), (word36) ((op2 >> 36) & MASK36), (word36) (op2 & MASK36), carryin, flagsToSet, * flags);
648 #endif
649
650 // https://en.wikipedia.org/wiki/Two%27s_complement
651 //
652 // As for addition, overflow in subtraction may be avoided (or detected after
653 // the operation) by first sign-extending both inputs by an extra bit.
654 //
655 // AL39:
656 //
657 // If carry indicator ON, then C(A) - C(Y) -> C(A)
658 // If carry indicator OFF, then C(A) - C(Y) - 1 -> C(A)
659
660 // 73 bit arithmetic for the above N+1 algorithm
661 #ifdef NEED_128
662 word74 op1e = and_128 (op1, MASK72);
663 word74 op2e = and_128 (op2, MASK72);
664 #else
665 word74 op1e = op1 & MASK72;
666 word74 op2e = op2 & MASK72;
667 #endif
668 // Note that carryin has an inverted sense for borrow
669 #ifdef NEED_128
670 word74 ci = construct_128 (0, carryin ? 0 : 1);
671 #else
672 word74 ci = carryin ? 0 : 1;
673 #endif
674
675 // extend sign bits
676 #ifdef NEED_128
677 if (isnonzero_128 (and_128 (op1e, SIGN72)))
678 op1e = or_128 (op1e, BIT73);
679 if (isnonzero_128 (and_128 (op2e, SIGN72)))
680 op2e = or_128 (op2e, BIT73);
681 #else
682 if (op1e & SIGN72)
683 op1e |= BIT73;
684 if (op2e & SIGN72)
685 op2e |= BIT73;
686 #endif
687
688 // Do the math
689 #ifdef NEED_128
690 sim_debug (DBG_TRACEEXT, & cpu_dev, "Sub72b op1e %012"PRIo64"%012"PRIo64" op2e %012"PRIo64"%012"PRIo64" carryin %o flagsToSet %06o flags %06o\n",
691 (word36) ((rshift_128 (op1e, 36).l) & MASK36), (word36) (op1e.l & MASK36), (word36) (rshift_128 (op2e, 36).l & MASK36), (word36) (op2e.l & MASK36), carryin, flagsToSet, * flags);
692 #else
693 sim_debug (DBG_TRACEEXT, & cpu_dev, "Sub72b op1e %012"PRIo64"%012"PRIo64" op2e %012"PRIo64"%012"PRIo64" carryin %o flagsToSet %06o flags %06o\n",
694 (word36) ((op1e >> 36) & MASK36), (word36) (op1e & MASK36), (word36) ((op2e >> 36) & MASK36), (word36) (op2e & MASK36), carryin, flagsToSet, * flags);
695 #endif
696 #ifdef NEED_128
697 word74 res = subtract_128 (subtract_128 (op1e, op2e), ci);
698 #else
699 word74 res = op1e - op2e - ci;
700 #endif
701 #ifdef NEED_128
702 sim_debug (DBG_TRACEEXT, & cpu_dev, "Sub72b res %012"PRIo64"%012"PRIo64" flags %06o ovf %o\n", (word36) (rshift_128 (res, 36).l & MASK36), (word36) (res.l & MASK36), * flags, * ovf);
703 #else
704 sim_debug (DBG_TRACEEXT, & cpu_dev, "Sub72b res %012"PRIo64"%012"PRIo64" flags %06o ovf %o\n", (word36) ((res >> 36) & MASK36), (word36) (res & MASK36), * flags, * ovf);
705 #endif
706
707 // Extract the overflow bits
708 #ifdef NEED_128
709 bool r73 = isnonzero_128 (and_128 (res, BIT73));
710 bool r72 = isnonzero_128 (and_128 (res, SIGN72));
711 #else
712 bool r73 = res & BIT73 ? true : false;
713 bool r72 = res & SIGN72 ? true : false;
714 #endif
715
716 // Extract the carry bit
717 #ifdef NEED_128
718 bool r74 = isnonzero_128 (and_128 (res, BIT74));
719 #else
720 bool r74 = res & BIT74 ? true : false;
721 #endif
722
723 // Truncate the result
724 #ifdef NEED_128
725 res = and_128 (res, MASK72);
726 #else
727 res &= MASK72;
728 #endif
729
730 // Check for overflow
731 * ovf = r73 ^ r72;
732
733 // Check for carry
734 bool cry = r74;
735
736 #ifdef PANEL
737 if (cry) CPT (cpt2L, 28); // carry
738 if (ovf) CPT (cpt2L, 29); // ovf
739 if (!res) CPT (cpt2L, 30); // zero
740 if (res & SIGN36) CPT (cpt2L, 31); // neg
741 #endif
742
743 if (flagsToSet & I_CARRY)
744 {
745 if (cry) // Note inverted logic for subtraction
746 CLRF (* flags, I_CARRY);
747 else
748 SETF (* flags, I_CARRY);
749 }
750
751 if (chkOVF () && (flagsToSet & I_OFLOW))
752 {
753 if (* ovf)
754 SETF (* flags, I_OFLOW); // overflow
755 }
756
757 if (flagsToSet & I_ZERO)
758 {
759 #ifdef NEED_128
760 if (isnonzero_128 (res))
761 #else
762 if (res)
763 #endif
764 CLRF (* flags, I_ZERO);
765 else
766 SETF (* flags, I_ZERO); // zero result
767 }
768
769 if (flagsToSet & I_NEG)
770 {
771 #ifdef NEED_128
772 if (isnonzero_128 (and_128 (res, SIGN72)))
773 #else
774 if (res & SIGN72)
775 #endif
776 SETF (* flags, I_NEG);
777 else
778 CLRF (* flags, I_NEG);
779 }
780
781 #ifdef NEED_128
782 sim_debug (DBG_TRACEEXT, & cpu_dev, "Sub72b res %012"PRIo64"%012"PRIo64" flags %06o ovf %o\n", (word36) (rshift_128 (res, 36).l & MASK36), (word36) (res.l & MASK36), * flags, * ovf);
783 #else
784 sim_debug (DBG_TRACEEXT, & cpu_dev, "Sub72b res %012"PRIo64"%012"PRIo64" flags %06o ovf %o\n", (word36) ((res >> 36) & MASK36), (word36) (res & MASK36), * flags, * ovf);
785 #endif
786 return res;
787 }
788
789 // CANFAULT
compl36(word36 op1,word18 * flags,bool * ovf)790 word36 compl36(word36 op1, word18 *flags, bool * ovf)
791 {
792 CPT (cpt2L, 23); // compl36
793 //printf("op1 = %"PRIo64" %"PRIo64"\n", op1, (-op1) & DMASK);
794
795 op1 &= DMASK;
796
797 word36 res = -op1 & DMASK;
798
799 * ovf = op1 == MAXNEG;
800
801 #ifdef PANEL
802 if (* ovf) CPT (cpt2L, 29); // ovf
803 if (!res) CPT (cpt2L, 30); // zero
804 if (res & SIGN36) CPT (cpt2L, 31); // neg
805 #endif
806
807 if (chkOVF () && * ovf)
808 SETF(*flags, I_OFLOW);
809
810 if (res & SIGN36)
811 SETF(*flags, I_NEG);
812 else
813 CLRF(*flags, I_NEG);
814
815 if (res == 0)
816 SETF(*flags, I_ZERO);
817 else
818 CLRF(*flags, I_ZERO);
819
820 return res;
821 }
822
823 // CANFAULT
compl18(word18 op1,word18 * flags,bool * ovf)824 word18 compl18(word18 op1, word18 *flags, bool * ovf)
825 {
826 CPT (cpt2L, 24); // compl18
827 //printf("op1 = %"PRIo64" %"PRIo64"\n", op1, (-op1) & DMASK);
828
829 op1 &= MASK18;
830
831 word18 res = -op1 & MASK18;
832
833 * ovf = op1 == MAX18NEG;
834 #ifdef PANEL
835 if (* ovf) CPT (cpt2L, 29); // ovf
836 if (!res) CPT (cpt2L, 30); // zero
837 if (res & SIGN18) CPT (cpt2L, 31); // neg
838 #endif
839
840 if (chkOVF () && * ovf)
841 SETF(*flags, I_OFLOW);
842 if (res & SIGN18)
843 SETF(*flags, I_NEG);
844 else
845 CLRF(*flags, I_NEG);
846
847 if (res == 0)
848 SETF(*flags, I_ZERO);
849 else
850 CLRF(*flags, I_ZERO);
851
852 return res;
853 }
854
copyBytes(int posn,word36 src,word36 * dst)855 void copyBytes(int posn, word36 src, word36 *dst)
856 {
857 word36 mask = 0;
858
859 if (posn & 8) // bit 30 - byte 0 - (bits 0-8)
860 mask |= 0777000000000LL;
861
862 if (posn & 4) // bit 31 - byte 1 - (bits 9-17)
863 mask |= 0000777000000LL;
864
865 if (posn & 2) // bit 32 - byte 2 - (bits 18-26)
866 mask |= 0000000777000LL;
867
868 if (posn & 1) // bit 33 - byte 3 - (bits 27-35)
869 mask |= 0000000000777LL;
870
871 word36 byteVals = src & mask; // get byte bits
872
873 // clear the bits in dst
874 *dst &= ~mask;
875
876 // and set the bits in dst
877 *dst |= byteVals;
878 }
879
copyChars(int posn,word36 src,word36 * dst)880 void copyChars(int posn, word36 src, word36 *dst)
881 {
882 word36 mask = 0;
883
884 if (posn & 32) // bit 30 - char 0 - (bits 0-5)
885 mask |= 0770000000000LL;
886
887 if (posn & 16) // bit 31 - char 1 - (bits 6-11)
888 mask |= 0007700000000LL;
889
890 if (posn & 8) // bit 32 - char 2 - (bits 12-17)
891 mask |= 0000077000000LL;
892
893 if (posn & 4) // bit 33 - char 3 - (bits 18-23)
894 mask |= 0000000770000LL;
895
896 if (posn & 2) // bit 34 - char 4 - (bits 24-29)
897 mask |= 0000000007700LL;
898
899 if (posn & 1) // bit 35 - char 5 - (bits 30-35)
900 mask |= 0000000000077LL;
901
902 word36 byteVals = src & mask; // get byte bits
903
904 // clear the bits in dst
905 *dst &= ~mask;
906
907 // and set the bits in dst
908 *dst |= byteVals;
909 }
910
911 /*!
912 * write 9-bit byte into 36-bit word....
913 */
putByte(word36 * dst,word9 data,int posn)914 void putByte(word36 *dst, word9 data, int posn)
915 {
916 // XXX which is faster switch() or calculation?
917
918 // int offset = 27 - (9 * posn);// 0;
919 // switch (posn)
920 // {
921 // case 0:
922 // offset = 27;
923 // break;
924 // case 1:
925 // offset = 18;
926 // break;
927 // case 2:
928 // offset = 9;
929 // break;
930 // case 3:
931 // offset = 0;
932 // break;
933 // }
934 putbits36_9 (dst, (uint) posn * 9, data);
935 }
936
putChar(word36 * dst,word6 data,int posn)937 void putChar(word36 *dst, word6 data, int posn)
938 {
939 // XXX which is faster switch() or calculation?
940
941 // int offset = 30 - (6 * posn); //0;
942 // switch (posn)
943 // {
944 // case 0:
945 // offset = 30;
946 // break;
947 // case 1:
948 // offset = 24;
949 // break;
950 // case 2:
951 // offset = 18;
952 // break;
953 // case 3:
954 // offset = 12;
955 // break;
956 // case 4:
957 // offset = 6;
958 // break;
959 // case 5:
960 // offset = 0;
961 // break;
962 // }
963 putbits36_6 (dst, (uint) posn * 6, data);
964 }
965
convert_to_word72(word36 even,word36 odd)966 word72 convert_to_word72(word36 even, word36 odd)
967 {
968 #ifdef NEED_128
969 return or_128 (lshift_128 (construct_128 (0, even), 36), construct_128 (0, odd));
970 #else
971 return ((word72)even << 36) | (word72)odd;
972 #endif
973 }
974
convert_to_word36(word72 src,word36 * even,word36 * odd)975 void convert_to_word36 (word72 src, word36 *even, word36 *odd)
976 {
977 #ifdef NEED_128
978 *even = rshift_128 (src, 36).l & DMASK;
979 *odd = src.l & DMASK;
980 #else
981 *even = (word36)(src >> 36) & DMASK;
982 *odd = (word36)src & DMASK;
983 #endif
984 }
985
cmp36(word36 oP1,word36 oP2,word18 * flags)986 void cmp36(word36 oP1, word36 oP2, word18 *flags)
987 {
988 CPT (cpt2L, 25); // cmp36
989 #ifdef L68
990 cpu.ou.cycle |= ou_GOS;
991 #endif
992 t_int64 op1 = SIGNEXT36_64(oP1 & DMASK);
993 t_int64 op2 = SIGNEXT36_64(oP2 & DMASK);
994
995 word36 sign1 = (word36) op1 & SIGN36;
996 word36 sign2 = (word36) op2 & SIGN36;
997
998
999 if ((! sign1) && sign2) // op1 > 0, op2 < 0 :: op1 > op2
1000 CLRF (* flags, I_ZERO | I_NEG | I_CARRY);
1001
1002 else if (sign1 == sign2) // both operands have the same sogn
1003 {
1004 if (op1 > op2)
1005 {
1006 CPT (cpt2L, 28); // carry
1007 SETF (* flags, I_CARRY);
1008 CLRF (* flags, I_ZERO | I_NEG);
1009 }
1010 else if (op1 == op2)
1011 {
1012 CPT (cpt2L, 28); // carry
1013 CPT (cpt2L, 30); // zero
1014 SETF (* flags, I_ZERO | I_CARRY);
1015 CLRF (* flags, I_NEG);
1016 }
1017 else // op1 < op2
1018 {
1019 CPT (cpt2L, 31); // neg
1020 SETF (* flags, I_NEG);
1021 CLRF (* flags, I_ZERO | I_CARRY);
1022 }
1023 }
1024 else // op1 < 0, op2 > 0 :: op1 < op2
1025 {
1026 CPT (cpt2L, 28); // carry
1027 CPT (cpt2L, 31); // neg
1028 SETF (* flags, I_CARRY | I_NEG);
1029 CLRF (* flags, I_ZERO);
1030 }
1031 }
1032
cmp18(word18 oP1,word18 oP2,word18 * flags)1033 void cmp18(word18 oP1, word18 oP2, word18 *flags)
1034 {
1035 CPT (cpt2L, 26); // cmp18
1036 #ifdef L68
1037 cpu.ou.cycle |= ou_GOS;
1038 #endif
1039 int32 op1 = SIGNEXT18_32 (oP1 & MASK18);
1040 int32 op2 = SIGNEXT18_32 (oP2 & MASK18);
1041
1042 word18 sign1 = (word18) op1 & SIGN18;
1043 word18 sign2 = (word18) op2 & SIGN18;
1044
1045
1046 if ((! sign1) && sign2) // op1 > 0, op2 < 0 :: op1 > op2
1047 CLRF (* flags, I_ZERO | I_NEG | I_CARRY);
1048
1049 else if (sign1 == sign2) // both operands have the same sogn
1050 {
1051 if (op1 > op2)
1052 {
1053 CPT (cpt2L, 28); // carry
1054 SETF (* flags, I_CARRY);
1055 CLRF (* flags, I_ZERO | I_NEG);
1056 }
1057 else if (op1 == op2)
1058 {
1059 CPT (cpt2L, 28); // carry
1060 CPT (cpt2L, 30); // zero
1061 SETF (* flags, I_ZERO | I_CARRY);
1062 CLRF (* flags, I_NEG);
1063 }
1064 else // op1 < op2
1065 {
1066 CPT (cpt2L, 31); // neg
1067 SETF (* flags, I_NEG);
1068 CLRF (* flags, I_ZERO | I_CARRY);
1069 }
1070 }
1071 else // op1 < 0, op2 > 0 :: op1 < op2
1072 {
1073 CPT (cpt2L, 28); // carry
1074 CPT (cpt2L, 31); // neg
1075 SETF (* flags, I_CARRY | I_NEG);
1076 CLRF (* flags, I_ZERO);
1077 }
1078 }
1079
cmp36wl(word36 A,word36 Y,word36 Q,word18 * flags)1080 void cmp36wl(word36 A, word36 Y, word36 Q, word18 *flags)
1081 {
1082 CPT (cpt2L, 26); // cmp36wl
1083 // This is wrong; signed math is needed.
1084
1085 //bool Z = (A <= Y && Y <= Q) || (A >= Y && Y >= Q);
1086
1087 #ifdef L68
1088 cpu.ou.cycle |= ou_GOS;
1089 #endif
1090 t_int64 As = (word36s) SIGNEXT36_64(A & DMASK);
1091 t_int64 Ys = (word36s) SIGNEXT36_64(Y & DMASK);
1092 t_int64 Qs = (word36s) SIGNEXT36_64(Q & DMASK);
1093 bool Z = (As <= Ys && Ys <= Qs) || (As >= Ys && Ys >= Qs);
1094
1095 SCF(Z, *flags, I_ZERO);
1096
1097 if (!(Q & SIGN36) && (Y & SIGN36) && (Qs > Ys))
1098 CLRF(*flags, I_NEG | I_CARRY);
1099 else if (((Q & SIGN36) == (Y & SIGN36)) && (Qs >= Ys))
1100 {
1101 CPT (cpt2L, 28); // carry
1102 SETF(*flags, I_CARRY);
1103 CLRF(*flags, I_NEG);
1104 } else if (((Q & SIGN36) == (Y & SIGN36)) && (Qs < Ys))
1105 {
1106 CPT (cpt2L, 31); // neg
1107 CLRF(*flags, I_CARRY);
1108 SETF(*flags, I_NEG);
1109 } else if ((Q & SIGN36) && !(Y & SIGN36) && (Qs < Ys))
1110 {
1111 CPT (cpt2L, 28); // carry
1112 CPT (cpt2L, 31); // neg
1113 SETF(*flags, I_NEG | I_CARRY);
1114 }
1115 }
1116
cmp72(word72 op1,word72 op2,word18 * flags)1117 void cmp72(word72 op1, word72 op2, word18 *flags)
1118 {
1119 CPT (cpt2L, 27); // cmp72
1120 // The case of op1 == 400000000000000000000000 and op2 == 0 falls through
1121 // this code.
1122 #ifdef L68
1123 cpu.ou.cycle |= ou_GOS;
1124 #endif
1125 #ifdef NEED_128
1126 sim_debug (DBG_TRACEEXT, & cpu_dev, "op1 %016"PRIx64"%016"PRIx64"\n", op1.h, op1.l);
1127 sim_debug (DBG_TRACEEXT, & cpu_dev, "op2 %016"PRIx64"%016"PRIx64"\n", op2.h, op2.l);
1128 int128 op1s = SIGNEXT72_128 (and_128 (op1, MASK72));
1129 int128 op2s = SIGNEXT72_128 (and_128 (op2, MASK72));
1130 sim_debug (DBG_TRACEEXT, & cpu_dev, "op1s %016"PRIx64"%016"PRIx64"\n", op1s.h, op1s.l);
1131 sim_debug (DBG_TRACEEXT, & cpu_dev, "op2s %016"PRIx64"%016"PRIx64"\n", op2s.h, op2s.l);
1132 #else
1133 sim_debug (DBG_TRACEEXT, & cpu_dev, "op1 %016"PRIx64"%016"PRIx64"\n", (uint64_t) (op1>>64), (uint64_t) op1);
1134 sim_debug (DBG_TRACEEXT, & cpu_dev, "op2 %016"PRIx64"%016"PRIx64"\n", (uint64_t) (op2>>64), (uint64_t) op2);
1135 int128 op1s = SIGNEXT72_128 (op1 & MASK72);
1136 int128 op2s = SIGNEXT72_128 (op2 & MASK72);
1137 sim_debug (DBG_TRACEEXT, & cpu_dev, "op1s %016"PRIx64"%016"PRIx64"\n", (uint64_t) (op1s>>64), (uint64_t) op1s);
1138 sim_debug (DBG_TRACEEXT, & cpu_dev, "op2s %016"PRIx64"%016"PRIx64"\n", (uint64_t) (op2s>>64), (uint64_t) op2s);
1139 #endif
1140 #ifdef NEED_128
1141 if (isgt_s128 (op1s, op2s))
1142 #else
1143 if (op1s > op2s)
1144 #endif
1145 {
1146 #ifdef NEED_128
1147 if (isnonzero_128 (and_128 (op2, SIGN72)))
1148 #else
1149 if (op2 & SIGN72)
1150 #endif
1151 CLRF (* flags, I_CARRY);
1152 else
1153 {
1154 CPT (cpt2L, 28); // carry
1155 SETF (* flags, I_CARRY);
1156 }
1157 CLRF (* flags, I_ZERO | I_NEG);
1158 }
1159 #ifdef NEED_128
1160 else if (iseq_128 (cast_128 (op1s), cast_128 (op2s)))
1161 #else
1162 else if (op1s == op2s)
1163 #endif
1164 {
1165 CPT (cpt2L, 28); // carry
1166 CPT (cpt2L, 30); // zero
1167 SETF (* flags, I_CARRY | I_ZERO);
1168 CLRF (* flags, I_NEG);
1169 }
1170 else /* op1s < op2s */
1171 {
1172 CPT (cpt2L, 31); // neg
1173 #ifdef NEED_128
1174 if (isnonzero_128 (and_128 (op1, SIGN72)))
1175 #else
1176 if (op1 & SIGN72)
1177 #endif
1178 {
1179 CPT (cpt2L, 28); // carry
1180 SETF (* flags, I_CARRY);
1181 }
1182 else
1183 CLRF (* flags, I_CARRY);
1184 CLRF (* flags, I_ZERO);
1185 SETF (* flags, I_NEG);
1186 }
1187 }
1188
1189 /*
1190 * String utilities ...
1191 */
1192
strlower(char * q)1193 char * strlower(char *q)
1194 {
1195 char *s = q;
1196
1197 while (*s) {
1198 if (isupper(*s))
1199 *s = (char) tolower(*s);
1200 s++;
1201 }
1202 return q;
1203 }
1204
1205 /* state definitions */
1206 #define STAR 0
1207 #define NOTSTAR 1
1208 #define RESET 2
1209
strmask(char * str,char * mask)1210 int strmask (char * str, char * mask)
1211 /*!
1212 Tests string 'str' against mask string 'mask'
1213 Returns TRUE if the string matches the mask.
1214
1215 The mask can contain '?' and '*' wild card characters.
1216 '?' matches any single character.
1217 '*' matches any number of any characters.
1218
1219 For example:
1220 strmask("Hello", "Hello"); ---> TRUE
1221 strmask("Hello", "Jello"); ---> FALSE
1222 strmask("Hello", "H*o"); ---> TRUE
1223 strmask("Hello", "H*g"); ---> FALSE
1224 strmask("Hello", "?ello"); ---> TRUE
1225 strmask("Hello", "H????"); ---> TRUE
1226 strmask("H", "H????"); ---> FALSE
1227 */
1228 {
1229 char * sp, * mp, * reset_string, * reset_mask, * sn;
1230 int state;
1231
1232 sp = str;
1233 mp = mask;
1234
1235 while (1)
1236 {
1237 switch (* mp)
1238 {
1239 case '\0':
1240 return * sp ? false : true;
1241
1242 case '?':
1243 sp ++;
1244 mp ++;
1245 break;
1246
1247 default:
1248 if (* mp == * sp)
1249 {
1250 sp ++;
1251 mp ++;
1252 break;
1253 }
1254 else
1255 {
1256 return false;
1257 }
1258
1259 case '*':
1260 if (* (mp + 1) == '\0')
1261 {
1262 return true;
1263 }
1264 if ((sn = strchr (sp, * (mp + 1))) == NULL)
1265 {
1266 return false;
1267 }
1268
1269 /* save place -- match rest of string */
1270 /* if fail, reset to here */
1271 reset_mask = mp;
1272 reset_string = sn + 1;
1273
1274 mp = mp + 2;
1275 sp = sn + 1;
1276 state = NOTSTAR;
1277 while (state == NOTSTAR)
1278 {
1279 switch (* mp)
1280 {
1281 case '\0':
1282 if (* sp == '\0')
1283 return false;
1284 else
1285 state = RESET;
1286 break;
1287 case '?':
1288 sp ++;
1289 mp ++;
1290 break;
1291 default:
1292 if (* mp == * sp)
1293 {
1294 sp ++;
1295 mp ++;
1296 }
1297 else
1298 state = RESET;
1299 break;
1300 case '*':
1301 state = STAR;
1302 break;
1303 }
1304 } // while STATE == NOTSTAR
1305 /* we've reach a new star or should reset to last star */
1306 if (state == RESET)
1307 {
1308 sp = reset_string;
1309 mp = reset_mask;
1310 }
1311 break;
1312 } // switch (* mp)
1313 } // while (1)
1314 }
1315
1316 /*
1317 * strtok() with string quoting...
1318 * (implemented as a small fsm, kinda...
1319 * (add support for embedded " later, much later...)
1320 */
1321 #define NORMAL 1
1322 #define IN_STRING 2
1323 #define EOB 3
1324
1325 char *
Strtok(char * line,char * sep)1326 Strtok(char *line, char *sep)
1327 {
1328
1329 static char *p; /*!< current pointer position in input line*/
1330 static int state = NORMAL;
1331
1332 char *q; /*!< beginning of current field*/
1333
1334 if (line) { /* 1st invocation */
1335 p = line;
1336 state = NORMAL;
1337 }
1338
1339 q = p;
1340 while (state != EOB) {
1341 switch (state) {
1342 case NORMAL:
1343 switch (*p) {
1344 case 0: // at end of buffer
1345 state = EOB; // set state to "end Of Buffer
1346 return q;
1347
1348 case '"': // beginning of a quoted string
1349 state = IN_STRING; // we're in a string
1350 p++;
1351 continue;
1352
1353 default: // only a few special characters
1354 if (strchr(sep, *p) == NULL) { // not a sep
1355 p++; // goto next char
1356 continue;
1357 } else {
1358 *p++ = (char)0; /* ... iff >0 */
1359 while (*p && strchr(sep, *p)) /* skip over seperator(s)*/
1360 p++;
1361 return q; /* return field */
1362 }
1363 }
1364
1365 case IN_STRING:
1366 if (*p == 0) { /*!< incomplete quoted string */
1367 state = EOB;
1368 return q;
1369 }
1370
1371 if (*p != '"') { // not end of line and still in a string
1372 p++;
1373 continue;
1374 }
1375 state = NORMAL; /* end of quoted string */
1376 p++;
1377
1378 continue;
1379
1380 case EOB: /* just in case */
1381 state = NORMAL;
1382 return NULL;
1383
1384 default:
1385 fprintf(stderr, "(Strtok):unknown state - %d",state);
1386 state = EOB;
1387 return NULL;
1388 }
1389
1390 }
1391
1392 return NULL; /* no more fields in buffer */
1393
1394 }
1395 #if 0
1396 bool startsWith(const char *str, const char *pre)
1397 {
1398 size_t lenpre = strlen(pre),
1399 lenstr = strlen(str);
1400 return lenstr < lenpre ? false : strncasecmp(pre, str, lenpre) == 0;
1401 }
1402 #endif
1403
1404 /*
1405 * Removes the trailing spaces from a string.
1406 */
rtrim(char * s)1407 char *rtrim(char *s)
1408 {
1409 if (! s)
1410 return s;
1411 int index;
1412
1413 //for (index = (int)strlen(s) - 1; index >= 0 && (s[index] == ' ' || s[index] == '\t'); index--)
1414 for (index = (int)strlen(s) - 1; index >= 0 && isspace(s[index]); index--)
1415 {
1416 s[index] = '\0';
1417 }
1418 return(s);
1419 }
1420
ltrim(char * s)1421 char *ltrim(char *s)
1422 /*
1423 * Removes the leading spaces from a string.
1424 */
1425 {
1426 char *p;
1427 if (s == NULL)
1428 return NULL;
1429
1430 //for (p = s; (*p == ' ' || *p == '\t') && *p != '\0'; p++)
1431 for (p = s; isspace(*p) && *p != '\0'; p++)
1432 ;
1433
1434 //strcpy(s, p);
1435 memmove(s, p, strlen(p) + 1);
1436 return(s);
1437 }
1438
trim(char * s)1439 char *trim(char *s)
1440 {
1441 return ltrim(rtrim(s));
1442 }
1443
1444 char *
stripquotes(char * s)1445 stripquotes(char *s)
1446 {
1447 if (! s || ! *s)
1448 return s;
1449 /*
1450 char *p;
1451
1452 while ((p = strchr(s, '"')))
1453 *p = ' ';
1454 strchop(s);
1455
1456 return s;
1457 */
1458 int nLast = (int)strlen(s) - 1;
1459 // trim away leading/trailing "'s
1460 if (s[0] == '"')
1461 s[0] = ' ';
1462 if (s[nLast] == '"')
1463 s[nLast] = ' ';
1464 return trim(s);
1465 }
1466
1467 #include <ctype.h>
1468
1469 // XXX what about config=addr7=123, where clist has a "addr%"?
1470
1471 // return -2: error; -1: done; >= 0 option found
cfg_parse(const char * tag,const char * cptr,config_list_t * clist,config_state_t * state,int64_t * result)1472 int cfg_parse (const char * tag, const char * cptr, config_list_t * clist, config_state_t * state, int64_t * result)
1473 {
1474 if (! cptr)
1475 return -2;
1476 char * start = NULL;
1477 if (! state -> copy)
1478 {
1479 state -> copy = strdup (cptr);
1480 start = state -> copy;
1481 state -> statement_save = NULL;
1482 }
1483
1484 int ret = -2; // error
1485
1486 // grab every thing up to the next semicolon
1487 char * statement;
1488 statement = strtok_r (start, ";", & state -> statement_save);
1489 start = NULL;
1490 if (! statement)
1491 {
1492 ret = -1; // done
1493 goto done;
1494 }
1495
1496 // extract name
1497 char * name_start = statement;
1498 char * name_save = NULL;
1499 char * name;
1500 name = strtok_r (name_start, "=", & name_save);
1501 if (! name)
1502 {
1503 sim_printf ("error: %s: can't parse name\n", tag);
1504 goto done;
1505 }
1506
1507 // lookup name
1508 config_list_t * p = clist;
1509 while (p -> name)
1510 {
1511 if (strcasecmp (name, p -> name) == 0)
1512 break;
1513 p ++;
1514 }
1515 if (! p -> name)
1516 {
1517 sim_printf ("error: %s: don't know name <%s>\n", tag, name);
1518 goto done;
1519 }
1520
1521 // extract value
1522 char * value;
1523 value = strtok_r (NULL, "", & name_save);
1524 if (! value)
1525 {
1526 // Special case; min>max and no value list
1527 // means that a missing value is ok
1528 if (p -> min > p -> max && ! p -> value_list)
1529 {
1530 return (int) (p - clist);
1531 }
1532 sim_printf ("error: %s: can't parse value\n", tag);
1533 goto done;
1534 }
1535
1536 // first look to value in the value list
1537 config_value_list_t * v = p -> value_list;
1538 if (v)
1539 {
1540 while (v -> value_name)
1541 {
1542 if (strcasecmp (value, v -> value_name) == 0)
1543 break;
1544 v ++;
1545 }
1546
1547 // Hit?
1548 if (v -> value_name)
1549 {
1550 * result = v -> value;
1551 return (int) (p - clist);
1552 }
1553 }
1554
1555 // Must be a number
1556
1557 if (p -> min > p -> max)
1558 {
1559 sim_printf ("error: %s: can't parse value\n", tag);
1560 goto done;
1561 }
1562
1563 if (strlen (value) == 0)
1564 {
1565 sim_printf ("error: %s: missing value\n", tag);
1566 goto done;
1567 }
1568 char * endptr;
1569 int64_t n = strtoll (value, & endptr, 0);
1570 if (* endptr)
1571 {
1572 sim_printf ("error: %s: can't parse value\n", tag);
1573 goto done;
1574 }
1575
1576 // XXX small bug; doesn't check for junk after number...
1577 if (n < p -> min || n > p -> max)
1578 {
1579 sim_printf ("error: %s: value out of range\n", tag);
1580 goto done;
1581 }
1582
1583 * result = n;
1584 return (int) (p - clist);
1585
1586 done:
1587 free (state -> copy);
1588 state -> copy= NULL;
1589 return ret;
1590 }
1591
cfg_parse_done(config_state_t * state)1592 void cfg_parse_done (config_state_t * state)
1593 {
1594 if (state -> copy)
1595 free (state -> copy);
1596 state -> copy = NULL;
1597 }
1598
1599 // strdup with limited C-style escape processing
1600 //
1601 // strdupesc ("foo\nbar") --> 'f' 'o' 'o' 012 'b' 'a' 'r'
1602 //
1603 // Handles:
1604 // \\ backslash
1605 // \n newline
1606 // \t tab
1607 // \f formfeed
1608 // \r carrriage return
1609 // \0 null // doesn't work, commented out.
1610 //
1611 // \\ doesn't seem to work...
1612 // Also, a simh specific:
1613 //
1614 // \e (end simulation)
1615 //
1616 // the simh parser doesn't handle these very well...
1617 //
1618 // \_ space
1619 // \c comma
1620 // \s semicolon
1621 // \d dollar
1622 // \q double quote
1623 // \w <backslash>
1624 // \z ^D eof (DECism)
1625 // \^ caret
1626 // \x expect; used by the autoinput parserj
1627 //
1628 // And a special case:
1629 //
1630 // \TZ replaced with the timezone string. Three characters are used
1631 // to allow for space in the buffer.
1632 //
1633 // all others silently ignored and left unprocessed
1634 //
1635
strdupesc(const char * str)1636 char * strdupesc (const char * str)
1637 {
1638 char * buf = strdup (str);
1639 char * p = buf;
1640 while (* p)
1641 {
1642 if (* p != '\\')
1643 {
1644 p ++;
1645 continue;
1646 }
1647 if (p [1] == '\\') // \\ backslash
1648 * p = '\\';
1649 else if (p [1] == 'a') // \a ^A
1650 * p = '\001';
1651 else if (p [1] == 'w') // \w backslash
1652 * p = '\\';
1653 else if (p [1] == 'n') // \n newline
1654 * p = '\n';
1655 else if (p [1] == 't') // \t tab
1656 * p = '\t';
1657 else if (p [1] == 'f') // \f formfeed
1658 * p = '\f';
1659 else if (p [1] == 'r') // \r carriage return
1660 * p = '\r';
1661 else if (p [1] == 'e') // \e control E; Multics escape char.
1662 * p = '\005';
1663 else if (p [1] == '_') // \_ space; needed for leading or
1664 // trailing spaces (simh parser
1665 // issue)
1666 * p = ' ';
1667 else if (p [1] == 'c') // \c comma (simh parser issue)
1668 * p = ',';
1669 else if (p [1] == 's') // \s semicolon (simh parser issue)
1670 * p = ';';
1671 else if (p [1] == 'd') // \d dollar sign (simh parser issue)
1672 * p = '$';
1673 else if (p [1] == 'q') // \q double quote (simh parser issue)
1674 * p = '"';
1675 else if (p [1] == 'z') // \z ^D eof (VAXism)
1676 * p = '\004';
1677 else if (p [1] == 'k') // \k caret
1678 * p = '^';
1679 else if (p [1] == 'x') // \x expect
1680 * p = '\030';
1681 else if (p [1] == 'y') // \y expect
1682 * p = '\031';
1683 //else if (p [1] == '0') // \0 null; used as end of expect string
1684 //* p = 0;
1685
1686 #if 0
1687 else if (p [1] == 'T' && p [2] == 'Z') // \TZ time zone
1688 {
1689 strncpy (p, "pst", 3);
1690 time_t t = time (NULL);
1691 struct tm * lt = localtime (& t);
1692 if (strlen (lt -> tm_zone) == 3)
1693 {
1694 //strncpy (p, lt -> tm_zone, 3);
1695 p [0] = tolower (lt -> tm_zone [0]);
1696 p [1] = tolower (lt -> tm_zone [1]);
1697 p [2] = tolower (lt -> tm_zone [2]);
1698 }
1699 p += 2;
1700 }
1701 #endif
1702 else
1703 {
1704 p ++;
1705 continue;
1706 }
1707 p ++;
1708 memmove (p, p + 1, strlen (p + 1) + 1);
1709 }
1710 return buf;
1711 }
1712
1713 // Layout of data as read from simh tape format
1714 //
1715 // bits: buffer of bits from a simh tape. The data is
1716 // packed as 2 36 bit words in 9 eight bit bytes (2 * 36 == 7 * 9)
1717 // The of the bytes in bits is
1718 // byte value
1719 // 0 most significant byte in word 0
1720 // 1 2nd msb in word 0
1721 // 2 3rd msb in word 0
1722 // 3 4th msb in word 0
1723 // 4 upper half is 4 least significant bits in word 0
1724 // lower half is 4 most significant bit in word 1
1725 // 5 5th to 13th most signicant bits in word 1
1726 // 6 ...
1727 // 7 ...
1728 // 8 least significant byte in word 1
1729 //
1730
1731 // Multics humor: this is idiotic
1732
1733 // Data conversion routines
1734 //
1735 // 'bits' is the packed bit stream read from the simh tape
1736 // it is assumed to start at an even word36 address
1737 //
1738 // extr36
1739 // extract the word36 at woffset
1740 //
1741
extrASCII36(uint8 * bits,uint woffset)1742 static word36 extrASCII36 (uint8 * bits, uint woffset)
1743 {
1744 uint8 * p = bits + woffset * 4;
1745
1746 uint64 w;
1747 w = ((uint64) p [0]) << 27;
1748 w |= ((uint64) p [1]) << 18;
1749 w |= ((uint64) p [2]) << 9;
1750 w |= ((uint64) p [3]);
1751 // mask shouldn't be neccessary but is robust
1752 return (word36) (w & MASK36);
1753 }
1754
1755 // Data conversion routines
1756 //
1757 // 'bits' is the packed bit stream read from the simh tape
1758 // it is assumed to start at an even word36 address
1759 //
1760 // extr36
1761 // extract the word36 at woffset
1762 //
1763
extr36(uint8 * bits,uint woffset)1764 word36 extr36 (uint8 * bits, uint woffset)
1765 {
1766 uint isOdd = woffset % 2;
1767 uint dwoffset = woffset / 2;
1768 uint8 * p = bits + dwoffset * 9;
1769
1770 uint64 w;
1771 if (isOdd)
1772 {
1773 w = (((uint64) p [4]) & 0xf) << 32;
1774 w |= ((uint64) p [5]) << 24;
1775 w |= ((uint64) p [6]) << 16;
1776 w |= ((uint64) p [7]) << 8;
1777 w |= ((uint64) p [8]);
1778 }
1779 else
1780 {
1781 w = ((uint64) p [0]) << 28;
1782 w |= ((uint64) p [1]) << 20;
1783 w |= ((uint64) p [2]) << 12;
1784 w |= ((uint64) p [3]) << 4;
1785 w |= (((uint64) p [4]) >> 4) & 0xf;
1786 }
1787 // mask shouldn't be neccessary but is robust
1788 return (word36) (w & MASK36);
1789 }
1790
putASCII36(word36 val,uint8 * bits,uint woffset)1791 static void putASCII36 (word36 val, uint8 * bits, uint woffset)
1792 {
1793 uint8 * p = bits + woffset * 4;
1794 p [0] = (val >> 27) & 0xff;
1795 p [1] = (val >> 18) & 0xff;
1796 p [2] = (val >> 9) & 0xff;
1797 p [3] = (val ) & 0xff;
1798 }
1799
put36(word36 val,uint8 * bits,uint woffset)1800 void put36 (word36 val, uint8 * bits, uint woffset)
1801 {
1802 uint isOdd = woffset % 2;
1803 uint dwoffset = woffset / 2;
1804 uint8 * p = bits + dwoffset * 9;
1805
1806 if (isOdd)
1807 {
1808 p [4] &= 0xf0;
1809 p [4] |= (val >> 32) & 0x0f;
1810 p [5] = (val >> 24) & 0xff;
1811 p [6] = (val >> 16) & 0xff;
1812 p [7] = (val >> 8) & 0xff;
1813 p [8] = (val >> 0) & 0xff;
1814 //w = ((uint64) (p [4] & 0xf)) << 32;
1815 //w |= (uint64) (p [5]) << 24;
1816 //w |= (uint64) (p [6]) << 16;
1817 //w |= (uint64) (p [7]) << 8;
1818 //w |= (uint64) (p [8]);
1819 }
1820 else
1821 {
1822 p [0] = (val >> 28) & 0xff;
1823 p [1] = (val >> 20) & 0xff;
1824 p [2] = (val >> 12) & 0xff;
1825 p [3] = (val >> 4) & 0xff;
1826 p [4] &= 0x0f;
1827 p [4] |= (val << 4) & 0xf0;
1828 //w = (uint64) (p [0]) << 28;
1829 //w |= (uint64) (p [1]) << 20;
1830 //w |= (uint64) (p [2]) << 12;
1831 //w |= (uint64) (p [3]) << 4;
1832 //w |= ((uint64) (p [4]) >> 4) & 0xf;
1833 }
1834 // mask shouldn't be neccessary but is robust
1835 }
1836
extractASCII36FromBuffer(uint8 * bufp,t_mtrlnt tbc,uint * words_processed,word36 * wordp)1837 int extractASCII36FromBuffer (uint8 * bufp, t_mtrlnt tbc, uint * words_processed, word36 *wordp)
1838 {
1839 uint wp = * words_processed; // How many words have been processed
1840
1841 // 1 dps8m word == 4 bytes
1842
1843 uint bytes_processed = wp * 4;
1844 if (bytes_processed >= tbc)
1845 return 1;
1846 //sim_printf ("store 0%08lo@0%012"PRIo64"\n", wordp - M, extr36 (bufp, wp));
1847
1848 * wordp = extrASCII36 (bufp, wp);
1849 //if (* wordp & ~MASK36) sim_printf (">>>>>>> extr %012"PRIo64"\n", * wordp);
1850 //sim_printf ("* %06lo = %012"PRIo64"\n", wordp - M, * wordp);
1851 (* words_processed) ++;
1852
1853 return 0;
1854 }
1855
extractWord36FromBuffer(uint8 * bufp,t_mtrlnt tbc,uint * words_processed,word36 * wordp)1856 int extractWord36FromBuffer (uint8 * bufp, t_mtrlnt tbc, uint * words_processed, word36 *wordp)
1857 {
1858 uint wp = * words_processed; // How many words have been processed
1859
1860 // 2 dps8m words == 9 bytes
1861
1862 uint bytes_processed = (wp * 9 + 1) / 2;
1863 if (bytes_processed >= tbc)
1864 return 1;
1865 //sim_printf ("store 0%08lo@0%012"PRIo64"\n", wordp - M, extr36 (bufp, wp));
1866
1867 * wordp = extr36 (bufp, wp);
1868 //if (* wordp & ~MASK36) sim_printf (">>>>>>> extr %012"PRIo64"\n", * wordp);
1869 //sim_printf ("* %06lo = %012"PRIo64"\n", wordp - M, * wordp);
1870 (* words_processed) ++;
1871
1872 return 0;
1873 }
1874
insertASCII36toBuffer(uint8 * bufp,t_mtrlnt tbc,uint * words_processed,word36 word)1875 int insertASCII36toBuffer (uint8 * bufp, t_mtrlnt tbc, uint * words_processed, word36 word)
1876 {
1877 uint wp = * words_processed; // How many words have been processed
1878
1879 // 1 dps8m word == 4 bytes
1880
1881 uint bytes_processed = wp * 4;
1882 if (bytes_processed >= tbc)
1883 return 1;
1884 //sim_printf ("store 0%08lo@0%012"PRIo64"\n", wordp - M, extr36 (bufp, wp));
1885
1886 putASCII36 (word, bufp, wp);
1887 //sim_printf ("* %06lo = %012"PRIo64"\n", wordp - M, * wordp);
1888 (* words_processed) ++;
1889
1890 return 0;
1891 }
1892
insertWord36toBuffer(uint8 * bufp,t_mtrlnt tbc,uint * words_processed,word36 word)1893 int insertWord36toBuffer (uint8 * bufp, t_mtrlnt tbc, uint * words_processed, word36 word)
1894 {
1895 uint wp = * words_processed; // How many words have been processed
1896
1897 // 2 dps8m words == 9 bytes
1898
1899 uint bytes_processed = (wp * 9 + 1) / 2;
1900 if (bytes_processed >= tbc)
1901 return 1;
1902 //sim_printf ("store 0%08lo@0%012"PRIo64"\n", wordp - M, extr36 (bufp, wp));
1903
1904 put36 (word, bufp, wp);
1905 //sim_printf ("* %06lo = %012"PRIo64"\n", wordp - M, * wordp);
1906 (* words_processed) ++;
1907
1908 return 0;
1909 }
1910
1911 #ifndef NEED_128
print_uint128_r(uint128 n,char * p)1912 static void print_uint128_r (uint128 n, char * p)
1913 {
1914 if (n == 0)
1915 return;
1916
1917 print_uint128_r(n / 10, p);
1918 if (p)
1919 {
1920 char s [2];
1921 s [0] = n % 10 + '0';
1922 s [1] = '\0';
1923 strcat (p, s);
1924 }
1925 else
1926 sim_printf("%c", (int) (n%10+0x30));
1927 }
1928
print_int128(int128 n,char * p)1929 void print_int128 (int128 n, char * p)
1930 {
1931 if (n == 0)
1932 {
1933 if (p)
1934 strcat (p, "0");
1935 else
1936 sim_printf ("0");
1937 return;
1938 }
1939 if (n < 0)
1940 {
1941 if (p)
1942 strcat (p, "-");
1943 else
1944 sim_printf ("-");
1945 n = -n;
1946 }
1947 print_uint128_r ((uint128) n, p);
1948 }
1949 #endif
1950
1951 // See: https://gist.github.com/diabloneo/9619917
timespec_diff(struct timespec * start,struct timespec * stop,struct timespec * result)1952 void timespec_diff(struct timespec * start, struct timespec * stop,
1953 struct timespec * result)
1954 {
1955 if ((stop->tv_nsec - start->tv_nsec) < 0) {
1956 result->tv_sec = stop->tv_sec - start->tv_sec - 1;
1957 result->tv_nsec = stop->tv_nsec - start->tv_nsec + 1000000000L;
1958 } else {
1959 result->tv_sec = stop->tv_sec - start->tv_sec;
1960 result->tv_nsec = stop->tv_nsec - start->tv_nsec;
1961 }
1962
1963 return;
1964 }
1965
1966 #if 0
1967 // Calculate current TR value
1968
1969 void currentTR (word27 * trunits, bool * ovf)
1970 {
1971 struct timespec now, delta;
1972 clock_gettime (CLOCK_BOOTTIME, & now);
1973 timespec_diff (& cpu.rTRTime, & now, & delta);
1974 if (delta.tv_sec > 263)
1975 {
1976 // The elapsed time is manifestly larger then the TR range
1977 * trunits = (~0llu) & MASK27;
1978 * ovf = true;
1979 return;
1980 }
1981 // difference in nSecs
1982 unsigned long dns = (unsigned long) delta.tv_sec * 1000000000 +
1983 (unsigned long) delta.tv_nsec;
1984 // in Timer ticks
1985 unsigned long ticks = dns / 1953 /* 1953.125 */;
1986
1987 // Runout?
1988 if (ticks >= cpu.rTR)
1989 {
1990 * trunits = (~0llu) & MASK27;
1991 * ovf = true;
1992 return;
1993 }
1994 * trunits = (cpu.rTR - ticks) & MASK27;
1995 //sim_printf ("time left %f\n", (float) (* trunits) / 5120000);
1996 * ovf = false;
1997 }
1998 #endif
1999