1 /*
2  * Copyright (c) 2016 Charles Anthony
3  * Copyright (c) 2021 The DPS8M Development Team
4  *
5  * All rights reserved.
6  *
7  * This software is made available under the terms of the ICU
8  * License, version 1.8.1 or later.  For more details, see the
9  * LICENSE.md file at the top-level directory of this distribution.
10  */
11 
12 // history debugging
13 
14 #ifdef TESTING
15 
16 # include <unistd.h>
17 # include <sys/types.h>
18 # include <sys/stat.h>
19 # include <fcntl.h>
20 
21 # include "dps8.h"
22 # include "dps8_sys.h"
23 # include "dps8_cpu.h"
24 # include "dps8_utils.h"
25 # include "hdbg.h"
26 
27 # include "dps8_faults.h"
28 
29 enum hevtType {
30   hevtEmpty = 0,
31   hevtTrace,
32   hevtM,
33   hevtAPU,
34   hevtFault,
35   hevtIntrSet,
36   hevtIntr,
37   hevtReg,
38   hevtPAReg,
39   hevtDSBRReg,
40   hevtIEFP,
41   hevtNote,
42 };
43 
44 struct hevt {
45   enum hevtType type;
46   uint64 time;
47   uint cpu_idx;
48   char ctx[16];
49   bool rw; // F: read  T: write
50   union {
51     struct {
52       addr_modes_e addrMode;
53       word15 segno;
54       word18 ic;
55       word3 ring;
56       word36 inst;
57     } trace;
58 
59     struct {
60       word24 addr;
61       word36 data;
62     } memref;
63 
64     struct {
65       _fault faultNumber;
66       _fault_subtype subFault;
67       char faultMsg [64];
68     } fault;
69 
70     struct {
71       uint inum;
72       uint cpuUnitIdx;
73       uint scuUnitIdx;
74     } intrSet;
75 
76     struct {
77       uint intr_pair_addr;
78     } intr;
79 
80     struct {
81       enum hregs_t type;
82       word36 data;
83     } reg;
84 
85     struct {
86       enum hregs_t type;
87       struct par_s data;
88     } par;
89 
90     struct {
91       enum hdbgIEFP_e type;
92       word15 segno;
93       word18 offset;
94     } iefp;
95 
96     struct {
97       enum hregs_t type;
98       struct dsbr_s data;
99     } dsbr;
100 
101     struct {
102       enum hregs_t type;
103       word15 segno;
104       word18 offset;
105       word24 final;
106       word36 data;
107     } apu;
108     struct {
109 # define NOTE_SZ 64
110       char noteBody [NOTE_SZ];
111     } note;
112   };
113 };
114 
115 static struct hevt * hevents = NULL;
116 static long hdbgSize = 0;
117 static long hevtPtr = 0;
118 static long hevtMark = 0;
119 static long hdbgSegNum = -1;
120 static bool blacklist[MAX18];
121 static long hdbgCPUMask = 0;
122 
createBuffer(void)123 static void createBuffer (void) {
124   if (hevents) {
125     free (hevents);
126     hevents = NULL;
127   }
128   if (hdbgSize <= 0)
129     return;
130   hevents = malloc (sizeof (struct hevt) * hdbgSize);
131   if (! hevents) {
132     sim_printf ("hdbg createBuffer failed\n");
133     return;
134   }
135   memset (hevents, 0, sizeof (struct hevt) * hdbgSize);
136 
137   hevtPtr = 0;
138 }
139 
hdbg_inc(void)140 static long hdbg_inc (void) {
141   //hevtPtr = (hevtPtr + 1) % hdbgSize;
142   long ret = __sync_fetch_and_add (& hevtPtr, 1l) % hdbgSize;
143 
144   if (hevtMark > 0) {
145     long ret = __sync_fetch_and_sub (& hevtMark, 1l);
146     if (ret <= 0)
147       hdbgPrint ();
148   }
149   return ret;
150 }
151 
152 # define hev(t, tf, filter) \
153   if (! hevents) \
154     goto done; \
155   if (filter && hdbgSegNum >= 0 && hdbgSegNum != cpu.PPR.PSR) \
156     goto done; \
157   if (filter && hdbgSegNum > 0 && blacklist[cpu.PPR.IC]) \
158     goto done; \
159   if (hdbgCPUMask && (hdbgCPUMask & (1 << current_running_cpu_idx))) \
160     goto done; \
161   unsigned long p = hdbg_inc (); \
162   hevents[p].type = t; \
163   hevents[p].cpu_idx = current_running_cpu_idx; \
164   hevents[p].time = cpu.cycleCnt; \
165   strncpy (hevents[p].ctx, ctx, 15); \
166   hevents[p].ctx[15] = 0; \
167   hevents[p].rw = tf;
168 
169 
170 # define FILTER true
171 # define NO_FILTER false
172 
173 # define WR true
174 # define RD false
175 
hdbgTrace(const char * ctx)176 void hdbgTrace (const char * ctx) {
177   hev (hevtTrace, RD, FILTER);
178   hevents[p].trace.addrMode = get_addr_mode ();
179   hevents[p].trace.segno = cpu.PPR.PSR;
180   hevents[p].trace.ic = cpu.PPR.IC;
181   hevents[p].trace.ring = cpu.PPR.PRR;
182   hevents[p].trace.inst = IWB_IRODD;
183 done: ;
184 }
185 
hdbgMRead(word24 addr,word36 data,const char * ctx)186 void hdbgMRead (word24 addr, word36 data, const char * ctx) {
187   hev (hevtM, RD, FILTER);
188   hevents[p].memref.addr = addr;
189   hevents[p].memref.data = data;
190 done: ;
191 }
192 
hdbgMWrite(word24 addr,word36 data,const char * ctx)193 void hdbgMWrite (word24 addr, word36 data, const char * ctx) {
194   hev (hevtM, WR, FILTER);
195   hevents[p].memref.addr = addr;
196   hevents[p].memref.data = data;
197 done: ;
198 }
199 
hdbgAPURead(word15 segno,word18 offset,word24 final,word36 data,const char * ctx)200 void hdbgAPURead (word15 segno, word18 offset, word24 final, word36 data, const char * ctx) {
201   hev (hevtAPU, RD, FILTER);
202   hevents[p].apu.segno = segno;
203   hevents[p].apu.offset = offset;
204   hevents[p].apu.final = final;
205   hevents[p].apu.data = data;
206 done: ;
207 }
208 
hdbgAPUWrite(word15 segno,word18 offset,word24 final,word36 data,const char * ctx)209 void hdbgAPUWrite (word15 segno, word18 offset, word24 final, word36 data, const char * ctx) {
210   hev (hevtAPU, WR, FILTER);
211   hevents[p].apu.segno = segno;
212   hevents[p].apu.offset = offset;
213   hevents[p].apu.final = final;
214   hevents[p].apu.data = data;
215 done: ;
216 }
217 
hdbgFault(_fault faultNumber,_fault_subtype subFault,const char * faultMsg,const char * ctx)218 void hdbgFault (_fault faultNumber, _fault_subtype subFault, const char * faultMsg, const char * ctx) {
219   hev (hevtFault, RD, FILTER);
220   hevents[p].fault.faultNumber = faultNumber;
221   hevents[p].fault.subFault = subFault;
222   strncpy (hevents[p].fault.faultMsg, faultMsg, 63);
223   hevents[p].fault.faultMsg[63] = 0;
224 done: ;
225 }
226 
hdbgIntrSet(uint inum,uint cpuUnitIdx,uint scuUnitIdx,const char * ctx)227 void hdbgIntrSet (uint inum, uint cpuUnitIdx, uint scuUnitIdx, const char * ctx) {
228   hev (hevtIntrSet, RD, FILTER);
229   hevents[p].intrSet.inum = inum;
230   hevents[p].intrSet.cpuUnitIdx = cpuUnitIdx;
231   hevents[p].intrSet.scuUnitIdx = scuUnitIdx;
232 done: ;
233 }
234 
hdbgIntr(uint intr_pair_addr,const char * ctx)235 void hdbgIntr (uint intr_pair_addr, const char * ctx) {
236   hev (hevtIntr, RD, FILTER);
237   hevents[p].cpu_idx = current_running_cpu_idx;
238   hevents[p].time = cpu.cycleCnt;
239   strncpy (hevents[p].ctx, ctx, 15);
240   hevents[p].ctx[15] = 0;
241   hevents[p].intr.intr_pair_addr = intr_pair_addr;
242 done: ;
243 }
244 
hdbgRegR(enum hregs_t type,word36 data,const char * ctx)245 void hdbgRegR (enum hregs_t type, word36 data, const char * ctx) {
246   hev (hevtReg, RD, FILTER);
247   hevents[p].reg.type = type;
248   hevents[p].reg.data = data;
249 done: ;
250 }
251 
252 
hdbgRegW(enum hregs_t type,word36 data,const char * ctx)253 void hdbgRegW (enum hregs_t type, word36 data, const char * ctx) {
254   hev (hevtReg, WR, FILTER);
255   hevents[p].reg.type = type;
256   hevents[p].reg.data = data;
257 done: ;
258 }
259 
260 
hdbgPARegR(enum hregs_t type,struct par_s * data,const char * ctx)261 void hdbgPARegR (enum hregs_t type, struct par_s * data, const char * ctx) {
262   hev (hevtPAReg, RD, FILTER);
263   hevents[p].par.type = type;
264   hevents[p].par.data = * data;
265 done: ;
266 }
267 
hdbgPARegW(enum hregs_t type,struct par_s * data,const char * ctx)268 void hdbgPARegW (enum hregs_t type, struct par_s * data, const char * ctx) {
269   hev (hevtPAReg, WR, FILTER);
270     hevents[p].par.type = type;
271     hevents[p].par.data = * data;
272 done: ;
273 }
274 
275 # if 0
276 void hdbgDSBRRegR (enum hregs_t type, struct dsbr_s * data, const char * ctx) {
277   hev (hevtDSBRReg, RD, FILTER);
278     hevents[p].dsbr.type = type;
279     hevents[p].dsbr.data = * data;
280 done: ;
281 }
282 
283 void hdbgDSBRRegW (enum hregs_t type, struct dsbr_s * data, const char * ctx) {
284   hev (hevtDSBRReg, WR, FILTER);
285     hevents[p].dsbr.type = type;
286     hevents[p].dsbr.data = * data;
287 done: ;
288 }
289 # endif
290 
hdbgIEFP(enum hdbgIEFP_e type,word15 segno,word18 offset,const char * ctx)291 void hdbgIEFP (enum hdbgIEFP_e type, word15 segno, word18 offset, const char * ctx) {
292   hev (hevtIEFP, RD, FILTER);
293   hevents [p].iefp.type = type;
294   hevents [p].iefp.segno = segno;
295   hevents [p].iefp.offset = offset;
296 done: ;
297 }
298 
hdbgNote(const char * ctx,const char * fmt,...)299 void hdbgNote (const char * ctx, const char * fmt, ...) {
300   hev (hevtNote, RD, NO_FILTER);
301   va_list arglist;
302   va_start (arglist, fmt);
303   vsnprintf (hevents [p].note.noteBody, NOTE_SZ - 1, fmt, arglist);
304   va_end (arglist);
305 done: ;
306 }
307 
308 static FILE * hdbgOut = NULL;
309 
printM(struct hevt * p)310 static void printM (struct hevt * p) {
311   fprintf (hdbgOut, "DBG(%"PRId64")> CPU %d FINAL: %s %s %08o %012"PRIo64"\n",
312            p->time,
313            p->cpu_idx,
314            p->ctx,
315            p->rw ? "write" : "read ",
316            p->memref.addr,
317            p->memref.data);
318 }
319 
printAPU(struct hevt * p)320 static void printAPU (struct hevt * p) {
321   fprintf (hdbgOut, "DBG(%"PRId64")> CPU %d APU: %s %s %05o:%06o %08o %012"PRIo64"\n",
322            p->time,
323            p->cpu_idx,
324            p->ctx,
325            p->rw ? "write" : "read ",
326            p->apu.segno,
327            p->apu.offset,
328            p->apu.final,
329            p->apu.data);
330 }
331 
printTrace(struct hevt * p)332 static void printTrace (struct hevt * p) {
333   char buf[256];
334   if (p -> trace.addrMode == ABSOLUTE_mode) {
335     fprintf (hdbgOut, "DBG(%"PRId64")> CPU %d TRACE: %s %06o %o %012"PRIo64" (%s)\n",
336              p->time,
337              p->cpu_idx,
338              p->ctx,
339              p->trace.ic,
340              p->trace.ring,
341              p->trace.inst,
342              disassemble (buf, p->trace.inst));
343   } else {
344     fprintf (hdbgOut, "DBG(%"PRId64")> CPU %d TRACE: %s %05o:%06o %o %012"PRIo64" (%s)\n",
345              p->time,
346              p->cpu_idx,
347              p->ctx,
348              p->trace.segno,
349              p->trace.ic,
350              p->trace.ring,
351              p->trace.inst,
352              disassemble (buf, p->trace.inst));
353   }
354 }
355 
printFault(struct hevt * p)356 static void printFault (struct hevt * p) {
357   fprintf (hdbgOut, "DBG(%"PRId64")> CPU %d FAULT: %s Fault %d(0%o), sub %"PRId64"(0%"PRIo64"), '%s'\n",
358            p->time,
359            p->cpu_idx,
360            p->ctx,
361            p->fault.faultNumber,
362            p->fault.faultNumber,
363            p->fault.subFault.bits,
364            p->fault.subFault.bits,
365            p->fault.faultMsg);
366 }
367 
printIntrSet(struct hevt * p)368 static void printIntrSet (struct hevt * p) {
369   fprintf (hdbgOut, "DBG(%"PRId64")> CPU %d INTR_SET: %s number %d(0%o), CPU %u SCU %u\n",
370            p->time,
371            p->cpu_idx,
372            p->ctx,
373            p->intrSet.inum,
374            p->intrSet.inum,
375            p->intrSet.cpuUnitIdx,
376            p->intrSet.scuUnitIdx);
377 }
378 
printIntr(struct hevt * p)379 static void printIntr (struct hevt * p) {
380   fprintf (hdbgOut, "DBG(%"PRId64")> CPU %d INTR: %s Interrupt pair address %o\n",
381            p->time,
382            p->cpu_idx,
383            p->ctx,
384            p->intr.intr_pair_addr);
385 }
386 
387 // Keep sync'd with hregs_t
388 static char * regNames[] = {
389   "A  ",
390   "Q  ",
391   "X0", "X1", "X2", "X3", "X4", "X5", "X6", "X7",
392   "AR0", "AR1", "AR2", "AR3", "AR4", "AR5", "AR6", "AR7",
393   "PR0", "PR1", "PR2", "PR3", "PR4", "PR5", "PR6", "PR7",
394   "Y  ", "Z  ",
395   "IR ",
396   "DSBR",
397 };
398 
printReg(struct hevt * p)399 static void printReg (struct hevt * p) {
400   if (p->reg.type == hreg_IR)
401     fprintf (hdbgOut, "DBG(%"PRId64")> CPU %d REG: %s %s %s %012"PRIo64" Z%o N%o C %o O%o T%o \n",
402              p->time,
403              p->cpu_idx,
404              p->ctx,
405              p->rw ? "write" : "read ",
406              regNames[p->reg.type],
407              p->reg.data,
408              TSTF (p->reg.data, I_ZERO),
409              TSTF (p->reg.data, I_NEG),
410              TSTF (p->reg.data, I_CARRY),
411              TSTF (p->reg.data, I_OFLOW),
412              TSTF (p->reg.data, I_TALLY));
413   else if (p->reg.type >= hreg_X0 && p->reg.type <= hreg_X7)
414     fprintf (hdbgOut, "DBG(%"PRId64")> CPU %d REG: %s %s %s %06"PRIo64"\n",
415              p->time,
416              p->cpu_idx,
417              p->ctx,
418              p->rw ? "write" : "read ",
419              regNames[p->reg.type],
420              p->reg.data);
421   else
422     fprintf (hdbgOut, "DBG(%"PRId64")> CPU %d REG: %s %s  %s %012"PRIo64"\n",
423              p->time,
424              p->cpu_idx,
425              p->ctx,
426              p->rw ? "write" : "read ",
427              regNames[p->reg.type],
428              p->reg.data);
429 }
430 
printPAReg(struct hevt * p)431 static void printPAReg (struct hevt * p)
432 {
433   if (p->reg.type >= hreg_PR0 && p->reg.type <= hreg_PR7)
434     fprintf (hdbgOut, "DBG(%"PRId64")> CPU %d REG: %s %s %s %05o:%06o BIT %2o RNR %o\n",
435              p->time,
436              p->cpu_idx,
437              p->ctx,
438              p->rw ? "write" : "read ",
439              regNames[p->reg.type],
440              p->par.data.SNR,
441              p->par.data.WORDNO,
442              p->par.data.PR_BITNO,
443              p->par.data.RNR);
444   else
445     fprintf (hdbgOut, "DBG(%"PRId64")> CPU %d REG: %s write %s %05o:%06o CHAR %o BIT %2o RNR %o\n",
446              p->time,
447              p->cpu_idx,
448              p->ctx,
449              regNames[p->reg.type],
450              p->par.data.SNR,
451              p->par.data.WORDNO,
452              p->par.data.AR_CHAR,
453              p->par.data.AR_BITNO,
454              p->par.data.RNR);
455 }
456 
printDSBRReg(struct hevt * p)457 static void printDSBRReg (struct hevt * p) {
458   fprintf (hdbgOut, "DBG(%"PRId64")> CPU %d REG: %s %s %s %05o:%06o BIT %2o RNR %o\n",
459            p->time,
460            p->cpu_idx,
461            p->ctx,
462            p->rw ? "write" : "read ",
463            regNames[p->reg.type],
464            p->par.data.SNR,
465            p->par.data.WORDNO,
466            p->par.data.PR_BITNO,
467            p->par.data.RNR);
468 }
469 
printIEFP(struct hevt * p)470 static void printIEFP (struct hevt * p) {
471   switch (p->iefp.type) {
472     case hdbgIEFP_abs_bar_read:
473       fprintf (hdbgOut, "DBG(%"PRId64")> CPU %d IEFP ABS BAR READ:  |%06o\n",
474                p->time,
475                p->cpu_idx,
476                p->iefp.offset);
477       break;
478 
479     case hdbgIEFP_abs_read:
480       fprintf (hdbgOut, "DBG(%"PRId64")> CPU %d IEFP ABS     READ:  :%06o\n",
481                p->time,
482                p->cpu_idx,
483                p->iefp.offset);
484       break;
485 
486     case hdbgIEFP_bar_read:
487       fprintf (hdbgOut, "DBG(%"PRId64")> CPU %d IEFP APP BAR READ:  %05o|%06o\n",
488                p->time,
489                p->cpu_idx,
490                p->iefp.segno,
491                p->iefp.offset);
492       break;
493 
494     case hdbgIEFP_read:
495       fprintf (hdbgOut, "DBG(%"PRId64")> CPU %d IEFP APP     READ:  %05o:%06o\n",
496                p->time,
497                p->cpu_idx,
498                p->iefp.segno,
499                p->iefp.offset);
500       break;
501 
502     case hdbgIEFP_abs_bar_write:
503       fprintf (hdbgOut, "DBG(%"PRId64")> CPU %d IEFP ABS BAR WRITE: |%06o\n",
504                p->time,
505                p->cpu_idx,
506                p->iefp.offset);
507       break;
508 
509     case hdbgIEFP_abs_write:
510       fprintf (hdbgOut, "DBG(%"PRId64")> CPU %d IEFP ABS     WRITE: :%06o\n",
511                p->time,
512                p->cpu_idx,
513                p->iefp.offset);
514       break;
515 
516     case hdbgIEFP_bar_write:
517       fprintf (hdbgOut, "DBG(%"PRId64")> CPU %d IEFP APP BAR WRITE: %05o|%06o\n",
518                p->time,
519                p->cpu_idx,
520                p->iefp.segno,
521                p->iefp.offset);
522       break;
523 
524     case hdbgIEFP_write:
525       fprintf (hdbgOut, "DBG(%"PRId64")> CPU %d IEFP APP     WRITE: %05o:%06o\n",
526                p->time,
527                p->cpu_idx,
528                p->iefp.segno,
529                p->iefp.offset);
530       break;
531 
532     default:
533       fprintf (hdbgOut, "DBG(%"PRId64")> CPU %d IEFP ??? ??? WRITE: %05o?%06o\n",
534                p->time,
535                p->cpu_idx,
536                p->iefp.segno,
537                p->iefp.offset);
538       break;
539   }
540 }
541 
printNote(struct hevt * p)542 static void printNote (struct hevt * p) {
543   fprintf (hdbgOut, "DBG(%"PRId64")> Note: %s\n",
544                p->time,
545                p->note.noteBody);
546 }
547 
hdbgPrint(void)548 void hdbgPrint (void) {
549   sim_printf ("hdbg print\n");
550   if (! hevents)
551     goto done;
552   struct hevt * t = hevents;
553   hevents = NULL;
554   hdbgOut = fopen ("hdbg.list", "w");
555   if (! hdbgOut) {
556     sim_printf ("can't open hdbg.list\n");
557     goto done;
558   }
559   time_t curtime;
560   time (& curtime);
561   fprintf (hdbgOut, "%s\n", ctime (& curtime));
562 
563   for (unsigned long p = 0; p < hdbgSize; p ++) {
564     unsigned long q = (hevtPtr + p) % hdbgSize;
565     struct hevt * evtp = t + q;
566     switch (evtp -> type) {
567       case hevtEmpty:
568         break;
569 
570       case hevtTrace:
571         printTrace (evtp);
572         break;
573 
574       case hevtM:
575         printM (evtp);
576         break;
577 
578       case hevtAPU:
579         printAPU (evtp);
580         break;
581 
582 # if 0
583       case hevtIWBUpdate:
584         printIWBUpdate (evtp);
585         break;
586 # endif
587 
588 # if 0
589       case hevtRegs:
590         printRegs (evtp);
591         break;
592 # endif
593 
594       case hevtFault:
595         printFault (evtp);
596         break;
597 
598       case hevtIntrSet:
599         printIntrSet (evtp);
600         break;
601 
602       case hevtIntr:
603         printIntr (evtp);
604         break;
605 
606       case hevtReg:
607         printReg (evtp);
608         break;
609 
610       case hevtPAReg:
611         printPAReg (evtp);
612         break;
613 
614       case hevtDSBRReg:
615         printDSBRReg (evtp);
616         break;
617 
618       case hevtIEFP:
619         printIEFP (evtp);
620         break;
621 
622       case hevtNote:
623         printNote (evtp);
624         break;
625 
626       default:
627         fprintf (hdbgOut, "hdbgPrint ? %d\n", evtp -> type);
628         break;
629     }
630   }
631   fclose (hdbgOut);
632 
633   int fd = open ("M.dump", O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
634   if (fd == -1) {
635     sim_printf ("can't open M.dump\n");
636     goto done;
637   }
638   // cast discards volatile
639   /* ssize_t n = */ write (fd, (const void *) M, MEMSIZE * sizeof (word36));
640   close (fd);
641 done: ;
642 }
643 
644 # if 0
645 void hdbg_mark (void) {
646   hevtMark = hdbgSize;
647   sim_printf ("hdbg mark set to %ld\n", hevtMark);
648 }
649 # endif
650 
hdbg_cpu_mask(UNUSED int32 arg,const char * buf)651 t_stat hdbg_cpu_mask (UNUSED int32 arg, const char * buf)
652   {
653     hdbgCPUMask = strtoul (buf, NULL, 0);
654     sim_printf ("hdbg CPU mask set to %ld\n", hdbgCPUMask);
655     return SCPE_OK;
656   }
657 
658 // set buffer size
hdbg_size(UNUSED int32 arg,const char * buf)659 t_stat hdbg_size (UNUSED int32 arg, const char * buf) {
660   hdbgSize = strtoul (buf, NULL, 0);
661   sim_printf ("hdbg size set to %ld\n", hdbgSize);
662   createBuffer ();
663   return SCPE_OK;
664 }
665 
666 // set target segment number
hdbgSegmentNumber(UNUSED int32 arg,const char * buf)667 t_stat hdbgSegmentNumber (UNUSED int32 arg, const char * buf) {
668   hdbgSegNum = strtoul (buf, NULL, 8);
669   sim_printf ("hdbg target segment number set to %lu\n", hdbgSize);
670   createBuffer ();
671   return SCPE_OK;
672 }
673 
hdbgBlacklist(UNUSED int32 arg,const char * buf)674 t_stat hdbgBlacklist (UNUSED int32 arg, const char * buf) {
675   char work[strlen (buf) + 1];
676   if (sscanf (buf, "%s", work) != 1)
677     return SCPE_ARG;
678   if (strcasecmp (work, "init") == 0) {
679     memset (blacklist, 0, sizeof (blacklist));
680     return SCPE_OK;
681   }
682   uint low, high;
683   if (sscanf (work, "%o-%o", & low, & high) != 2)
684     return SCPE_ARG;
685   if (low > MAX18 || high > MAX18)
686     return SCPE_ARG;
687   for (uint addr = low; addr <= high; addr ++)
688     blacklist[addr] = true;
689   return SCPE_OK;
690 }
691 
hdbg_print(UNUSED int32 arg,const char * buf)692 t_stat hdbg_print (UNUSED int32 arg, const char * buf) {
693   hdbgPrint ();
694   return SCPE_OK;
695 }
696 
697 #endif // TESTING
698