-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathpdp11_cpu.c
2427 lines (2225 loc) · 74 KB
/
pdp11_cpu.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
/* pdp11_cpu.c: PDP-11 CPU simulator
Copyright (c) 1993-1998,
Robert M Supnik, Digital Equipment Corporation
Commercial use prohibited
18-Aug-98 RMS Added CIS support
09-May-98 RMS Fixed bug in DIV overflow test
19-Jan-97 RMS Added RP/RM support
06-Apr-96 RMS Added dynamic memory sizing
29-Feb-96 RMS Added TM11 support
17-Jul-94 RMS Corrected updating of MMR1 if MMR0 locked
The register state for the PDP-11 is:
REGFILE[0:5][0] general register set
REGFILE[0:5][1] alternate general register set
STACKFILE[4] stack pointers for kernel, supervisor, unused, user
PC program counter
PSW processor status word
<15:14> = CM current processor mode
<13:12> = PM previous processor mode
<11> = RS register set select
<7:5> = IPL interrupt priority level
<4> = TBIT trace trap enable
<3:0> = NZVC condition codes
FR[0:5] floating point accumulators
FPS floating point status register
FEC floating exception code
FEA floating exception address
MMR0,1,2,3 memory management control registers
APRFILE[0:63] memory management relocation registers for
kernel, supervisor, unused, user
<31:16> = PAR processor address registers
<15:0> = PDR processor data registers
PIRQ processor interrupt request register
CPUERR CPU error register
MEMERR memory system error register
CCR cache control register
MAINT maintenance register
HITMISS cache status register
SR switch register
DR display register
*/
/* The PDP-11 has many instruction formats:
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ double operand
| opcode | source spec | dest spec | 010000:067777
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 110000:167777
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ register + operand
| opcode | src reg| dest spec | 004000:004777
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 070000:077777
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ single operand
| opcode | dest spec | 000100:000177
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 000300:000377
005000:007777
105000:107777
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ single register
| opcode |dest reg| 000200:000207
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 000230:000237
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ no operand
| opcode | 000000:000007
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ branch
| opcode | branch displacement | 000400:003477
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 100000:103477
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ EMT/TRAP
| opcode | trap code | 104000:104777
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ cond code operator
| opcode | immediate | 000240:000277
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
An operand specifier consists of an addressing mode and a register.
The addressing modes are:
0 register direct R op = R
1 register deferred (R) op = M[R]
2 autoincrement (R)+ op = M[R]; R = R + length
3 autoincrement deferred @(R)+ op = M[M[R]]; R = R + 2
4 autodecrement -(R) R = R - length; op = M[R]
5 autodecrement deferred @-(R) R = R - 2; op = M[M[R]]
6 displacement d(R) op = M[R + disp]
7 displacement deferred @d(R) op = M[M[R + disp]]
There are eight general registers, R0-R7. R6 is the stack pointer,
R7 the PC. The combination of addressing modes with R7 yields:
27 immediate #n op = M[PC]; PC = PC + 2
37 absolute @#n op = M[M[PC]]; PC = PC + 2
67 relative d(PC) op = M[PC + disp]
77 relative deferred @d(PC) op = M[M[PC + disp]]
*/
/* This routine is the instruction decode routine for the PDP-11. It
is called from the simulator control program to execute instructions
in simulated memory, starting at the simulated PC. It runs until an
enabled exception is encountered.
General notes:
1. Virtual address format. PDP-11 memory management uses the 16b
virtual address, the type of reference (instruction or data), and
the current mode, to construct the 22b physical address. To
package this conveniently, the simulator uses a 19b pseudo virtual
address, consisting of the 16b virtual address prefixed with the
current mode and ispace/dspace indicator. These are precalculated
as isenable and dsenable for ispace and dspace, respectively, and
must be recalculated whenever MMR0, MMR3, or PSW<cm> changes.
2. Traps and interrupts. Variable trap_req bit-encodes all possible
traps. In addition, an interrupt pending bit is encoded as the
lowest priority trap. Traps are processed by trap_vec and trap_clear,
which provide the vector and subordinate traps to clear, respectively.
Variable int_req bit encodes all possible interrupts. It is masked
under the interrupt masks, int_mask[ipl]. If any interrupt request
is not masked, the interrupt bit is set in trap_req. While most
interrupts are handled centrally, a device can supply an interrupt
acknowledge routine.
3. PSW handling. The PSW is kept as components, for easier access.
Because the PSW can be explicitly written as address 17777776,
all instructions must update PSW before executing their last write.
4. Adding I/O devices. This requires modifications to three modules:
pdp11_defs.h add interrupt request definitions
pdp11_cpu.c add I/O page linkages
pdp11_sys.c add to sim_devices
*/
/* Definitions */
#include "pdp11_defs.h"
#ifdef GAMEBOY
#include "gba/gba_io.h"
#endif
#include <setjmp.h>
#define calc_is(md) ((md) << VA_V_MODE)
#define calc_ds(md) (calc_is((md)) | ((MMR3 & dsmask[(md)])? VA_DS: 0))
#define calc_MMR1(val) (MMR1 = MMR1? ((val) << 8) | MMR1: (val))
#define calc_ints(lv,rq,tr) (((rq) & int_mask[(lv)])? \
((tr) | TRAP_INT) : ((tr) & ~TRAP_INT))
#define GET_SIGN_W(v) ((v) >> 15)
#define GET_SIGN_B(v) ((v) >> 7)
#define GET_Z(v) ((v) == 0)
#define JMP_PC(x) old_PC = PC; PC = (x)
#define BRANCH_F(x) old_PC = PC; PC = (PC + (((x) + (x)) & 0377)) & 0177777
#define BRANCH_B(x) old_PC = PC; PC = (PC + (((x) + (x)) | 0177400)) & 0177777
#define ILL_ADR_FLAG 0200000
#define save_ibkpt (cpu_unit.u3) /* will be SAVEd */
#define last_pa (cpu_unit.u4) /* and RESTOREd */
#define UNIT_V_18B (UNIT_V_UF) /* force 18b addr */
#define UNIT_18B (1u << UNIT_V_18B)
#define UNIT_V_CIS (UNIT_V_UF + 1) /* CIS present */
#define UNIT_CIS (1u << UNIT_V_CIS)
#define UNIT_V_MSIZE (UNIT_V_UF + 2) /* dummy */
#define UNIT_MSIZE (1u << UNIT_V_MSIZE)
/* Global state */
unsigned int16 *M = NULL; /* address of memory */
#ifdef GAMEBOY
GBA_IWRAM_DATA int32 REGFILE[6][2] = { { 0 } }; /* R0-R5, two sets */
#else
int32 REGFILE[6][2] = { 0 }; /* R0-R5, two sets */
#endif
GBA_IWRAM_DATA int32 STACKFILE[4] = { 0 }; /* SP, four modes */
GBA_IWRAM_DATA int32 saved_PC = 0; /* program counter */
GBA_IWRAM_DATA int32 R[8] = { 0 }; /* working registers */
GBA_IWRAM_DATA int32 PSW = 0; /* PSW */
GBA_IWRAM_DATA int32 cm = 0; /* current mode */
GBA_IWRAM_DATA int32 pm = 0; /* previous mode */
GBA_IWRAM_DATA int32 rs = 0; /* register set */
GBA_IWRAM_DATA int32 ipl = 0; /* int pri level */
GBA_IWRAM_DATA int32 tbit = 0; /* trace flag */
GBA_IWRAM_DATA int32 N = 0; /* condition codes */
GBA_IWRAM_DATA int32 Z = 0; /* condition codes */
GBA_IWRAM_DATA int32 V = 0; /* condition codes */
GBA_IWRAM_DATA int32 C = 0; /* condition codes */
GBA_IWRAM_DATA int32 wait_state = 0; /* wait state */
GBA_IWRAM_DATA int32 trap_req = 0; /* trap requests */
GBA_IWRAM_DATA int32 int_req = 0; /* interrupt requests */
GBA_IWRAM_DATA int32 PIRQ = 0; /* programmed int req */
GBA_IWRAM_DATA int32 SR = 0; /* switch register */
GBA_IWRAM_DATA int32 DR = 0; /* display register */
#ifdef GAMEBOY
GBA_IWRAM_DATA fpac_t FR[6] = { { 0 } }; /* fp accumulators */
#else
fpac_t FR[6] = { 0 }; /* fp accumulators */
#endif
GBA_IWRAM_DATA int32 FPS = 0; /* fp status */
GBA_IWRAM_DATA int32 FEC = 0; /* fp exception code */
GBA_IWRAM_DATA int32 FEA = 0; /* fp exception addr */
GBA_IWRAM_DATA int32 APRFILE[64] = { 0 }; /* PARs/PDRs */
GBA_IWRAM_DATA int32 MMR0 = 0; /* MMR0 - status */
GBA_IWRAM_DATA int32 MMR1 = 0; /* MMR1 - R+/-R */
GBA_IWRAM_DATA int32 MMR2 = 0; /* MMR2 - saved PC */
GBA_IWRAM_DATA int32 MMR3 = 0; /* MMR3 - 22b status */
GBA_IWRAM_DATA int32 isenable = 0; /* i, d space flags */
GBA_IWRAM_DATA int32 dsenable = 0; /* i, d space flags */
GBA_IWRAM_DATA int32 CPUERR = 0; /* CPU error reg */
GBA_IWRAM_DATA int32 MEMERR = 0; /* memory error reg */
GBA_IWRAM_DATA int32 CCR = 0; /* cache control reg */
GBA_IWRAM_DATA int32 HITMISS = 0; /* hit/miss reg */
GBA_IWRAM_DATA int32 MAINT = (0 << 9) + (0 << 8) + (4 << 4);
/* maint bit<9> = Q/U */
/* <8> = hwre FP */
/* <6:4> = sys type */
GBA_IWRAM_DATA int32 stop_trap = 1; /* stop on trap */
GBA_IWRAM_DATA int32 stop_vecabort = 1; /* stop on vec abort */
GBA_IWRAM_DATA int32 stop_spabort = 1; /* stop on SP abort */
GBA_IWRAM_DATA int32 wait_enable = 0; /* wait state enable */
GBA_IWRAM_DATA int32 ibkpt_addr = ILL_ADR_FLAG | VAMASK;/* breakpoint addr */
GBA_IWRAM_DATA int32 old_PC = 0; /* previous PC */
jmp_buf save_env; /* abort handler */
GBA_IWRAM_DATA int32 dsmask[4] = { MMR3_KDS, MMR3_SDS, 0, MMR3_UDS };
/* dspace enables */
GBA_IWRAM_DATA int32 int_mask[8] = { /* interrupt masks */
INT_IPL0,
INT_IPL1,
INT_IPL2,
INT_IPL3,
INT_IPL4,
INT_IPL5,
INT_IPL6,
INT_IPL7
};
extern int32 sim_int_char;
/* Function declarations */
t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
t_stat cpu_reset (DEVICE *dptr);
#ifdef GAMEBOY
t_stat cpu_identify();
#endif
t_stat cpu_svc (UNIT *uptr);
t_stat cpu_set_size (UNIT *uptr, int32 value);
int32 GeteaB (int32 spec);
int32 GeteaW (int32 spec);
int32 relocR (int32 addr);
int32 relocW (int32 addr);
int32 ReadW (int32 addr);
int32 ReadB (int32 addr);
int32 ReadMW (int32 addr);
int32 ReadMB (int32 addr);
void WriteW (int32 data, int32 addr);
void WriteB (int32 data, int32 addr);
void PWriteW (int32 data, int32 addr);
void PWriteB (int32 data, int32 addr);
t_stat iopageR (int32 *data, int32 addr, int32 access);
t_stat iopageW (int32 data, int32 addr, int32 access);
t_stat CPU_rd (int32 *data, int32 addr, int32 access);
t_stat CPU_wr (int32 data, int32 addr, int32 access);
t_stat APR_rd (int32 *data, int32 addr, int32 access);
t_stat APR_wr (int32 data, int32 addr, int32 access);
t_stat SR_MMR012_rd (int32 *data, int32 addr, int32 access);
t_stat SR_MMR012_wr (int32 data, int32 addr, int32 access);
t_stat MMR3_rd (int32 *data, int32 addr, int32 access);
t_stat MMR3_wr (int32 data, int32 addr, int32 access);
extern t_stat std_rd (int32 *data, int32 addr, int32 access);
extern t_stat std_wr (int32 data, int32 addr, int32 access);
extern t_stat lpt_rd (int32 *data, int32 addr, int32 access);
extern t_stat lpt_wr (int32 data, int32 addr, int32 access);
extern t_stat rk_rd (int32 *data, int32 addr, int32 access);
extern t_stat rk_wr (int32 data, int32 addr, int32 access);
extern int32 rk_inta (void);
extern t_stat rl_rd (int32 *data, int32 addr, int32 access);
extern t_stat rl_wr (int32 data, int32 addr, int32 access);
extern t_stat rp_rd (int32 *data, int32 addr, int32 access);
extern t_stat rp_wr (int32 data, int32 addr, int32 access);
extern int32 rp_inta (void);
extern t_stat rx_rd (int32 *data, int32 addr, int32 access);
extern t_stat rx_wr (int32 data, int32 addr, int32 access);
extern t_stat tm_rd (int32 *data, int32 addr, int32 access);
extern t_stat tm_wr (int32 data, int32 addr, int32 access);
extern t_stat sim_activate (UNIT *uptr, int32 delay);
/* Auxiliary data structures */
struct iolink { /* I/O page linkage */
int32 low; /* low I/O addr */
int32 high; /* high I/O addr */
t_stat (*read)(); /* read routine */
t_stat (*write)(); }; /* write routine */
struct iolink iotable[] = {
{ 017777740, 017777777, &CPU_rd, &CPU_wr },
{ 017777546, 017777567, &std_rd, &std_wr },
{ 017777514, 017777517, &lpt_rd, &lpt_wr },
{ 017777400, 017777417, &rk_rd, &rk_wr },
{ 017774400, 017774411, &rl_rd, &rl_wr },
{ 017776700, 017776753, &rp_rd, &rp_wr },
{ 017777170, 017777173, &rx_rd, &rx_wr },
{ 017772520, 017772533, &tm_rd, &tm_wr },
{ 017777600, 017777677, &APR_rd, &APR_wr },
{ 017772200, 017772377, &APR_rd, &APR_wr },
{ 017777570, 017777577, &SR_MMR012_rd, &SR_MMR012_wr },
{ 017772516, 017772517, &MMR3_rd, &MMR3_wr },
{ 0, 0, NULL } };
int32 int_vec[32] = { /* int req to vector */
0, 0, 0, VEC_PIRQ, VEC_CLK, 0, 0, VEC_PIRQ,
VEC_RK, VEC_RL, VEC_RX, VEC_TM, VEC_RP, 0, 0, VEC_PIRQ,
VEC_TTI, VEC_TTO, VEC_PTR, VEC_PTP, VEC_LPT, 0, 0, 0,
0, 0, 0, 0, VEC_PIRQ, VEC_PIRQ, VEC_PIRQ, VEC_PIRQ };
int32 (*int_ack[32])() = { /* int ack routines */
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
&rk_inta, NULL, NULL, NULL, &rp_inta, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
int32 trap_vec[TRAP_V_MAX] = { /* trap req to vector */
VEC_RED, VEC_ODD, VEC_MME, VEC_NXM,
VEC_PAR, VEC_PRV, VEC_ILL, VEC_BPT,
VEC_IOT, VEC_EMT, VEC_TRAP, VEC_TRC,
VEC_YEL, VEC_PWRFL, VEC_FPE };
int32 trap_clear[TRAP_V_MAX] = { /* trap clears */
TRAP_RED+TRAP_PAR+TRAP_YEL+TRAP_TRC,
TRAP_ODD+TRAP_PAR+TRAP_YEL+TRAP_TRC,
TRAP_MME+TRAP_PAR+TRAP_YEL+TRAP_TRC,
TRAP_NXM+TRAP_PAR+TRAP_YEL+TRAP_TRC,
TRAP_PAR+TRAP_TRC, TRAP_PRV+TRAP_TRC,
TRAP_ILL+TRAP_TRC, TRAP_BPT+TRAP_TRC,
TRAP_IOT+TRAP_TRC, TRAP_EMT+TRAP_TRC,
TRAP_TRAP+TRAP_TRC, TRAP_TRC,
TRAP_YEL, TRAP_PWRFL, TRAP_FPE };
/* CPU data structures
cpu_dev CPU device descriptor
cpu_unit CPU unit descriptor
cpu_reg CPU register list
cpu_mod CPU modifier list
*/
UNIT cpu_unit = { UDATA (&cpu_svc, UNIT_FIX + UNIT_BINK, INIMEMSIZE) };
REG cpu_reg[] = {
{ ORDATA (PC, saved_PC, 16) },
{ ORDATA (R0, REGFILE[0][0], 16) },
{ ORDATA (R1, REGFILE[1][0], 16) },
{ ORDATA (R2, REGFILE[2][0], 16) },
{ ORDATA (R3, REGFILE[3][0], 16) },
{ ORDATA (R4, REGFILE[4][0], 16) },
{ ORDATA (R5, REGFILE[5][0], 16) },
{ ORDATA (R10, REGFILE[0][1], 16) },
{ ORDATA (R11, REGFILE[1][1], 16) },
{ ORDATA (R12, REGFILE[2][1], 16) },
{ ORDATA (R13, REGFILE[3][1], 16) },
{ ORDATA (R14, REGFILE[4][1], 16) },
{ ORDATA (R15, REGFILE[5][1], 16) },
{ ORDATA (KSP, STACKFILE[KERNEL], 16) },
{ ORDATA (SSP, STACKFILE[SUPER], 16) },
{ ORDATA (USP, STACKFILE[USER], 16) },
{ ORDATA (PSW, PSW, 16) },
{ GRDATA (CM, PSW, 8, 2, PSW_V_CM) },
{ GRDATA (PM, PSW, 8, 2, PSW_V_PM) },
{ FLDATA (RS, PSW, PSW_V_RS) },
{ GRDATA (IPL, PSW, 8, 3, PSW_V_IPL) },
{ FLDATA (T, PSW, PSW_V_TBIT) },
{ FLDATA (N, PSW, PSW_V_N) },
{ FLDATA (Z, PSW, PSW_V_Z) },
{ FLDATA (V, PSW, PSW_V_V) },
{ FLDATA (C, PSW, PSW_V_C) },
{ ORDATA (SR, SR, 16) },
{ ORDATA (DR, DR, 16) },
{ ORDATA (MEMERR, MEMERR, 16) },
{ ORDATA (CCR, CCR, 16) },
{ ORDATA (MAINT, MAINT, 16) },
{ ORDATA (HITMISS, HITMISS, 16) },
{ ORDATA (CPUERR, CPUERR, 16) },
{ ORDATA (INT, int_req, 32), REG_RO },
{ ORDATA (TRAPS, trap_req, TRAP_V_MAX) },
{ ORDATA (PIRQ, PIRQ, 16) },
{ FLDATA (WAIT, wait_state, 0) },
{ FLDATA (WAIT_ENABLE, wait_enable, 0) },
{ ORDATA (STOP_TRAPS, stop_trap, TRAP_V_MAX) },
{ FLDATA (STOP_VECA, stop_vecabort, 0) },
{ FLDATA (STOP_SPA, stop_spabort, 0) },
{ ORDATA (FAC0H, FR[0].h, 32) },
{ ORDATA (FAC0L, FR[0].l, 32) },
{ ORDATA (FAC1H, FR[1].h, 32) },
{ ORDATA (FAC1L, FR[1].l, 32) },
{ ORDATA (FAC2H, FR[2].h, 32) },
{ ORDATA (FAC2L, FR[2].l, 32) },
{ ORDATA (FAC3H, FR[3].h, 32) },
{ ORDATA (FAC3L, FR[3].l, 32) },
{ ORDATA (FAC4H, FR[4].h, 32) },
{ ORDATA (FAC4L, FR[4].l, 32) },
{ ORDATA (FAC5H, FR[5].h, 32) },
{ ORDATA (FAC5L, FR[5].l, 32) },
{ ORDATA (FPS, FPS, 16) },
{ ORDATA (FEA, FEA, 16) },
{ ORDATA (FEC, FEC, 4) },
{ ORDATA (MMR0, MMR0, 16) },
{ ORDATA (MMR1, MMR1, 16) },
{ ORDATA (MMR2, MMR2, 16) },
{ ORDATA (MMR3, MMR3, 16) },
{ GRDATA (KIPAR0, APRFILE[000], 8, 16, 16) },
{ GRDATA (KIPDR0, APRFILE[000], 8, 16, 0) },
{ GRDATA (KIPAR1, APRFILE[001], 8, 16, 16) },
{ GRDATA (KIPDR1, APRFILE[001], 8, 16, 0) },
{ GRDATA (KIPAR2, APRFILE[002], 8, 16, 16) },
{ GRDATA (KIPDR2, APRFILE[002], 8, 16, 0) },
{ GRDATA (KIPAR3, APRFILE[003], 8, 16, 16) },
{ GRDATA (KIPDR3, APRFILE[003], 8, 16, 0) },
{ GRDATA (KIPAR4, APRFILE[004], 8, 16, 16) },
{ GRDATA (KIPDR4, APRFILE[004], 8, 16, 0) },
{ GRDATA (KIPAR5, APRFILE[005], 8, 16, 16) },
{ GRDATA (KIPDR5, APRFILE[005], 8, 16, 0) },
{ GRDATA (KIPAR6, APRFILE[006], 8, 16, 16) },
{ GRDATA (KIPDR6, APRFILE[006], 8, 16, 0) },
{ GRDATA (KIPAR7, APRFILE[007], 8, 16, 16) },
{ GRDATA (KIPDR7, APRFILE[007], 8, 16, 0) },
{ GRDATA (KDPAR0, APRFILE[010], 8, 16, 16) },
{ GRDATA (KDPDR0, APRFILE[010], 8, 16, 0) },
{ GRDATA (KDPAR1, APRFILE[011], 8, 16, 16) },
{ GRDATA (KDPDR1, APRFILE[011], 8, 16, 0) },
{ GRDATA (KDPAR2, APRFILE[012], 8, 16, 16) },
{ GRDATA (KDPDR2, APRFILE[012], 8, 16, 0) },
{ GRDATA (KDPAR3, APRFILE[013], 8, 16, 16) },
{ GRDATA (KDPDR3, APRFILE[013], 8, 16, 0) },
{ GRDATA (KDPAR4, APRFILE[014], 8, 16, 16) },
{ GRDATA (KDPDR4, APRFILE[014], 8, 16, 0) },
{ GRDATA (KDPAR5, APRFILE[015], 8, 16, 16) },
{ GRDATA (KDPDR5, APRFILE[015], 8, 16, 0) },
{ GRDATA (KDPAR6, APRFILE[016], 8, 16, 16) },
{ GRDATA (KDPDR6, APRFILE[016], 8, 16, 0) },
{ GRDATA (KDPAR7, APRFILE[017], 8, 16, 16) },
{ GRDATA (KDPDR7, APRFILE[017], 8, 16, 0) },
{ GRDATA (SIPAR0, APRFILE[020], 8, 16, 16) },
{ GRDATA (SIPDR0, APRFILE[020], 8, 16, 0) },
{ GRDATA (SIPAR1, APRFILE[021], 8, 16, 16) },
{ GRDATA (SIPDR1, APRFILE[021], 8, 16, 0) },
{ GRDATA (SIPAR2, APRFILE[022], 8, 16, 16) },
{ GRDATA (SIPDR2, APRFILE[022], 8, 16, 0) },
{ GRDATA (SIPAR3, APRFILE[023], 8, 16, 16) },
{ GRDATA (SIPDR3, APRFILE[023], 8, 16, 0) },
{ GRDATA (SIPAR4, APRFILE[024], 8, 16, 16) },
{ GRDATA (SIPDR4, APRFILE[024], 8, 16, 0) },
{ GRDATA (SIPAR5, APRFILE[025], 8, 16, 16) },
{ GRDATA (SIPDR5, APRFILE[025], 8, 16, 0) },
{ GRDATA (SIPAR6, APRFILE[026], 8, 16, 16) },
{ GRDATA (SIPDR6, APRFILE[026], 8, 16, 0) },
{ GRDATA (SIPAR7, APRFILE[027], 8, 16, 16) },
{ GRDATA (SIPDR7, APRFILE[027], 8, 16, 0) },
{ GRDATA (SDPAR0, APRFILE[030], 8, 16, 16) },
{ GRDATA (SDPDR0, APRFILE[030], 8, 16, 0) },
{ GRDATA (SDPAR1, APRFILE[031], 8, 16, 16) },
{ GRDATA (SDPDR1, APRFILE[031], 8, 16, 0) },
{ GRDATA (SDPAR2, APRFILE[032], 8, 16, 16) },
{ GRDATA (SDPDR2, APRFILE[032], 8, 16, 0) },
{ GRDATA (SDPAR3, APRFILE[033], 8, 16, 16) },
{ GRDATA (SDPDR3, APRFILE[033], 8, 16, 0) },
{ GRDATA (SDPAR4, APRFILE[034], 8, 16, 16) },
{ GRDATA (SDPDR4, APRFILE[034], 8, 16, 0) },
{ GRDATA (SDPAR5, APRFILE[035], 8, 16, 16) },
{ GRDATA (SDPDR5, APRFILE[035], 8, 16, 0) },
{ GRDATA (SDPAR6, APRFILE[036], 8, 16, 16) },
{ GRDATA (SDPDR6, APRFILE[036], 8, 16, 0) },
{ GRDATA (SDPAR7, APRFILE[037], 8, 16, 16) },
{ GRDATA (SDPDR7, APRFILE[037], 8, 16, 0) },
{ GRDATA (UIPAR0, APRFILE[060], 8, 16, 16) },
{ GRDATA (UIPDR0, APRFILE[060], 8, 16, 0) },
{ GRDATA (UIPAR1, APRFILE[061], 8, 16, 16) },
{ GRDATA (UIPDR1, APRFILE[061], 8, 16, 0) },
{ GRDATA (UIPAR2, APRFILE[062], 8, 16, 16) },
{ GRDATA (UIPDR2, APRFILE[062], 8, 16, 0) },
{ GRDATA (UIPAR3, APRFILE[063], 8, 16, 16) },
{ GRDATA (UIPDR3, APRFILE[063], 8, 16, 0) },
{ GRDATA (UIPAR4, APRFILE[064], 8, 16, 16) },
{ GRDATA (UIPDR4, APRFILE[064], 8, 16, 0) },
{ GRDATA (UIPAR5, APRFILE[065], 8, 16, 16) },
{ GRDATA (UIPDR5, APRFILE[065], 8, 16, 0) },
{ GRDATA (UIPAR6, APRFILE[066], 8, 16, 16) },
{ GRDATA (UIPDR6, APRFILE[066], 8, 16, 0) },
{ GRDATA (UIPAR7, APRFILE[067], 8, 16, 16) },
{ GRDATA (UIPDR7, APRFILE[067], 8, 16, 0) },
{ GRDATA (UDPAR0, APRFILE[070], 8, 16, 16) },
{ GRDATA (UDPDR0, APRFILE[070], 8, 16, 0) },
{ GRDATA (UDPAR1, APRFILE[071], 8, 16, 16) },
{ GRDATA (UDPDR1, APRFILE[071], 8, 16, 0) },
{ GRDATA (UDPAR2, APRFILE[072], 8, 16, 16) },
{ GRDATA (UDPDR2, APRFILE[072], 8, 16, 0) },
{ GRDATA (UDPAR3, APRFILE[073], 8, 16, 16) },
{ GRDATA (UDPDR3, APRFILE[073], 8, 16, 0) },
{ GRDATA (UDPAR4, APRFILE[074], 8, 16, 16) },
{ GRDATA (UDPDR4, APRFILE[074], 8, 16, 0) },
{ GRDATA (UDPAR5, APRFILE[075], 8, 16, 16) },
{ GRDATA (UDPDR5, APRFILE[075], 8, 16, 0) },
{ GRDATA (UDPAR6, APRFILE[076], 8, 16, 16) },
{ GRDATA (UDPDR6, APRFILE[076], 8, 16, 0) },
{ GRDATA (UDPAR7, APRFILE[077], 8, 16, 16) },
{ GRDATA (UDPDR7, APRFILE[077], 8, 16, 0) },
{ FLDATA (18B_ADDR, cpu_unit.flags, UNIT_V_18B), REG_HRO },
{ FLDATA (CIS, cpu_unit.flags, UNIT_V_CIS), REG_HRO },
{ ORDATA (OLDPC, old_PC, 16), REG_RO },
{ ORDATA (BREAK, ibkpt_addr, 17) },
{ ORDATA (WRU, sim_int_char, 8) },
{ NULL} };
MTAB cpu_mod[] = {
{ UNIT_18B, UNIT_18B, "18b addressing", "18B", NULL },
{ UNIT_18B, 0, NULL, "22B", NULL },
{ UNIT_CIS, UNIT_CIS, "CIS", "CIS", NULL },
{ UNIT_CIS, 0, "No CIS", "NOCIS", NULL },
{ UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size},
{ UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size},
{ UNIT_MSIZE, 49152, NULL, "48K", &cpu_set_size},
{ UNIT_MSIZE, 65536, NULL, "64K", &cpu_set_size},
{ UNIT_MSIZE, 98304, NULL, "96K", &cpu_set_size},
{ UNIT_MSIZE, 131072, NULL, "128K", &cpu_set_size},
{ UNIT_MSIZE, 229376, NULL, "192K", &cpu_set_size},
{ UNIT_MSIZE, 262144, NULL, "256K", &cpu_set_size},
{ UNIT_MSIZE, 393216, NULL, "384K", &cpu_set_size},
{ UNIT_MSIZE, 524288, NULL, "512K", &cpu_set_size},
{ UNIT_MSIZE, 786432, NULL, "768K", &cpu_set_size},
{ UNIT_MSIZE, 1048576, NULL, "1024K", &cpu_set_size},
{ UNIT_MSIZE, 2097152, NULL, "2048K", &cpu_set_size},
{ UNIT_MSIZE, 3145728, NULL, "3072K", &cpu_set_size},
{ UNIT_MSIZE, 4194304, NULL, "4096K", &cpu_set_size},
{ UNIT_MSIZE, 1048576, NULL, "1M", &cpu_set_size},
{ UNIT_MSIZE, 2097152, NULL, "2M", &cpu_set_size},
{ UNIT_MSIZE, 3145728, NULL, "3M", &cpu_set_size},
{ UNIT_MSIZE, 4194304, NULL, "4M", &cpu_set_size},
{ 0 } };
DEVICE cpu_dev = {
"CPU", &cpu_unit, cpu_reg, cpu_mod,
1, 8, 22, 2, 8, 16,
&cpu_ex, &cpu_dep, &cpu_reset,
#ifdef GAMEBOY
NULL, NULL, NULL, &cpu_identify };
#else
NULL, NULL, NULL };
#endif
t_stat sim_instr (void)
{
extern int32 sim_interval;
extern UNIT *sim_clock_queue;
register int32 IR, srcspec, srcreg, dstspec, dstreg;
register int32 src, src2, dst;
#ifdef GAMEBOY
register int32 i, t, sign, oldrs, trapnum = 0;
#else
register int32 i, t, sign, oldrs, trapnum;
#endif
int32 abortval;
volatile int32 trapea;
t_stat reason;
void fp11 (int32 IR);
#ifndef GAMEBOY
void cis11 (int32 IR);
#endif
/* Restore register state
1. PSW components
2. Active register file based on PSW<rs>
3. Active stack pointer based on PSW<cm>
4. Memory management control flags
5. Interrupt system
*/
cm = (PSW >> PSW_V_CM) & 03; /* call calc_is,ds */
pm = (PSW >> PSW_V_PM) & 03;
rs = (PSW >> PSW_V_RS) & 01;
ipl = (PSW >> PSW_V_IPL) & 07; /* call calc_ints */
tbit = (PSW >> PSW_V_TBIT) & 01;
N = (PSW >> PSW_V_N) & 01;
Z = (PSW >> PSW_V_Z) & 01;
V = (PSW >> PSW_V_V) & 01;
C = (PSW >> PSW_V_C) & 01;
for (i = 0; i < 6; i++) R[i] = REGFILE[i][rs];
SP = STACKFILE[cm];
PC = saved_PC;
isenable = calc_is (cm);
dsenable = calc_ds (cm);
CPU_wr (PIRQ, 017777772, WRITE); /* rewrite PIRQ */
trap_req = calc_ints (ipl, int_req, trap_req);
trapea = 0;
reason = 0;
/* Abort handling
If an abort occurs in memory management or memory access, the lower
level routine executes a longjmp to this area OUTSIDE the main
simulation loop. The longjmp specifies a trap mask which is OR'd
into the trap_req register. Simulation then resumes at the fetch
phase, and the trap is sprung.
Aborts which occur within a trap sequence (trapea != 0) require
special handling. If the abort occured on the stack pushes, and
the mode (encoded in trapea) is kernel, an "emergency" kernel
stack is created at 4, and a red zone stack trap taken.
*/
abortval = setjmp (save_env); /* set abort hdlr */
if (abortval != 0) {
trap_req = trap_req | abortval; /* or in trap flag */
if ((trapea > 0) && (stop_vecabort)) reason = STOP_VECABORT;
if ((trapea < 0) && (stop_spabort)) reason = STOP_SPABORT;
if (trapea == ~KERNEL) { /* kernel stk abort? */
setTRAP (TRAP_RED);
setCPUERR (CPUE_RED);
STACKFILE[KERNEL] = 4;
if (cm == KERNEL) SP = 4; } }
/* Main instruction fetch/decode loop
Check for traps or interrupts. If trap, locate the vector and check
for stop condition. If interrupt, locate the vector.
*/
while (reason == 0) {
if (sim_interval <= 0) { /* check clock queue */
reason = sim_process_event ();
trap_req = calc_ints (ipl, int_req, trap_req);
continue; }
if (trap_req) { /* check traps, ints */
trapea = 0; /* assume srch fails */
#ifdef GAMEBOY
if ((t = trap_req & TRAP_ALL)) { /* if a trap */
#else
if (t = trap_req & TRAP_ALL) { /* if a trap */
#endif
for (trapnum = 0; trapnum < TRAP_V_MAX; trapnum++) {
if ((t >> trapnum) & 1) {
trapea = trap_vec[trapnum];
trap_req = trap_req & ~trap_clear[trapnum];
if ((stop_trap >> trapnum) & 1)
reason = trapnum + 1;
break; } } }
#ifdef GAMEBOY
else if ((t = int_req & int_mask[ipl])) { /* if an interrupt */
#else
else if (t = int_req & int_mask[ipl]) { /* if an interrupt */
#endif
for (i = 0; i < 32; i++) {
if ((t >> i) & 1) {
int_req = int_req & ~(1u << i);
if (int_ack[i]) trapea = int_ack[i]();
else trapea = int_vec[i];
trapnum = TRAP_V_MAX;
break; } } }
if (trapea == 0) { /* nothing to do? */
trap_req = calc_ints (ipl, int_req, 0); /* recalculate */
continue; } /* back to fetch */
/* Process a trap or interrupt
1. Exit wait state
2. Save the current SP and PSW
3. Read the new PC, new PSW from trapea, kernel data space
4. Get the mode and stack selected by the new PSW
5. Push the old PC and PSW on the new stack
6. Update SP, PSW, and PC
7. If not stack overflow, check for stack overflow
*/
wait_state = 0; /* exit wait state */
STACKFILE[cm] = SP;
PSW = (cm << PSW_V_CM) | (pm << PSW_V_PM) | (rs << PSW_V_RS) |
(ipl << PSW_V_IPL) | (tbit << PSW_V_TBIT) |
(N << PSW_V_N) | (Z << PSW_V_Z) |
(V << PSW_V_V) | (C << PSW_V_C);
oldrs = rs;
src = ReadW (trapea | calc_ds (KERNEL));
src2 = ReadW ((trapea + 2) | calc_ds (KERNEL));
t = (src2 >> PSW_V_CM) & 03;
trapea = ~t; /* flag pushes */
WriteW (PSW, ((STACKFILE[t] - 2) & 0177777) | calc_ds (t));
WriteW (PC, ((STACKFILE[t] - 4) & 0177777) | calc_ds (t));
trapea = 0; /* clear trap flag */
pm = cm;
cm = t; /* call calc_is,ds */
rs = (src2 >> PSW_V_RS) & 01;
ipl = (src2 >> PSW_V_IPL) & 07; /* call calc_ints */
tbit = (src2 >> PSW_V_TBIT) & 01;
N = (src2 >> PSW_V_N) & 01;
Z = (src2 >> PSW_V_Z) & 01;
V = (src2 >> PSW_V_V) & 01;
C = (src2 >> PSW_V_C) & 01;
if (rs != oldrs) { /* if rs chg, swap */
for (i = 0; i < 6; i++) {
REGFILE[i][oldrs] = R[i];
R[i] = REGFILE[i][rs]; } }
SP = (STACKFILE[cm] - 4) & 0177777; /* update SP, PC */
JMP_PC (src);
isenable = calc_is (cm);
dsenable = calc_ds (cm);
trap_req = calc_ints (ipl, int_req, trap_req);
if ((SP < STKLIM) && (cm == KERNEL) &&
(trapnum != TRAP_V_RED) && (trapnum != TRAP_V_YEL)) {
setTRAP (TRAP_YEL);
setCPUERR (CPUE_YEL); }
continue; } /* end if traps */
/* Fetch and decode next instruction */
if (tbit) setTRAP (TRAP_TRC);
if (wait_state) { /* wait state? */
if (sim_clock_queue != NULL) sim_interval = 0; /* force check */
else reason = STOP_WAIT;
continue; }
if (PC == ibkpt_addr) { /* breakpoint? */
save_ibkpt = ibkpt_addr; /* save bkpt */
ibkpt_addr = ibkpt_addr | ILL_ADR_FLAG; /* disable */
sim_activate (&cpu_unit, 1); /* sched re-enable */
reason = STOP_IBKPT; /* stop simulation */
continue; }
if (update_MM) { /* if mm not frozen */
MMR1 = 0;
MMR2 = PC; }
IR = ReadW (PC | isenable); /* fetch instruction */
PC = (PC + 2) & 0177777; /* incr PC, mod 65k */
sim_interval = sim_interval - 1;
srcspec = (IR >> 6) & 077; /* src, dst specs */
dstspec = IR & 077;
srcreg = (srcspec <= 07); /* src, dst = rmode? */
dstreg = (dstspec <= 07);
switch ((IR >> 12) & 017) { /* decode IR<15:12> */
/* Opcode 0: no operands, specials, branches, JSR, SOPs */
case 000:
switch ((IR >> 6) & 077) { /* decode IR<11:6> */
case 000: /* no operand */
if (IR > 000010) { /* 000010 - 000077 */
setTRAP (TRAP_ILL); /* illegal */
break; }
switch (IR) { /* decode IR<2:0> */
case 0: /* HALT */
if (cm == KERNEL) reason = STOP_HALT;
else { setTRAP (TRAP_PRV);
setCPUERR (CPUE_HALT); }
break;
case 1: /* WAIT */
if (cm == KERNEL && wait_enable) wait_state = 1;
break;
case 3: /* BPT */
setTRAP (TRAP_BPT);
break;
case 4: /* IOT */
setTRAP (TRAP_IOT);
break;
case 5: /* RESET */
if (cm == KERNEL) {
reset_all (1);
PIRQ = 0;
int_req = 0;
MMR0 = MMR0 & ~(MMR0_MME | MMR0_FREEZE);
MMR3 = 0;
trap_req = trap_req & ~TRAP_INT;
dsenable = calc_ds (cm); }
break;
/* Opcode 0: specials, continued */
case 2: /* RTI */
case 6: /* RTT */
src = ReadW (SP | dsenable);
src2 = ReadW (((SP + 2) & 0177777) | dsenable);
STACKFILE[cm] = SP = (SP + 4) & 0177777;
oldrs = rs;
if (cm == KERNEL) {
cm = (src2 >> PSW_V_CM) & 03;
pm = (src2 >> PSW_V_PM) & 03;
rs = (src2 >> PSW_V_RS) & 01;
ipl = (src2 >> PSW_V_IPL) & 07; }
else { cm = cm | ((src2 >> PSW_V_CM) & 03);
pm = pm | ((src2 >> PSW_V_PM) & 03);
rs = rs | ((src2 >> PSW_V_RS) & 01); }
tbit = (src2 >> PSW_V_TBIT) & 01;
N = (src2 >> PSW_V_N) & 01;
Z = (src2 >> PSW_V_Z) & 01;
V = (src2 >> PSW_V_V) & 01;
C = (src2 >> PSW_V_C) & 01;
trap_req = calc_ints (ipl, int_req, trap_req);
isenable = calc_is (cm);
dsenable = calc_ds (cm);
if (rs != oldrs) {
for (i = 0; i < 6; i++) {
REGFILE[i][oldrs] = R[i];
R[i] = REGFILE[i][rs]; } }
SP = STACKFILE[cm];
JMP_PC (src);
if ((IR == 000002) && tbit) setTRAP (TRAP_TRC);
break;
case 7: /* MFPT */
R[0] = 5; /* report J-11 */
break; } /* end switch no ops */
break; /* end case no ops */
/* Opcode 0: specials, continued */
case 001: /* JMP */
if (dstreg) setTRAP (TRAP_ILL);
else { JMP_PC (GeteaW (dstspec) & 0177777); }
break; /* end JMP */
case 002: /* RTS et al*/
if (IR < 000210) { /* RTS */
dstspec = dstspec & 07;
JMP_PC (R[dstspec]);
R[dstspec] = ReadW (SP | dsenable);
SP = (SP + 2) & 0177777;
break; } /* end if RTS */
if (IR < 000230) {
setTRAP (TRAP_ILL);
break; }
if (IR < 000240) { /* SPL */
if (cm == KERNEL) ipl = IR & 07;
trap_req = calc_ints (ipl, int_req, trap_req);
break; } /* end if SPL */
if (IR < 000260) { /* clear CC */
if (IR & 010) N = 0;
if (IR & 004) Z = 0;
if (IR & 002) V = 0;
if (IR & 001) C = 0;
break; } /* end if clear CCs */
if (IR & 010) N = 1; /* set CC */
if (IR & 004) Z = 1;
if (IR & 002) V = 1;
if (IR & 001) C = 1;
break; /* end case RTS et al */
case 003: /* SWAB */
dst = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec));
dst = ((dst & 0377) << 8) | ((dst >> 8) & 0377);
N = GET_SIGN_B (dst & 0377);
Z = GET_Z (dst & 0377);
V = C = 0;
if (dstreg) R[dstspec] = dst;
else PWriteW (dst, last_pa);
break; /* end SWAB */
/* Opcode 0: branches, JSR */
case 004: case 005: /* BR */
BRANCH_F (IR);
break;
case 006: case 007: /* BR */
BRANCH_B (IR);
break;
case 010: case 011: /* BNE */
if (Z == 0) { BRANCH_F (IR); }
break;
case 012: case 013: /* BNE */
if (Z == 0) { BRANCH_B (IR); }
break;
case 014: case 015: /* BEQ */
if (Z) { BRANCH_F (IR); }
break;
case 016: case 017: /* BEQ */
if (Z) { BRANCH_B (IR); }
break;
case 020: case 021: /* BGE */
if ((N ^ V) == 0) { BRANCH_F (IR); }
break;
case 022: case 023: /* BGE */
if ((N ^ V) == 0) { BRANCH_B (IR); }
break;
case 024: case 025: /* BLT */
if (N ^ V) { BRANCH_F (IR); }
break;
case 026: case 027: /* BLT */
if (N ^ V) { BRANCH_B (IR); }
break;
case 030: case 031: /* BGT */
if ((Z | (N ^ V)) == 0) { BRANCH_F (IR); }
break;
case 032: case 033: /* BGT */
if ((Z | (N ^ V)) == 0) { BRANCH_B (IR); }
break;
case 034: case 035: /* BLE */
if (Z | (N ^ V)) { BRANCH_F (IR); }
break;
case 036: case 037: /* BLE */
if (Z | (N ^ V)) { BRANCH_B (IR); }
break;
case 040: case 041: case 042: case 043: /* JSR */
case 044: case 045: case 046: case 047:
if (dstreg) setTRAP (TRAP_ILL);
else { srcspec = srcspec & 07;
dst = GeteaW (dstspec);
SP = (SP - 2) & 0177777;
if (update_MM) MMR1 = calc_MMR1 (0366);
WriteW (R[srcspec], SP | dsenable);
if ((SP < STKLIM) && (cm == KERNEL)) {
setTRAP (TRAP_YEL);
setCPUERR (CPUE_YEL); }
R[srcspec] = PC;
JMP_PC (dst & 0177777); }
break; /* end JSR */
/* Opcode 0: SOPs */
case 050: /* CLR */
N = V = C = 0;
Z = 1;
if (dstreg) R[dstspec] = 0;
else WriteW (0, GeteaW (dstspec));
break;
case 051: /* COM */
dst = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec));
dst = dst ^ 0177777;
N = GET_SIGN_W (dst);
Z = GET_Z (dst);
V = 0;
C = 1;
if (dstreg) R[dstspec] = dst;
else PWriteW (dst, last_pa);
break;
case 052: /* INC */
dst = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec));
dst = (dst + 1) & 0177777;
N = GET_SIGN_W (dst);
Z = GET_Z (dst);
V = (dst == 0100000);
if (dstreg) R[dstspec] = dst;
else PWriteW (dst, last_pa);
break;
case 053: /* DEC */
dst = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec));
dst = (dst - 1) & 0177777;
N = GET_SIGN_W (dst);
Z = GET_Z (dst);
V = (dst == 077777);
if (dstreg) R[dstspec] = dst;
else PWriteW (dst, last_pa);
break;
case 054: /* NEG */
dst = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec));
dst = (-dst) & 0177777;
N = GET_SIGN_W (dst);
Z = GET_Z (dst);
V = (dst == 0100000);
C = Z ^ 1;
if (dstreg) R[dstspec] = dst;
else PWriteW (dst, last_pa);
break;
case 055: /* ADC */
dst = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec));
dst = (dst + C) & 0177777;
N = GET_SIGN_W (dst);
Z = GET_Z (dst);
V = (C && (dst == 0100000));
C = C & Z;
if (dstreg) R[dstspec] = dst;
else PWriteW (dst, last_pa);
break;
/* Opcode 0: SOPs, continued */
case 056: /* SBC */
dst = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec));
dst = (dst - C) & 0177777;
N = GET_SIGN_W (dst);
Z = GET_Z (dst);
V = (C && (dst == 077777));
C = (C && (dst == 0177777));
if (dstreg) R[dstspec] = dst;
else PWriteW (dst, last_pa);
break;
case 057: /* TST */
dst = dstreg? R[dstspec]: ReadW (GeteaW (dstspec));
N = GET_SIGN_W (dst);
Z = GET_Z (dst);
V = C = 0;
break;
case 060: /* ROR */
src = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec));
dst = (src >> 1) | (C << 15);
N = GET_SIGN_W (dst);
Z = GET_Z (dst);
C = (src & 1);
V = N ^ C;
if (dstreg) R[dstspec] = dst;