-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathscp.c
2024 lines (1799 loc) · 57.5 KB
/
scp.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/* Simulator control program
Copyright (c) 1993-1998,
Robert M Supnik, Digital Equipment Corporation
Commercial use prohibited
20-Aug-98 RMS Added radix commands
05-Jun-98 RMS Fixed bug in ^D handling for UNIX
10-Apr-98 RMS Added switches to all commands
26-Oct-97 RMS Added search capability
25-Jan-97 RMS Revised data types
23-Jan-97 RMS Added bi-endian I/O
06-Sep-96 RMS Fixed bug in variable length IEXAMINE
16-Jun-96 RMS Changed interface to parse/print_sym
06-Apr-96 RMS Added error checking in reset all
07-Jan-96 RMS Added register buffers in save/restore
11-Dec-95 RMS Fixed ordering bug in save/restore
22-May-95 RMS Added symbolic input
13-Apr-95 RMS Added symbolic printouts
*/
#define SCP 1 /* defining module */
#include "sim_defs.h"
#ifdef GAMEBOY
#include "gba/gba_fsio.h"
#include "gba/gba_intr.h"
#endif
#include <limits.h>
#include <signal.h>
#include <ctype.h>
#define EX_D 0 /* deposit */
#define EX_E 1 /* examine */
#define EX_I 2 /* interactive */
#define SCH_OR 0 /* search logicals */
#define SCH_AND 1
#define SCH_XOR 2
#define SCH_E 0 /* search booleans */
#define SCH_N 1
#define SCH_G 2
#define SCH_L 3
#define SCH_EE 4
#define SCH_NE 5
#define SCH_GE 6
#define SCH_LE 7
#define SWHIDE (1u << 26) /* enable hiding */
#define RU_RUN 0 /* run */
#define RU_GO 1 /* go */
#define RU_STEP 2 /* step */
#define RU_CONT 3 /* continue */
#define RU_BOOT 4 /* boot */
#define UPDATE_SIM_TIME(x) sim_time = sim_time + (x - sim_interval); \
x = sim_interval
extern char sim_name[];
extern DEVICE *sim_devices[];
extern REG *sim_PC;
extern char *sim_stop_messages[];
extern t_stat sim_instr (void);
extern t_stat sim_load (FILE *ptr);
extern int32 sim_emax;
extern t_stat print_sym (t_addr addr, t_value *val, UNIT *uptr, int32 sw);
extern t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val,
int32 sw);
extern t_stat ttinit (void);
extern t_stat ttrunstate (void);
extern t_stat ttcmdstate (void);
extern t_stat ttclose (void);
UNIT *sim_clock_queue = NULL;
int32 sim_interval = 0;
int32 sim_switches = 0;
#ifdef GAMEBOY
double sim_time;
int32 noqueue_time;
#else
static double sim_time;
static int32 noqueue_time;
#endif
volatile int32 stop_cpu = 0;
t_value *sim_eval = NULL;
int32 sim_end = 1; /* 1 = little, 0 = big */
unsigned char sim_flip[FLIP_SIZE];
#define print_val(a,b,c,d) fprint_val (stdout, (a), (b), (c), (d))
#define SZ_D(dp) (size_map[((dp) -> dwidth + CHAR_BIT - 1) / CHAR_BIT])
#define SZ_R(rp) \
(size_map[((rp) -> width + (rp) -> offset + CHAR_BIT - 1) / CHAR_BIT])
#define GET_SWITCHES(cp,gb) \
for (sim_switches = 0; *cp == '-'; ) { \
int32 lsw; \
cp = get_glyph (cp, gb, 0); \
if ((lsw = get_switches (gb)) <= 0) return SCPE_ARG; \
sim_switches = sim_switches | lsw; }
#define GET_RADIX(val,dft) \
if (sim_switches & SWMASK ('O')) val = 8; \
else if (sim_switches & SWMASK ('D')) val = 10; \
else if (sim_switches & SWMASK ('H')) val = 16; \
else val = dft;
int32 get_switches (char *cptr);
t_value get_rval (REG *rptr, int idx);
void put_rval (REG *rptr, int idx, t_value val, t_value mask);
t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr);
t_stat fprint_val (FILE *stream, t_value val, int rdx, int wid, int fmt);
char *read_line (char *ptr, int size, FILE *stream);
DEVICE *find_device (char *ptr, int32 *iptr);
DEVICE *find_dev_from_unit (UNIT *uptr);
REG *find_reg (char *ptr, char **optr, DEVICE *dptr);
t_stat detach_all (int start_device);
t_stat ex_reg (t_value val, int flag, REG *rptr);
t_stat dep_reg (int flag, char *cptr, REG *rptr);
t_stat ex_addr (int flag, t_addr addr, DEVICE *dptr, UNIT *uptr);
t_stat dep_addr (int flag, char *cptr, t_addr addr, DEVICE *dptr,
UNIT *uptr, int dfltinc);
SCHTAB *get_search (char *cptr, DEVICE *dptr, SCHTAB *schptr);
int test_search (t_value val, SCHTAB *schptr);
t_stat step_svc (UNIT *ptr);
UNIT step_unit = { UDATA (&step_svc, 0, 0) };
const char *scp_error_messages[] = {
"Address space exceeded",
"Unit not attached",
"I/O error",
"Checksum error",
"Format error",
"Unit not attachable",
"File open error",
"Memory exhausted",
"Invalid argument",
"Step expired",
"Unknown command",
"Read only argument",
"Command not completed",
"Simulation stopped",
"Goodbye",
"Console input I/O error",
"Console output I/O error",
"End of file",
"Relocation error",
"No settable parameters",
"Unit already attached" };
const size_t size_map[] = { sizeof (int8),
sizeof (int8), sizeof (int16), sizeof (int32), sizeof (int32)
#if defined (int64)
, sizeof (int64), sizeof (int64), sizeof (int64), sizeof (int64)
#endif
};
const t_value width_mask[] = { 0,
0x1, 0x3, 0x7, 0xF,
0x1F, 0x3F, 0x7F, 0xFF,
0x1FF, 0x3FF, 0x7FF, 0xFFF,
0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF,
0x1FFFF, 0x3FFFF, 0x7FFFF, 0xFFFFF,
0x1FFFFF, 0x3FFFFF, 0x7FFFFF, 0xFFFFFF,
0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF,
0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF
#if defined (int64)
, 0x1FFFFFFFF, 0x3FFFFFFFF, 0x7FFFFFFFF, 0xFFFFFFFFF,
0x1FFFFFFFFF, 0x3FFFFFFFFF, 0x7FFFFFFFFF, 0xFFFFFFFFFF,
0x1FFFFFFFFFF, 0x3FFFFFFFFFF, 0x7FFFFFFFFFF, 0xFFFFFFFFFFF,
0x1FFFFFFFFFFF, 0x3FFFFFFFFFFF, 0x7FFFFFFFFFFF, 0xFFFFFFFFFFFF,
0x1FFFFFFFFFFFF, 0x3FFFFFFFFFFFF, 0x7FFFFFFFFFFFF, 0xFFFFFFFFFFFFF,
0x1FFFFFFFFFFFFF, 0x3FFFFFFFFFFFFF, 0x7FFFFFFFFFFFFF, 0xFFFFFFFFFFFFFF,
0x1FFFFFFFFFFFFFF, 0x3FFFFFFFFFFFFFF,
0x7FFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFF,
0x1FFFFFFFFFFFFFFF, 0x3FFFFFFFFFFFFFFF,
0x7FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF
#endif
};
#ifdef GAMEBOY
int main ()
{
int argc = 1;
char *argv[] = { "sim", NULL };
#else
int main (int argc, char *argv[])
{
#endif
char cbuf[CBUFSIZE], gbuf[CBUFSIZE], *cptr;
int32 i, stat;
FILE *fpin;
union {int32 i; char c[sizeof (int32)]; } end_test;
t_stat reset_cmd (int flag, char *ptr);
t_stat exdep_cmd (int flag, char *ptr);
t_stat load_cmd (int flag, char *ptr);
t_stat run_cmd (int flag, char *ptr);
t_stat attach_cmd (int flag, char *ptr);
t_stat detach_cmd (int flag, char *ptr);
t_stat save_cmd (int flag, char *ptr);
t_stat restore_cmd (int flag, char *ptr);
t_stat exit_cmd (int flag, char *ptr);
t_stat set_cmd (int flag, char *ptr);
t_stat show_cmd (int flag, char *ptr);
t_stat add_cmd (int flag, char *ptr);
t_stat remove_cmd (int flag, char *ptr);
t_stat help_cmd (int flag, char *ptr);
GAMEBOY_STATIC CTAB cmd_table[] = {
{ "RESET", &reset_cmd, 0 },
{ "EXAMINE", &exdep_cmd, EX_E },
{ "IEXAMINE", &exdep_cmd, EX_E+EX_I },
{ "DEPOSIT", &exdep_cmd, EX_D },
{ "IDEPOSIT", &exdep_cmd, EX_D+EX_I },
{ "RUN", &run_cmd, RU_RUN },
{ "GO", &run_cmd, RU_GO },
{ "STEP", &run_cmd, RU_STEP },
{ "CONT", &run_cmd, RU_CONT },
{ "BOOT", &run_cmd, RU_BOOT },
{ "ATTACH", &attach_cmd, 0 },
{ "DETACH", &detach_cmd, 0 },
{ "SAVE", &save_cmd, 0 },
{ "RESTORE", &restore_cmd, 0 },
{ "GET", &restore_cmd, 0 },
{ "LOAD", &load_cmd, 0 },
{ "EXIT", &exit_cmd, 0 },
{ "QUIT", &exit_cmd, 0 },
{ "BYE", &exit_cmd, 0 },
{ "SET", &set_cmd, 0 },
{ "SHOW", &show_cmd, 0 },
{ "ADD", &add_cmd, 0 },
{ "REMOVE", &remove_cmd, 0 },
{ "HELP", &help_cmd, 0 },
{ NULL, NULL, 0 } };
/* Main command loop */
#ifdef GAMEBOY
gba_tty_init();
gba_intr_init();
gba_fsio_init();
#else
printf ("\n%s simulator V2.3d\n", sim_name);
#endif
end_test.i = 1; /* test endian-ness */
sim_end = end_test.c[0];
if (sim_emax <= 0) sim_emax = 1;
#ifdef GAMEBOY
if ((sim_eval = (t_value *)calloc (sim_emax, sizeof (t_value))) == NULL) {
#else
if ((sim_eval = calloc (sim_emax, sizeof (t_value))) == NULL) {
#endif
printf ("Unable to allocate examine buffer\n");
return 0; };
if ((stat = ttinit ()) != SCPE_OK) {
printf ("Fatal terminal initialization error\n%s\n",
scp_error_messages[stat - SCPE_BASE]);
return 0; }
stop_cpu = 0;
sim_interval = 0;
sim_time = 0;
noqueue_time = 0;
sim_clock_queue = NULL;
if ((stat = reset_all (0)) != SCPE_OK) {
printf ("Fatal simulator initialization error\n%s\n",
scp_error_messages[stat - SCPE_BASE]);
return 0; }
if ((argc > 1) && (argv[1] != NULL) &&
((fpin = fopen (argv[1], "r")) != NULL)) { /* command file? */
do { cptr = read_line (cbuf, CBUFSIZE, fpin);
if (cptr == NULL) break; /* exit on eof */
if (*cptr == 0) continue; /* ignore blank */
cptr = get_glyph (cptr, gbuf, 0); /* get command glyph */
for (i = 0; cmd_table[i].name != NULL; i++) {
if (MATCH_CMD (gbuf, cmd_table[i].name) == 0) {
stat = cmd_table[i].action (cmd_table[i].arg, cptr);
break; } }
if (stat >= SCPE_BASE)
printf ("%s\n", scp_error_messages[stat - SCPE_BASE]);
} while (stat != SCPE_EXIT); } /* end if cmd file */
#ifdef GAMEBOY
do {
#else
do { printf ("sim> "); /* prompt */
#endif
cptr = read_line (cbuf, CBUFSIZE, stdin); /* read command line */
stat = SCPE_UNK;
if (cptr == NULL) continue; /* ignore EOF */
if (*cptr == 0) continue; /* ignore blank */
cptr = get_glyph (cptr, gbuf, 0); /* get command glyph */
for (i = 0; cmd_table[i].name != NULL; i++) {
if (MATCH_CMD (gbuf, cmd_table[i].name) == 0) {
stat = cmd_table[i].action (cmd_table[i].arg, cptr);
break; } }
if (stat >= SCPE_BASE)
printf ("%s\n", scp_error_messages[stat - SCPE_BASE]);
} while (stat != SCPE_EXIT);
detach_all (0);
ttclose ();
return 0;
}
/* Exit command */
t_stat exit_cmd (int flag, char *cptr)
{
return SCPE_EXIT;
}
/* Help command */
t_stat help_cmd (int flag, char *cptr)
{
printf ("r{eset} {ALL|<device>} reset simulator\n");
printf ("e{xamine} <list> examine memory or registers\n");
printf ("ie{xamine} <list> interactive examine memory or registers\n");
printf ("d{eposit} <list> <val> deposit in memory or registers\n");
printf ("id{eposit} <list> interactive deposit in memory or registers\n");
printf ("l{oad} <file> load binary file\n");
printf ("ru{n} {new PC} reset and start simulation\n");
printf ("go {new PC} start simulation\n");
printf ("c{ont} continue simulation\n");
printf ("s{tep} {n} simulate n instructions\n");
printf ("b{oot} <device>|<unit> bootstrap device\n");
printf ("at{tach} <unit> <file> attach file to simulated unit\n");
printf ("det{ach} <unit> detach file from simulated unit\n");
printf ("sa{ve} <file> save simulator to file\n");
printf ("rest{ore}|ge{t} <file> restore simulator from file\n");
printf ("exi{t}|q{uit}|by{e} exit from simulation\n");
printf ("set <unit> <val> set unit parameter\n");
printf ("show <device> show device parameters\n");
printf ("sh{ow} c{onfiguration} show configuration\n");
printf ("sh{ow} q{ueue} show event queue\n");
printf ("sh{ow} t{ime} show simulated time\n");
printf ("ad{d} <unit> add unit to configuration\n");
printf ("rem{ove} <unit> remove unit from configuration\n");
printf ("h{elp} type this message\n");
return SCPE_OK;
}
/* Set command */
t_stat set_cmd (int flag, char *cptr)
{
int32 i, unitno;
t_stat r;
char gbuf[CBUFSIZE];
DEVICE *dptr;
UNIT *uptr;
MTAB *mptr;
t_stat set_radix (DEVICE *dptr, int flag);
GAMEBOY_STATIC CTAB set_table[] = {
{ "OCTAL", &set_radix, 8 },
{ "DECIMAL", &set_radix, 10 },
{ "HEX", &set_radix, 16 },
{ NULL, NULL, 0 } };
GET_SWITCHES (cptr, gbuf); /* test for switches */
cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */
dptr = find_device (gbuf, &unitno); /* find device */
if ((dptr == NULL) || (*cptr == 0)) return SCPE_ARG; /* argument? */
cptr = get_glyph (cptr, gbuf, 0); /* get glyph */
if (*cptr != 0) return SCPE_ARG; /* now eol? */
uptr = dptr -> units + unitno;
if (uptr -> flags & UNIT_DIS) return SCPE_ARG; /* disabled? */
for (i = 0; set_table[i].name != NULL; i++) { /* check globals */
if (MATCH_CMD (gbuf, set_table[i].name) == 0)
return set_table[i].action (dptr, set_table[i].arg); }
if (dptr -> modifiers == NULL) return SCPE_NOPARAM; /* any modifiers? */
for (mptr = dptr -> modifiers; mptr -> mask != 0; mptr++) {
if ((mptr -> mstring != NULL) &&
(MATCH_CMD (gbuf, mptr -> mstring) == 0)) {
if ((mptr -> valid != NULL) &&
((r = mptr -> valid (uptr, mptr -> match)) != SCPE_OK))
return r; /* invalid? */
uptr -> flags = (uptr -> flags & ~(mptr -> mask)) |
(mptr -> match & mptr -> mask); /* set new value */
return SCPE_OK; } }
return SCPE_ARG; /* no match */
}
/* Set radix routine */
t_stat set_radix (DEVICE *dptr, int flag)
{
dptr -> dradix = flag & 017;
return SCPE_OK;
}
/* Show command */
t_stat show_cmd (int flag, char *cptr)
{
int32 i;
char gbuf[CBUFSIZE];
DEVICE *dptr;
t_stat show_config (int flag);
t_stat show_queue (int flag);
t_stat show_time (int flag);
t_stat show_device (DEVICE *dptr);
GAMEBOY_STATIC CTAB show_table[] = {
{ "CONFIGURATION", &show_config, 0 },
{ "QUEUE", &show_queue, 0 },
{ "TIME", &show_time, 0 },
{ NULL, NULL, 0 } };
GET_SWITCHES (cptr, gbuf); /* test for switches */
cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */
if (*cptr != 0) return SCPE_ARG; /* now eol? */
for (i = 0; show_table[i].name != NULL; i++) { /* find command */
if (MATCH_CMD (gbuf, show_table[i].name) == 0)
return show_table[i].action (show_table[i].arg); }
dptr = find_device (gbuf, NULL); /* find device */
if (dptr == NULL) return SCPE_ARG;
return show_device (dptr);
}
/* Show processors */
t_stat show_device (DEVICE *dptr)
{
int32 j, ucnt;
UNIT *uptr;
MTAB *mptr;
printf ("%s", dptr -> name);
for (j = ucnt = 0; j < dptr -> numunits; j++) {
uptr = (dptr -> units) + j;
if (!(uptr -> flags & UNIT_DIS)) ucnt++; }
if (ucnt == 0) printf (", all units disabled\n");
if (ucnt > 1) printf (", %d units\n", ucnt);
for (j = 0; j < dptr -> numunits; j++) {
uptr = (dptr -> units) + j;
if (uptr -> flags & UNIT_DIS) continue;
if (ucnt > 1) printf (" unit %d", j);
if (uptr -> flags & UNIT_FIX)
printf (", %dK%s",
uptr -> capac / ((uptr -> flags & UNIT_BINK)? 1024: 1000),
((dptr -> dwidth / dptr -> aincr) > 8)? "W": "B");
if (uptr -> flags & UNIT_ATT)
printf (", attached to %s", uptr -> filename);
else if (uptr -> flags & UNIT_ATTABLE) printf (", not attached");
if (dptr -> modifiers != NULL) {
for (mptr = dptr -> modifiers; mptr -> mask != 0; mptr++) {
if ((mptr -> pstring != NULL) &&
((uptr -> flags & mptr -> mask) == mptr -> match))
printf (", %s", mptr -> pstring); } }
printf ("\n"); }
return SCPE_OK;
}
t_stat show_config (int flag)
{
int32 i;
DEVICE *dptr;
printf ("%s simulator configuration\n\n", sim_name);
for (i = 0; (dptr = sim_devices[i]) != NULL; i++) show_device (dptr);
return SCPE_OK;
}
t_stat show_queue (int flag)
{
DEVICE *dptr;
UNIT *uptr;
int32 accum;
if (sim_clock_queue == NULL) {
printf ("%s event queue empty, time = %-16.0f\n", sim_name, sim_time);
return SCPE_OK; }
printf ("%s event queue status, time = %-16.0f\n", sim_name, sim_time);
accum = 0;
for (uptr = sim_clock_queue; uptr != NULL; uptr = uptr -> next) {
if (uptr == &step_unit) printf (" Step timer");
else if ((dptr = find_dev_from_unit (uptr)) != NULL) {
printf (" %s", dptr -> name);
#ifdef GAMEBOY
if (dptr -> numunits > 1) printf (" unit %ld",
#else
if (dptr -> numunits > 1) printf (" unit %d",
#endif
uptr - dptr -> units); }
else printf (" Unknown");
printf (" at %d\n", accum + uptr -> time);
accum = accum + uptr -> time; }
return SCPE_OK;
}
t_stat show_time (int flag)
{
printf ("Time: %-16.0f\n", sim_time);
return SCPE_OK;
}
/* Add and remove commands and routines
ad[d] add unit to configuration
rem[ove] remove unit from configuration
*/
t_stat add_cmd (int flag, char *cptr)
{
int32 unitno;
char gbuf[CBUFSIZE];
DEVICE *dptr;
UNIT *uptr;
GET_SWITCHES (cptr, gbuf); /* test for switches */
cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */
dptr = find_device (gbuf, &unitno); /* locate device */
if ((dptr == NULL) || (*cptr != 0)) return SCPE_ARG; /* found it? */
uptr = dptr -> units + unitno; /* locate unit */
if ((uptr -> flags & UNIT_DISABLE) && (uptr -> flags & UNIT_DIS)) {
uptr -> flags = uptr -> flags & ~UNIT_DIS; /* enable it */
return SCPE_OK; }
return SCPE_ARG; /* not valid */
}
t_stat remove_cmd (int flag, char *cptr)
{
int32 unitno;
char gbuf[CBUFSIZE];
DEVICE *dptr;
UNIT *uptr;
GET_SWITCHES (cptr, gbuf); /* test for switches */
cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */
dptr = find_device (gbuf, &unitno); /* locate device */
if ((dptr == NULL) || (*cptr != 0)) return SCPE_ARG; /* found it? */
uptr = dptr -> units + unitno; /* locate unit */
if ((uptr -> flags & UNIT_DISABLE) && !(uptr -> flags & UNIT_DIS) &&
!(uptr -> flags & UNIT_ATT) && !sim_is_active (uptr)) {
uptr -> flags = uptr -> flags | UNIT_DIS; /* disable it */
return SCPE_OK; }
return SCPE_ARG; /* not valid */
}
/* Reset command and routines
re[set] reset all devices
re[set] all reset all devices
re[set] device reset specific device
*/
t_stat reset_cmd (int flag, char *cptr)
{
char gbuf[CBUFSIZE];
DEVICE *dptr;
GET_SWITCHES (cptr, gbuf); /* test for switches */
if (*cptr == 0) return (reset_all (0)); /* reset(cr) */
cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */
if (*cptr != 0) return SCPE_ARG; /* now (cr)? */
if (strcmp (gbuf, "ALL") == 0) return (reset_all (0));
if ((dptr = find_device (gbuf, NULL)) == NULL) return SCPE_ARG;
if (dptr -> reset != NULL) return dptr -> reset (dptr);
else return SCPE_OK;
}
/* Reset devices start..end
Inputs:
start = number of starting device
Outputs:
status = error status
*/
t_stat reset_all (int start)
{
DEVICE *dptr;
int32 i;
t_stat reason;
if ((start < 0) || (start > 1)) return SCPE_ARG;
for (i = start; (dptr = sim_devices[i]) != NULL; i++) {
if (dptr -> reset != NULL) {
reason = dptr -> reset (dptr);
if (reason != SCPE_OK) return reason; } }
return SCPE_OK;
}
/* Load command
lo[ad] filename load specified file
*/
t_stat load_cmd (int flag, char *cptr)
{
char gbuf[CBUFSIZE];
FILE *loadfile;
t_stat reason;
GET_SWITCHES (cptr, gbuf); /* test for switches */
if (*cptr == 0) return SCPE_ARG;
loadfile = fopen (cptr, "rb");
if (loadfile == NULL) return SCPE_OPENERR;
reason = sim_load (loadfile);
fclose (loadfile);
return reason;
}
/* Attach command
at[tach] unit file attach specified unit to file
*/
t_stat attach_cmd (int flag, char *cptr)
{
char gbuf[CBUFSIZE];
int32 unitno;
DEVICE *dptr;
UNIT *uptr;
GET_SWITCHES (cptr, gbuf); /* test for switches */
if (*cptr == 0) return SCPE_ARG;
cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */
if (*cptr == 0) return SCPE_ARG;
if ((dptr = find_device (gbuf, &unitno)) == NULL) return SCPE_ARG;
uptr = (dptr -> units) + unitno;
if (dptr -> attach != NULL) return dptr -> attach (uptr, cptr);
return attach_unit (uptr, cptr);
}
t_stat attach_unit (UNIT *uptr, char *cptr)
{
DEVICE *dptr;
t_stat reason;
if (uptr -> flags & UNIT_DIS) return SCPE_ARG; /* disabled? */
if (!(uptr -> flags & UNIT_ATTABLE)) return SCPE_NOATT; /* not attachable? */
if ((dptr = find_dev_from_unit (uptr)) == NULL) return SCPE_NOATT;
if (uptr -> flags & UNIT_ATT) { /* already attached? */
reason = detach_unit (uptr);
if (reason != SCPE_OK) return reason; }
uptr -> filename = calloc (CBUFSIZE, sizeof (char));
if (uptr -> filename == NULL) return SCPE_MEM;
strncpy (uptr -> filename, cptr, CBUFSIZE);
uptr -> fileref = fopen (cptr, "rb+");
if (uptr -> fileref == NULL) {
uptr -> fileref = fopen (cptr, "wb+");
if (uptr -> fileref == NULL) return SCPE_OPENERR;
printf ("%s: creating new file\n", dptr -> name); }
if (uptr -> flags & UNIT_BUFABLE) {
if ((uptr -> filebuf = calloc (uptr -> capac, SZ_D (dptr))) != NULL) {
printf ("%s: buffering file in memory\n", dptr -> name);
uptr -> hwmark = fxread (uptr -> filebuf, SZ_D (dptr),
uptr -> capac, uptr -> fileref);
uptr -> flags = uptr -> flags | UNIT_BUF; }
else if (uptr -> flags & UNIT_MUSTBUF) return SCPE_MEM; }
uptr -> flags = uptr -> flags | UNIT_ATT;
uptr -> pos = 0;
return SCPE_OK;
}
/* Detach command
det[ach] all detach all units
det[ach] unit detach specified unit
*/
t_stat detach_cmd (int flag, char *cptr)
{
char gbuf[CBUFSIZE];
int32 unitno;
DEVICE *dptr;
UNIT *uptr;
GET_SWITCHES (cptr, gbuf); /* test for switches */
if (*cptr == 0) return SCPE_ARG;
cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */
if (*cptr != 0) return SCPE_ARG;
if (strcmp (gbuf, "ALL") == 0) return (detach_all (0));
if ((dptr = find_device (gbuf, &unitno)) == NULL) return SCPE_ARG;
uptr = (dptr -> units) + unitno;
if (!(uptr -> flags & UNIT_ATTABLE)) return SCPE_NOATT;
if (dptr -> detach != NULL) return dptr -> detach (uptr);
return detach_unit (uptr);
}
/* Detach devices start..end
Inputs:
start = number of starting device
Outputs:
status = error status
*/
t_stat detach_all (int start)
{
int32 i, j;
t_stat reason;
DEVICE *dptr;
UNIT *uptr;
if ((start < 0) || (start > 1)) return SCPE_ARG;
for (i = start; (dptr = sim_devices[i]) != NULL; i++) {
for (j = 0; j < dptr -> numunits; j++) {
uptr = (dptr -> units) + j;
if (dptr -> detach != NULL) reason = dptr -> detach (uptr);
else reason = detach_unit (uptr);
if (reason != SCPE_OK) return reason; } }
return SCPE_OK;
}
t_stat detach_unit (UNIT *uptr)
{
DEVICE *dptr;
if (uptr == NULL) return SCPE_ARG;
if (!(uptr -> flags & UNIT_ATT)) return SCPE_OK;
if ((dptr = find_dev_from_unit (uptr)) == NULL) return SCPE_OK;
uptr -> flags = uptr -> flags & ~UNIT_ATT;
if (uptr -> flags & UNIT_BUF) {
printf ("%s: writing buffer to file\n", dptr -> name);
uptr -> flags = uptr -> flags & ~UNIT_BUF;
rewind (uptr -> fileref);
fxwrite (uptr -> filebuf, SZ_D (dptr), uptr -> hwmark, uptr -> fileref);
if (ferror (uptr -> fileref)) perror ("I/O error");
free (uptr -> filebuf);
uptr -> filebuf = NULL; }
free (uptr -> filename);
uptr -> filename = NULL;
return (fclose (uptr -> fileref) == EOF)? SCPE_IOERR: SCPE_OK;
}
/* Save command
sa[ve] filename save state to specified file
*/
t_stat save_cmd (int flag, char *cptr)
{
char gbuf[CBUFSIZE];
FILE *sfile;
int32 i, j, t, zerocnt;
t_addr k, high;
t_value val;
t_stat reason;
DEVICE *dptr;
UNIT *uptr;
REG *rptr;
#define WRITE_I(xx) fxwrite (&(xx), sizeof (xx), 1, sfile)
GET_SWITCHES (cptr, gbuf); /* test for switches */
if (*cptr == 0) return SCPE_ARG;
if ((sfile = fopen (cptr, "wb")) == NULL) return SCPE_OPENERR;
fputs (sim_name, sfile); /* sim name */
fputc ('\n', sfile);
WRITE_I (sim_time); /* sim time */
for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru devices */
fputs (dptr -> name, sfile); /* device name */
fputc ('\n', sfile);
for (j = 0; j < dptr -> numunits; j++) {
uptr = (dptr -> units) + j;
t = sim_is_active (uptr);
WRITE_I (j); /* unit number */
WRITE_I (t); /* activation time */
WRITE_I (uptr -> u3); /* unit specific */
WRITE_I (uptr -> u4);
if (uptr -> flags & UNIT_ATT) fputs (uptr -> filename, sfile);
fputc ('\n', sfile);
if (((uptr -> flags & (UNIT_FIX + UNIT_ATTABLE)) == UNIT_FIX) &&
(dptr -> examine != NULL) &&
((high = uptr -> capac) != 0)) { /* memory-like unit? */
WRITE_I (high); /* memory limit */
zerocnt = 0;
for (k = 0; k < high; k = k + (dptr -> aincr)) {
reason = dptr -> examine (&val, k, uptr, 0);
if (reason != SCPE_OK) return reason;
if (val == 0) zerocnt = zerocnt - 1;
else { if (zerocnt) WRITE_I (zerocnt);
zerocnt = 0;
WRITE_I (val); } }
if (zerocnt) WRITE_I (zerocnt); }
else { k = 0; /* no memory */
WRITE_I (k); } }
j = -1;
WRITE_I (j); /* end units */
for (rptr = dptr -> registers; /* loop thru regs */
(rptr != NULL) && (rptr -> name != NULL); rptr++) {
fputs (rptr -> name, sfile); /* name */
fputc ('\n', sfile);
for (j = 0; j < rptr -> depth; j++) { /* loop thru values */
val = get_rval (rptr, j); /* get value */
WRITE_I (val); } } /* store */
fputc ('\n', sfile); } /* end registers */
fputc ('\n', sfile); /* end devices */
reason = (ferror (sfile))? SCPE_IOERR: SCPE_OK; /* error during save? */
fclose (sfile);
return reason;
}
/* Restore command
re[store] filename restore state from specified file
*/
t_stat restore_cmd (int flag, char *cptr)
{
char buf[CBUFSIZE];
FILE *rfile;
int32 j, data, unitno, time;
t_addr k, high;
t_value val, mask;
t_stat reason;
DEVICE *dptr;
UNIT *uptr;
REG *rptr;
#define READ_S(xx) if (read_line ((xx), CBUFSIZE, rfile) == NULL) \
{ fclose (rfile); return SCPE_IOERR; }
#define READ_I(xx) if (fxread (&xx, sizeof (xx), 1, rfile) <= 0) \
{ fclose (rfile); return SCPE_IOERR; }
GET_SWITCHES (cptr, buf); /* test for switches */
if (*cptr == 0) return SCPE_ARG;
if ((rfile = fopen (cptr, "rb")) == NULL) return SCPE_OPENERR;
READ_S (buf); /* sim name */
if (strcmp (buf, sim_name)) {
printf ("Wrong system type: %s\n", buf);
fclose (rfile);
return SCPE_OK; }
READ_I (sim_time); /* sim time */
for ( ;; ) { /* device loop */
READ_S (buf); /* read device name */
if (buf[0] == 0) break; /* last? */
if ((dptr = find_device (buf, NULL)) == NULL) {
printf ("Invalid device name: %s\n", buf);
fclose (rfile);
return SCPE_INCOMP; }
for ( ;; ) { /* unit loop */
READ_I (unitno); /* unit number */
if (unitno < 0) break;
if (unitno >= dptr -> numunits) {
printf ("Invalid unit number %s%d\n", dptr -> name,
unitno);
fclose (rfile);
return SCPE_INCOMP; }
READ_I (time); /* event time */
uptr = (dptr -> units) + unitno;
sim_cancel (uptr);
if (time > 0) sim_activate (uptr, time - 1);
READ_I (uptr -> u3); /* device specific */
READ_I (uptr -> u4);
READ_S (buf); /* attached file */
if (buf[0] != 0) {
uptr -> flags = uptr -> flags & ~UNIT_DIS;
reason = attach_unit (uptr, buf);
if (reason != SCPE_OK) return reason; }
READ_I (high); /* memory capacity */
if ((high > 0) && /* validate if > 0 */
(((uptr -> flags & (UNIT_FIX + UNIT_ATTABLE)) != UNIT_FIX) ||
(high > uptr -> capac) || (dptr -> deposit == NULL))) {
printf ("Invalid memory bound: %u\n", high);
fclose (rfile);
return SCPE_INCOMP; }
for (k = 0; k < high; k = k + (dptr -> aincr)) {
READ_I (data);
if (data < 0) {
for (j = data + 1; j < 0; j++) {
reason = dptr -> deposit (0, k, uptr, 0);
if (reason != SCPE_OK) return reason;
k = k + (dptr -> aincr); }
data = 0; }
reason = dptr -> deposit (data, k, uptr, 0);
if (reason != SCPE_OK) return reason; }
} /* end unit loop */
for ( ;; ) { /* register loop */
READ_S (buf); /* read reg name */
if (buf[0] == 0) break; /* last? */
if ((rptr = find_reg (buf, NULL, dptr)) == NULL) {
printf ("Invalid register name: %s\n", buf);
fclose (rfile);
return SCPE_INCOMP; }
mask = width_mask[rptr -> width];
for (j = 0; j < rptr -> depth; j++) { /* loop thru values */
READ_I (val); /* read value */
if (val > mask)
printf ("Invalid register value: %s\n", buf);
else put_rval (rptr, j, val, mask); } }
} /* end device loop */
fclose (rfile);
return SCPE_OK;
}
/* Run, go, cont, step commands
ru[n] [new PC] reset and start simulation
go [new PC] start simulation
co[nt] start simulation
s[tep] [step limit] start simulation for 'limit' instructions
b[oot] device bootstrap from device and start simulation
*/
t_stat run_cmd (int flag, char *cptr)
{
#ifdef GAMEBOY
int nlpos = 0;
#endif
char gbuf[CBUFSIZE];
int32 i, j, step, unitno;
t_stat r;
t_addr addr, k;
DEVICE *dptr;
UNIT *uptr;
void int_handler (int signal);
GET_SWITCHES (cptr, gbuf); /* test for switches */
step = 0;
if (((flag == RU_RUN) || (flag == RU_GO)) && (*cptr != 0)) { /* run or go */
cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */
if ((r = dep_reg (0, gbuf, sim_PC)) != SCPE_OK) return r; }
if (flag == RU_STEP) { /* step */
if (*cptr == 0) step = 1;
else { cptr = get_glyph (cptr, gbuf, 0);
step = get_uint (gbuf, 10, INT_MAX, &r);
if ((r != SCPE_OK) || (step == 0)) return SCPE_ARG; } }
if (flag == RU_BOOT) { /* boot */
if (*cptr == 0) return SCPE_ARG;
cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */
if ((dptr = find_device (gbuf, &unitno)) == NULL) return SCPE_ARG;
if (dptr -> boot == NULL) return SCPE_ARG;
uptr = dptr -> units + unitno;
if (uptr -> flags & UNIT_DIS) return SCPE_ARG; /* disabled? */
if (!(uptr -> flags & UNIT_ATTABLE)) return SCPE_NOATT;
if (!(uptr -> flags & UNIT_ATT)) return SCPE_UNATT;
if ((r = dptr -> boot (unitno)) != SCPE_OK) return r; }
if (*cptr != 0) return SCPE_ARG;
if ((flag == RU_RUN) || (flag == RU_BOOT)) { /* run or boot */
#ifdef GAMEBOY
nlpos = 0;
#endif
sim_interval = 0; /* reset queue */
sim_time = 0;
noqueue_time = 0;
sim_clock_queue = NULL;
if ((r = reset_all (0)) != SCPE_OK) return r; }
#ifdef GAMEBOY
sim_devices[0]->identify();
printf("Devices: Probing UNIBUS ...\n");
printf(" ");
#endif
for (i = 1; (dptr = sim_devices[i]) != NULL; i++) {
#ifdef GAMEBOY
nlpos += printf("%s ", dptr->name);
if (nlpos >= 20) {
nlpos = 0;
printf("\n ");
}
#endif
for (j = 0; j < dptr -> numunits; j++) {
uptr = (dptr -> units) + j;
if ((uptr -> flags & (UNIT_ATT + UNIT_SEQ)) ==
(UNIT_ATT + UNIT_SEQ))
fseek (uptr -> fileref, uptr -> pos, SEEK_SET); } }
#ifdef GAMEBOY
printf("\nBootdev: RK05 2.5MB disk\n [t,h,s = 203,2,12]"
"\n\nLoading bootstrapper ...\n\n");
#endif
stop_cpu = 0;
if ((int) signal (SIGINT, int_handler) == -1) { /* set WRU */
printf ("Simulator interrupt handler setup failed\n");
return SCPE_OK; }
if (ttrunstate () != SCPE_OK) { /* set console */
ttcmdstate ();
printf ("Simulator terminal setup failed\n");
return SCPE_OK; }
if (step) sim_activate (&step_unit, step); /* set step timer */
r = sim_instr();
ttcmdstate (); /* restore console */
signal (SIGINT, SIG_DFL); /* cancel WRU */
sim_cancel (&step_unit); /* cancel step timer */
if (sim_clock_queue != NULL) { /* update sim time */
UPDATE_SIM_TIME (sim_clock_queue -> time); }
else { UPDATE_SIM_TIME (noqueue_time); }
#ifdef VMS
printf ("\n");
#endif
if (r >= SCPE_BASE) printf ("\n%s, %s: ", scp_error_messages[r - SCPE_BASE],
sim_PC -> name);
else printf ("\n%s, %s: ", sim_stop_messages[r], sim_PC -> name);
print_val (addr = get_rval (sim_PC, 0), sim_PC -> radix,
sim_PC -> width, sim_PC -> flags & REG_FMT);
if (((dptr = sim_devices[0]) != NULL) && (dptr -> examine != NULL)) {
for (i = 0; i < sim_emax; i++) sim_eval[i] = 0;
for (i = 0, k = addr; i < sim_emax; i++, k = k + dptr -> aincr) {
#ifdef GAMEBOY
if ((r = dptr -> examine (&sim_eval[i], k, dptr -> units,
SWMASK ('V'))) != SCPE_OK) break; }
#else
if (r = dptr -> examine (&sim_eval[i], k, dptr -> units,
SWMASK ('V')) != SCPE_OK) break; }
#endif
if ((r == SCPE_OK) || (i > 0)) {
printf (" (");
if (print_sym (addr, sim_eval, NULL, SWMASK('M')) > 0)
print_val (sim_eval[0], dptr -> dradix,
dptr -> dwidth, PV_RZRO);