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