492
528
case 016: /* 105740-105737 */
493
529
case 017: /* 105760-105777 */
494
530
return cpu_eig (IR, intrq); /* Extended Instruction Group */
497
533
return stop_inst; /* others undefined */
502
The 2100 and 21MX CPUs share the single-precision (two word) floating point
503
instruction codes. Option implementation by CPU was as follows:
505
2116 2100 21MX-M 21MX-E 21MX-F
506
------ ------ ------ ------ ------
507
N/A 12901A std std std
509
The instruction codes are mapped to routines as follows:
511
Instr. 2100/21MX-M/E/F
512
------ ---------------
520
Bits 3-0 are not decoded by these instructions, so FAD (e.g.) would be
521
executed by any instruction in the range 105000-105017.
524
static const OP_PAT op_fp[6] = {
525
OP_F, OP_F, OP_F, OP_F, /* FAD FSB FMP FDV */
526
OP_N, OP_N /* FIX FLT --- --- */
529
static t_stat cpu_fp (uint32 IR, uint32 intrq)
531
t_stat reason = SCPE_OK;
535
if ((cpu_unit.flags & UNIT_FP) == 0) /* FP option installed? */
538
entry = (IR >> 4) & 017; /* mask to entry point */
540
if (op_fp[entry] != OP_N) {
541
if (reason = get_ops (op_fp[entry], op, intrq)) /* get instruction operands */
545
switch (entry) { /* decode IR<7:4> */
547
case 000: /* FMP 105000 */
548
O = f_as (op[0], 0); /* add, upd ovflo */
551
case 001: /* FMP 105020 */
552
O = f_as (op[0], 1); /* sub, upd ovflo */
555
case 002: /* FMP 105040 */
556
O = f_mul (op[0]); /* mul, upd ovflo */
559
case 003: /* FDV 105060 */
560
O = f_div (op[0]); /* div, upd ovflo */
563
case 004: /* FIX 105100 */
564
O = f_fix (); /* fix, upd ovflo */
567
case 005: /* FLT 105120 */
568
O = f_flt (); /* float, upd ovflo */
571
default: /* should be impossible */
578
/* Fast FORTRAN Processor
580
The Fast FORTRAN Processor (FFP) is a set of FORTRAN language accelerators
581
and extended-precision (three-word) floating point routines. Although the
582
FFP is an option for the 2100 and later CPUs, each implements the FFP in a
583
slightly different form.
585
Option implementation by CPU was as follows:
587
2116 2100 21MX-M 21MX-E 21MX-F
588
------ ------ ------ ------ ------
589
N/A 12907A 12977B 13306B std
591
The instruction codes are mapped to routines as follows:
593
Instr. 2100 21MX-M 21MX-E 21MX-F Instr. 2100 21MX-M 21MX-E 21MX-F
594
------ ------ ------ ------ ------ ------ ------ ------ ------ ------
595
105200 -- -- -- [test] 105220 .XFER .XFER .XFER .XFER
596
105201 DBLE DBLE DBLE DBLE 105221 .GOTO .GOTO .GOTO .GOTO
597
105202 SNGL SNGL SNGL SNGL 105222 ..MAP ..MAP ..MAP ..MAP
598
105203 .XMPY .XMPY .XMPY -- 105223 .ENTR .ENTR .ENTR .ENTR
599
105204 .XDIV .XDIV .XDIV -- 105224 .ENTP .ENTP .ENTP .ENTP
600
105205 .DFER .DFER .DFER .DFER 105225 -- .PWR2 .PWR2 .PWR2
601
105206 -- .XPAK .XPAK .XPAK 105226 -- .FLUN .FLUN .FLUN
602
105207 -- XADD XADD .BLE 105227 $SETP $SETP $SETP $SETP
604
105210 -- XSUB XSUB -- 105230 -- .PACK .PACK .PACK
605
105211 -- XMPY XMPY -- 105231 -- -- .CFER .CFER
606
105212 -- XDIV XDIV -- 105232 -- -- -- ..FCM
607
105213 .XADD .XADD .XADD -- 105233 -- -- -- ..TCM
608
105214 .XSUB .XSUB .XSUB .NGL 105234 -- -- -- --
609
105215 -- .XCOM .XCOM .XCOM 105235 -- -- -- --
610
105216 -- ..DCM ..DCM ..DCM 105236 -- -- -- --
611
105217 -- DDINT DDINT DDINT 105237 -- -- -- --
615
1. The "$SETP" instruction is sometimes listed as ".SETP" in the
618
2. Extended-precision arithmetic routines (e.g., .XMPY) exist on the
619
21MX-F, but they are assigned instruction codes in the single-precision
620
floating-point module.
622
3. The software implementation of ..MAP supports 1-, 2-, or 3-dimensional
623
arrays, designated by setting A = -1, 0, and +1, respectively. The
624
firmware implementation supports only 2- and 3-dimensional access.
626
4. The documentation for ..MAP for the 2100 FFP shows A = 0 or -1 for two
627
or three dimensions, respectively, but the 21MX FFP shows A = 0 or +1.
628
The firmware actually only checks the LSB of A.
630
5. The .DFER and .XFER implementations for the 2100 FFP return X+4 and Y+4
631
in the A and B registers, whereas the 21MX FFP returns X+3 and Y+3.
633
6. The .XFER implementation for the 2100 FFP returns to P+2, whereas the
634
21MX implementation returns to P+1.
636
Additional references:
637
- DOS/RTE Relocatable Library Reference Manual (24998-90001, Oct-1981)
638
- Implementing the HP 2100 Fast FORTRAN Processor (12907-90010, Nov-1974)
641
static const OP_PAT op_ffp[32] = {
642
OP_N, OP_AAF, OP_AX, OP_AXX, /* --- DBLE SNGL .XMPY */
643
OP_AXX, OP_AA, OP_A, OP_AAXX, /* .XDIV .DFER .XPAK XADD */
644
OP_AAXX, OP_AAXX, OP_AAXX, OP_AXX, /* XSUB XMPY XDIV .XADD */
645
OP_AXX, OP_A, OP_A, OP_AAX, /* .XSUB .XCOM ..DCM DDINT */
646
OP_N, OP_AK, OP_KKKK, OP_A, /* .XFER .GOTO ..MAP .ENTR */
647
OP_A, OP_K, OP_N, OP_K, /* .ENTP .PWR2 .FLUN $SETP */
648
OP_C, OP_AA, OP_N, OP_N, /* .PACK .CFER --- --- */
649
OP_N, OP_N, OP_N, OP_N /* --- --- --- --- */
652
static t_stat cpu_ffp (uint32 IR, uint32 intrq)
654
t_stat reason = SCPE_OK;
657
uint32 j, sa, sb, sc, da, dc, ra, MA;
661
if ((cpu_unit.flags & UNIT_FFP) == 0) /* FFP option installed? */
664
entry = IR & 037; /* mask to entry point */
666
if (op_ffp[entry] != OP_N) {
667
if (reason = get_ops (op_ffp[entry], op, intrq)) /* get instruction operands */
671
switch (entry) { /* decode IR<3:0> */
675
case 001: /* DBLE 105201 (OP_AAF) */
676
WriteW (op[1]++, (op[2] >> 16) & DMASK); /* transfer high mantissa */
677
WriteW (op[1]++, op[2] & 0177400); /* convert low mantissa */
678
WriteW (op[1], op[2] & 0377); /* convert exponent */
681
case 002: /* SNGL 105202 (OP_AX) */
682
BR = op[2] >> 16; /* move LSB and expon to B */
683
f_unpack (); /* unpack B into A/B */
684
sa = AR; /* save exponent */
685
AR = (op[1] >> 16) & DMASK; /* move MSB to A */
686
BR = (op[1] & DMASK) | (BR != 0); /* move mid to B with carry */
687
O = f_pack (SEXT (sa)); /* pack into A/B */
690
#if defined (HAVE_INT64)
692
case 003: /* .XMPY 105203 (OP_AXX) */
693
i = 0; /* params start at op[0] */
694
goto XMPY; /* process as XMPY */
696
case 004: /* .XDIV 105204 (OP_AXX) */
697
i = 0; /* params start at op[0] */
698
goto XDIV; /* process as XDIV */
702
case 005: /* .DFER 105205 (OP_AA) */
703
BR = op[0]; /* get destination address */
704
AR = op[1]; /* get source address */
705
goto XFER; /* do transfer */
707
#if defined (HAVE_INT64)
709
case 006: /* .XPAK 105206 (OP_A) */
710
if (UNIT_CPU_TYPE != UNIT_TYPE_21MX) /* must be 21MX */
711
return stop_inst; /* trap if not */
712
if (intrq) { /* interrupt pending? */
713
PC = err_PC; /* restart instruction */
716
xop = ReadX (op[0]); /* read unpacked */
717
O = x_pak (&xop, xop, SEXT (AR)); /* pack mantissa, exponent */
718
WriteX (op[0], xop); /* write back */
721
case 007: /* XADD 105207 (OP_AAXX) */
722
i = 1; /* params start at op[1] */
723
XADD: /* enter here from .XADD */
724
if (intrq) { /* interrupt pending? */
725
PC = err_PC; /* restart instruction */
728
O = x_add (&xop, AS_XPN (op [i + 1]), AS_XPN (op [i + 3])); /* add ops */
729
WriteX (op[i], xop); /* write sum */
732
case 010: /* XSUB 105210 (OP_AAXX) */
733
i = 1; /* params start at op[1] */
734
XSUB: /* enter here from .XSUB */
735
if (intrq) { /* interrupt pending? */
736
PC = err_PC; /* restart instruction */
739
O = x_sub (&xop, AS_XPN (op [i + 1]), AS_XPN (op [i + 3])); /* subtract */
740
WriteX (op[i], xop); /* write difference */
743
case 011: /* XMPY 105211 (OP_AAXX) */
744
i = 1; /* params start at op[1] */
745
XMPY: /* enter here from .XMPY */
746
if (intrq) { /* interrupt pending? */
747
PC = err_PC; /* restart instruction */
750
O = x_mpy (&xop, AS_XPN (op [i + 1]), AS_XPN (op [i + 3])); /* multiply */
751
WriteX (op[i], xop); /* write product */
754
case 012: /* XDIV 105212 (OP_AAXX) */
755
i = 1; /* params start at op[1] */
756
XDIV: /* enter here from .XDIV */
757
if (intrq) { /* interrupt pending? */
758
PC = err_PC; /* restart instruction */
761
O = x_div (&xop, AS_XPN (op [i + 1]), AS_XPN (op [i + 3])); /* divide */
762
WriteX (op[i], xop); /* write quotient */
765
case 013: /* .XADD 105213 (OP_AXX) */
766
i = 0; /* params start at op[0] */
767
goto XADD; /* process as XADD */
769
case 014: /* .XSUB 105214 (OP_AXX) */
770
i = 0; /* params start at op[0] */
771
goto XSUB; /* process as XSUB */
773
case 015: /* .XCOM 105215 (OP_A) */
774
if (UNIT_CPU_TYPE != UNIT_TYPE_21MX) /* must be 21MX */
775
return stop_inst; /* trap if not */
776
xop = ReadX (op[0]); /* read operand */
777
AR = x_com (&xop); /* neg and rtn exp adj */
778
WriteX (op[0], xop); /* write result */
781
case 016: /* ..DCM 105216 (OP_A) */
782
if (UNIT_CPU_TYPE != UNIT_TYPE_21MX) /* must be 21MX */
783
return stop_inst; /* trap if not */
784
if (intrq) { /* interrupt pending? */
785
PC = err_PC; /* restart instruction */
788
xop = ReadX (op[0]); /* read operand */
789
O = x_dcm (&xop); /* negate */
790
WriteX (op[0], xop); /* write result */
793
case 017: /* DDINT 105217 (OP_AAX) */
794
if (UNIT_CPU_TYPE != UNIT_TYPE_21MX) /* must be 21MX */
795
return stop_inst; /* trap if not */
796
if (intrq) { /* interrupt pending? */
797
PC = err_PC; /* restart instruction */
800
x_trun (&xop, AS_XPN (op [2])); /* truncate operand */
801
WriteX (op[1], xop); /* write result */
808
case 020: /* .XFER 105220 (OP_N) */
809
if (UNIT_CPU_TYPE == UNIT_TYPE_2100)
810
PC = (PC + 1) & VAMASK; /* 2100 .XFER returns to P+2 */
811
XFER: /* enter here from .DFER */
812
sc = 3; /* set count for 3-wd xfer */
813
goto CFER; /* do transfer */
815
case 021: /* .GOTO 105221 (OP_AK) */
816
if ((op[1] == 0) || (op[1] & SIGN)) /* index < 1? */
817
op[1] = 1; /* reset min */
818
sa = PC + op[1] - 1; /* point to jump target */
819
if (sa >= op[0]) /* must be <= last target */
821
da = ReadW (sa); /* get jump target */
822
if (reason = resolve (da, &MA, intrq)) { /* resolve indirects */
823
PC = err_PC; /* irq restarts instruction */
826
mp_dms_jmp (MA); /* validate jump addr */
827
PCQ_ENTRY; /* record last PC */
829
BR = op[0]; /* (for 2100 FFP compat) */
832
case 022: /* ..MAP 105222 (OP_KKKK) */
833
op[1] = op[1] - 1; /* decrement 1st subscr */
834
if ((AR & 1) == 0) /* 2-dim access? */
835
op[1] = op[1] + (op[2] - 1) * op[3]; /* compute element offset */
836
else { /* 3-dim access */
837
if (reason = get_ops (OP_KK, op2, intrq)) { /* get 1st, 2nd ranges */
838
PC = err_PC; /* irq restarts instruction */
841
op[1] = op[1] + ((op[3] - 1) * op2[1] + op[2] - 1) * op2[0]; /* offset */
843
AR = (op[0] + op[1] * BR) & DMASK; /* return element address */
846
case 023: /* .ENTR 105223 (OP_A) */
847
MA = PC - 3; /* get addr of entry point */
848
ENTR: /* enter here from .ENTP */
849
da = op[0]; /* get addr of 1st formal */
850
dc = MA - da; /* get count of formals */
851
sa = ReadW (MA); /* get addr of return point */
852
ra = ReadW (sa++); /* get rtn, ptr to 1st actual */
853
WriteW (MA, ra); /* stuff rtn into caller's ent */
854
sc = ra - sa; /* get count of actuals */
855
if (sc > dc) sc = dc; /* use min (actuals, formals) */
856
for (j = 0; j < sc; j++) {
857
MA = ReadW (sa++); /* get addr of actual */
858
if (reason = resolve (MA, &MA, intrq)) { /* resolve indirect */
859
PC = err_PC; /* irq restarts instruction */
862
WriteW (da++, MA); /* put addr into formal */
864
AR = ra; /* return address */
865
BR = da; /* addr of 1st unused formal */
868
case 024: /* .ENTP 105224 (OP_A) */
869
MA = PC - 5; /* get addr of entry point */
872
case 025: /* .PWR2 105225 (OP_K) */
873
if (UNIT_CPU_TYPE != UNIT_TYPE_21MX) /* must be 21MX */
874
return stop_inst; /* trap if not */
875
f_pwr2 (SEXT (op[0])); /* calc result into A/B */
878
case 026: /* .FLUN 105226 (OP_N) */
879
if (UNIT_CPU_TYPE != UNIT_TYPE_21MX) /* must be 21MX */
880
return stop_inst; /* trap if not */
881
f_unpack (); /* unpack into A/B */
884
case 027: /* $SETP 105227 (OP_K) */
885
j = sa = AR; /* save initial value */
886
sb = BR; /* save initial address */
887
AR = 0; /* AR will return = 0 */
888
BR = BR & VAMASK; /* addr must be direct */
890
WriteW (BR, j); /* write value to address */
891
j = (j + 1) & DMASK; /* incr value */
892
BR = (BR + 1) & VAMASK; /* incr address */
893
op[0] = op[0] - 1; /* decr count */
894
if (op[0] && intrq) { /* more and intr? */
895
AR = sa; /* restore A */
896
BR = sb; /* restore B */
897
PC = err_PC; /* restart instruction */
901
while (op[0] != 0); /* loop until count exhausted */
904
case 030: /* .PACK 105230 (OP_C) */
905
if (UNIT_CPU_TYPE != UNIT_TYPE_21MX) /* must be 21MX */
906
return stop_inst; /* trap if not */
907
O = f_pack (SEXT (op[0])); /* calc A/B and overflow */
910
case 031: /* .CFER 105231 (OP_AA) */
911
if (UNIT_CPU_MODEL != UNIT_21MX_E) /* must be 21MX E-series */
912
return stop_inst; /* trap if not */
913
BR = op[0]; /* get destination address */
914
AR = op[1]; /* get source address */
915
sc = 4; /* set for 4-wd xfer */
916
CFER: /* enter here from .XFER */
917
for (j = 0; j < sc; j++) { /* xfer loop */
918
WriteW (BR, ReadW (AR)); /* transfer word */
919
AR = (AR + 1) & VAMASK; /* bump source addr */
920
BR = (BR + 1) & VAMASK; /* bump destination addr */
922
E = 0; /* routine clears E */
923
if (UNIT_CPU_TYPE == UNIT_TYPE_2100) { /* 2100 (and .DFER/.XFER)? */
924
AR = (AR + 1) & VAMASK; /* 2100 FFP returns X+4, Y+4 */
925
BR = (BR + 1) & VAMASK;
929
default: /* others undefined */
936
/* 2000 I/O Processor
938
The IOP accelerates certain operations of the HP 2000 Time-Share BASIC system
939
I/O processor. Most 2000 systems were delivered with 2100 CPUs, although IOP
940
microcode was developed for the 21MX-M and 21MX-E. As the I/O processors
941
were specific to the 2000 system, general compatibility with other CPU
942
microcode options was unnecessary, and indeed no other options were possible
945
Option implementation by CPU was as follows:
947
2116 2100 21MX-M 21MX-E 21MX-F
948
------ ------ ------ ------ ------
949
N/A 13206A 13207A 22702A N/A
951
The routines are mapped to instruction codes as follows:
953
Instr. 2100 21MX-M/E Description
954
------ ---------- ---------- --------------------------------------------
955
SAI 105060-117 101400-037 Store A indexed by B (+/- offset in IR<4:0>)
956
LAI 105020-057 105400-037 Load A indexed by B (+/- offset in IR<4:0>)
957
CRC 105150 105460 Generate CRC
958
REST 105340 105461 Restore registers from stack
959
READF 105220 105462 Read F register (stack pointer)
960
INS -- 105463 Initialize F register (stack pointer)
961
ENQ 105240 105464 Enqueue
962
PENQ 105257 105465 Priority enqueue
963
DEQ 105260 105466 Dequeue
964
TRSLT 105160 105467 Translate character
965
ILIST 105000 105470 Indirect address list (similar to $SETP)
966
PRFEI 105222 105471 Power fail exit with I/O
967
PRFEX 105223 105472 Power fail exit
968
PRFIO 105221 105473 Power fail I/O
969
SAVE 105362 105474 Save registers to stack
971
MBYTE 105120 105765 Move bytes (MBT)
972
MWORD 105200 105777 Move words (MVW)
973
SBYTE 105300 105764 Store byte (SBT)
974
LBYTE 105320 105763 Load byte (LBT)
976
The INS instruction was not required in the 2100 implementation because the
977
stack pointer was actually the memory protect fence register and so could be
978
loaded directly with an OTA/B 05. Also, the 21MX implementation did not
979
offer the MBYTE, MWORD, SBYTE, and LBYTE instructions because the equivalent
980
instructions from the standard Extended Instruction Group were used instead.
982
Additional reference:
983
- HP 2000 Computer System Sources and Listings Documentation
984
(22687-90020, undated), section 3, pages 2-74 through 2-91.
987
static const OP_PAT op_iop[16] = {
988
OP_V, OP_N, OP_N, OP_N, /* CRC RESTR READF INS */
989
OP_N, OP_N, OP_N, OP_V, /* ENQ PENQ DEQ TRSLT */
990
OP_AC, OP_CVA, OP_A, OP_CV, /* ILIST PRFEI PRFEX PRFIO */
991
OP_N, OP_N, OP_N, OP_N /* SAVE --- --- --- */
994
static t_stat cpu_iop (uint32 IR, uint32 intrq)
996
t_stat reason = SCPE_OK;
999
uint32 hp, tp, i, t, wc, MA;
1001
if ((cpu_unit.flags & UNIT_IOP) == 0) /* IOP option installed? */
1004
entry = IR & 077; /* mask to entry point */
1006
if (entry <= 037) { /* LAI/SAI 10x400-437 */
1007
MA = ((entry - 020) + BR) & VAMASK; /* +/- offset */
1008
if (IR & I_AB) AR = ReadW (MA); /* AB = 1 -> LAI */
1009
else WriteW (MA, AR); /* AB = 0 -> SAI */
1012
else if (entry <= 057) /* IR = 10x440-457? */
1013
return stop_inst; /* not part of IOP */
1015
entry = entry - 060; /* offset 10x460-477 */
1017
if (op_iop[entry] != OP_N) {
1018
if (reason = get_ops (op_iop[entry], op, intrq)) /* get instruction operands */
1022
switch (entry) { /* decode IR<5:0> */
1024
case 000: /* CRC 105460 (OP_V) */
1025
t = ReadW (op[0]) ^ (AR & 0377); /* xor prev CRC and char */
1026
for (i = 0; i < 8; i++) { /* apply polynomial */
1027
t = (t >> 1) | ((t & 1) << 15); /* rotate right */
1028
if (t & SIGN) t = t ^ 020001; /* old t<0>? xor */
1030
WriteW (op[0], t); /* rewrite CRC */
1033
case 001: /* RESTR 105461 (OP_N) */
1034
iop_sp = (iop_sp - 1) & VAMASK; /* decr stack ptr */
1035
t = ReadW (iop_sp); /* get E and O */
1036
O = ((t >> 1) ^ 1) & 1; /* restore O */
1037
E = t & 1; /* restore E */
1038
iop_sp = (iop_sp - 1) & VAMASK; /* decr sp */
1039
BR = ReadW (iop_sp); /* restore B */
1040
iop_sp = (iop_sp - 1) & VAMASK; /* decr sp */
1041
AR = ReadW (iop_sp); /* restore A */
1042
if (UNIT_CPU_MODEL == UNIT_2100)
1043
mp_fence = iop_sp; /* 2100 keeps sp in MP FR */
1046
case 002: /* READF 105462 (OP_N) */
1047
AR = iop_sp; /* copy stk ptr */
1050
case 003: /* INS 105463 (OP_N) */
1051
iop_sp = AR; /* init stk ptr */
1054
case 004: /* ENQ 105464 (OP_N) */
1055
hp = ReadW (AR & VAMASK); /* addr of head */
1056
tp = ReadW ((AR + 1) & VAMASK); /* addr of tail */
1057
WriteW ((BR - 1) & VAMASK, 0); /* entry link */
1058
WriteW ((tp - 1) & VAMASK, BR); /* tail link */
1059
WriteW ((AR + 1) & VAMASK, BR); /* queue tail */
1060
if (hp != 0) PC = (PC + 1) & VAMASK; /* q not empty? skip */
1063
case 005: /* PENQ 105465 (OP_N) */
1064
hp = ReadW (AR & VAMASK); /* addr of head */
1065
WriteW ((BR - 1) & VAMASK, hp); /* becomes entry link */
1066
WriteW (AR & VAMASK, BR); /* queue head */
1067
if (hp == 0) /* q empty? */
1068
WriteW ((AR + 1) & VAMASK, BR); /* queue tail */
1069
else PC = (PC + 1) & VAMASK; /* skip */
1072
case 006: /* DEQ 105466 (OP_N) */
1073
BR = ReadW (AR & VAMASK); /* addr of head */
1074
if (BR) { /* queue not empty? */
1075
hp = ReadW ((BR - 1) & VAMASK); /* read hd entry link */
1076
WriteW (AR & VAMASK, hp); /* becomes queue head */
1077
if (hp == 0) /* q now empty? */
1078
WriteW ((AR + 1) & VAMASK, (AR + 1) & DMASK);
1079
PC = (PC + 1) & VAMASK; /* skip */
1083
case 007: /* TRSLT 105467 (OP_V) */
1084
wc = ReadW (op[0]); /* get count */
1085
if (wc & SIGN) break; /* cnt < 0? */
1086
while (wc != 0) { /* loop */
1087
MA = (AR + AR + ReadB (BR)) & VAMASK;
1088
t = ReadB (MA); /* xlate */
1089
WriteB (BR, t); /* store char */
1090
BR = (BR + 1) & DMASK; /* incr ptr */
1091
wc = (wc - 1) & DMASK; /* decr cnt */
1092
if (wc && intrq) { /* more and intr? */
1093
WriteW (op[0], wc); /* save count */
1094
PC = err_PC; /* stop for now */
1100
case 010: /* ILIST 105470 (OP_AC) */
1101
do { /* for count */
1102
WriteW (op[0], AR); /* write AR to mem */
1103
AR = (AR + 1) & DMASK; /* incr AR */
1104
op[0] = (op[0] + 1) & VAMASK; /* incr MA */
1105
op[1] = (op[1] - 1) & DMASK; /* decr count */
1110
case 011: /* PRFEI 105471 (OP_CVA) */
1111
WriteW (op[1], 1); /* set flag */
1112
reason = iogrp (op[0], 0); /* execute I/O instr */
1113
op[0] = op[2]; /* set rtn and fall through */
1115
case 012: /* PRFEX 105472 (OP_A) */
1117
PC = ReadW (op[0]) & VAMASK; /* jump indirect */
1118
WriteW (op[0], 0); /* clear exit */
1121
case 013: /* PRFIO 105473 (OP_CV) */
1122
WriteW (op[1], 1); /* set flag */
1123
reason = iogrp (op[0], 0); /* execute instr */
1126
case 014: /* SAVE 105474 (OP_N) */
1127
WriteW (iop_sp, AR); /* save A */
1128
iop_sp = (iop_sp + 1) & VAMASK; /* incr stack ptr */
1129
WriteW (iop_sp, BR); /* save B */
1130
iop_sp = (iop_sp + 1) & VAMASK; /* incr stack ptr */
1131
t = ((O ^ 1) << 1) | E; /* merge E and O */
1132
WriteW (iop_sp, t); /* save E and O */
1133
iop_sp = (iop_sp + 1) & VAMASK; /* incr stack ptr */
1134
if (UNIT_CPU_TYPE == UNIT_TYPE_2100)
1135
mp_fence = iop_sp; /* 2100 keeps sp in MP FR */
1138
default: /* instruction undefined */
1145
/* Dynamic Mapping System
1147
The 21MX Dynamic Mapping System (DMS) consisted of the 12731A Memory
1148
Expansion Module (MEM) card and 38 instructions to expand the basic 32K
1149
logical address space to a 1024K physical space. The MEM provided four maps
1150
of 32 mapping registers each: a system map, a user map, and two DCPC maps.
1151
DMS worked in conjunction with memory protect to provide a "protected mode"
1152
in which memory read and write violations could be trapped, and that
1153
inhibited "privileged" instruction execution that attempted to alter the
1156
Option implementation by CPU was as follows:
1158
2116 2100 21MX-M 21MX-E 21MX-F
1159
------ ------ ------ ------ ------
1160
N/A N/A 12976B 13307B std
1162
The instruction codes are mapped to routines as follows:
1164
Instr. 21MX-M 21MX-E/F Instr. 21MX-M 21MX-E/F
1165
------ ------ -------- ------ ------ --------
1166
10x700 [xmm] [xmm] 10x720 XMM XMM
1167
10x701 [nop] [test] 10x721 XMS XMS
1168
10x702 MBI MBI 10x722 XM* XM*
1169
10x703 MBF MBF 10x723 [nop] [nop]
1170
10x704 MBW MBW 10x724 XL* XL*
1171
10x705 MWI MWI 10x725 XS* XS*
1172
10x706 MWF MWF 10x726 XC* XC*
1173
10x707 MWW MWW 10x727 LF* LF*
1174
10x710 SY* SY* 10x730 RS* RS*
1176
10x711 US* US* 10x731 RV* RV*
1177
10x712 PA* PA* 10x732 DJP DJP
1178
10x713 PB* PB* 10x733 DJS DJS
1179
10x714 SSM SSM 10x734 SJP SJP
1180
10x715 JRS JRS 10x735 SJS SJS
1181
10x716 [nop] [nop] 10x736 UJP UJP
1182
10x717 [nop] [nop] 10x737 UJS UJS
1184
Instructions that use IR bit 9 to select the A or B register are designated
1185
with a * above (e.g., 101710 is SYA, and 105710 is SYB). For those that do
1186
not use this feature, either the 101xxx or 105xxx code will execute the
1187
corresponding instruction, although the 105xxx form is the documented
1192
1. Instruction code 10x700 will execute the XMM instruction, although
1193
10x720 is the documented instruction value.
1195
2. The DMS privilege violation rules are:
1196
- load map and CTL5 set (XMM, XMS, XM*, SY*, US*, PA*, PB*)
1197
- load state or fence and UMAP set (JRS, DJP, DJS, SJP, SJS, UJP, UJS, LF*)
1199
3. The 21MX manual is incorrect in stating that M*I, M*W, XS* are
1203
static const OP_PAT op_dms[32] = {
1204
OP_N, OP_N, OP_N, OP_N, /* xmm test MBI MBF */
1205
OP_N, OP_N, OP_N, OP_N, /* MBW MWI MWF MWW */
1206
OP_N, OP_N, OP_N, OP_N, /* SYA/B USA/B PAA/B PBA/B */
1207
OP_A, OP_KA, OP_N, OP_N, /* SSM JRS nop nop */
1208
OP_N, OP_N, OP_N, OP_N, /* XMM XMS XMA/B nop */
1209
OP_A, OP_A, OP_A, OP_N, /* XLA/B XSA/B XCA/B LFA/B */
1210
OP_N, OP_N, OP_A, OP_A, /* RSA/B RVA/B DJP DJS */
1211
OP_A, OP_A, OP_A, OP_A /* SJP SJS UJP UJS */
1214
static t_stat cpu_dms (uint32 IR, uint32 intrq)
1216
t_stat reason = SCPE_OK;
1218
uint32 entry, absel;
1219
uint32 i, t, mapi, mapj;
1221
if ((cpu_unit.flags & UNIT_DMS) == 0) /* DMS option installed? */
1224
absel = (IR & I_AB)? 1: 0; /* get A/B select */
1225
entry = IR & 037; /* mask to entry point */
1227
if (op_dms[entry] != OP_N) {
1228
if (reason = get_ops (op_dms[entry], op, intrq)) /* get instruction operands */
1232
switch (entry) { /* decode IR<3:0> */
1236
case 000: /* [undefined] 105700 (OP_N) */
1237
goto XMM; /* decodes as XMM */
1239
case 001: /* [self test] 105701 (OP_N) */
1240
ABREG[absel] = ABREG[absel] ^ DMASK; /* CMA or CMB */
1243
case 002: /* MBI 105702 (OP_N) */
1244
AR = AR & ~1; /* force A, B even */
1246
while (XR != 0) { /* loop */
1247
t = ReadB (AR); /* read curr */
1248
WriteBA (BR, t); /* write alt */
1249
AR = (AR + 1) & DMASK; /* incr ptrs */
1250
BR = (BR + 1) & DMASK;
1251
XR = (XR - 1) & DMASK;
1252
if (XR && intrq && !(AR & 1)) { /* more, int, even? */
1253
PC = err_PC; /* stop for now */
1259
case 003: /* MBF 105703 (OP_N) */
1260
AR = AR & ~1; /* force A, B even */
1262
while (XR != 0) { /* loop */
1263
t = ReadBA (AR); /* read alt */
1264
WriteB (BR, t); /* write curr */
1265
AR = (AR + 1) & DMASK; /* incr ptrs */
1266
BR = (BR + 1) & DMASK;
1267
XR = (XR - 1) & DMASK;
1268
if (XR && intrq && !(AR & 1)) { /* more, int, even? */
1269
PC = err_PC; /* stop for now */
1275
case 004: /* MBW 105704 (OP_N) */
1276
AR = AR & ~1; /* force A, B even */
1278
while (XR != 0) { /* loop */
1279
t = ReadBA (AR); /* read alt */
1280
WriteBA (BR, t); /* write alt */
1281
AR = (AR + 1) & DMASK; /* incr ptrs */
1282
BR = (BR + 1) & DMASK;
1283
XR = (XR - 1) & DMASK;
1284
if (XR && intrq && !(AR & 1)) { /* more, int, even? */
1285
PC = err_PC; /* stop for now */
1291
case 005: /* MWI 105705 (OP_N) */
1292
while (XR != 0) { /* loop */
1293
t = ReadW (AR & VAMASK); /* read curr */
1294
WriteWA (BR & VAMASK, t); /* write alt */
1295
AR = (AR + 1) & DMASK; /* incr ptrs */
1296
BR = (BR + 1) & DMASK;
1297
XR = (XR - 1) & DMASK;
1298
if (XR && intrq) { /* more and intr? */
1299
PC = err_PC; /* stop for now */
1305
case 006: /* MWF 105706 (OP_N) */
1306
while (XR != 0) { /* loop */
1307
t = ReadWA (AR & VAMASK); /* read alt */
1308
WriteW (BR & VAMASK, t); /* write curr */
1309
AR = (AR + 1) & DMASK; /* incr ptrs */
1310
BR = (BR + 1) & DMASK;
1311
XR = (XR - 1) & DMASK;
1312
if (XR && intrq) { /* more and intr? */
1313
PC = err_PC; /* stop for now */
1319
case 007: /* MWW 105707 (OP_N) */
1320
while (XR != 0) { /* loop */
1321
t = ReadWA (AR & VAMASK); /* read alt */
1322
WriteWA (BR & VAMASK, t); /* write alt */
1323
AR = (AR + 1) & DMASK; /* incr ptrs */
1324
BR = (BR + 1) & DMASK;
1325
XR = (XR - 1) & DMASK;
1326
if (XR && intrq) { /* more and intr? */
1327
PC = err_PC; /* stop for now */
1333
case 010: /* SYA, SYB 10x710 (OP_N) */
1334
case 011: /* USA, USB 10x711 (OP_N) */
1335
case 012: /* PAA, PAB 10x712 (OP_N) */
1336
case 013: /* PBA, PBB 10x713 (OP_N) */
1337
mapi = (IR & 03) << VA_N_PAG; /* map base */
1338
if (ABREG[absel] & SIGN) { /* store? */
1339
for (i = 0; i < MAP_LNT; i++) {
1340
t = dms_rmap (mapi + i); /* map to memory */
1341
WriteW ((ABREG[absel] + i) & VAMASK, t);
1345
dms_viol (err_PC, MVI_PRV); /* priv if PRO */
1346
for (i = 0; i < MAP_LNT; i++) {
1347
t = ReadW ((ABREG[absel] + i) & VAMASK);
1348
dms_wmap (mapi + i, t); /* mem to map */
1351
ABREG[absel] = (ABREG[absel] + MAP_LNT) & DMASK;
1354
case 014: /* SSM 105714 (OP_A) */
1355
WriteW (op[0], dms_upd_sr ()); /* store stat */
1358
case 015: /* JRS 105715 (OP_KA) */
1359
if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */
1360
dms_enb = 0; /* assume off */
1362
if (op[0] & 0100000) { /* set enable? */
1364
if (op[0] & 0040000) dms_ump = UMAP; /* set/clr usr */
1366
mp_dms_jmp (op[1]); /* mpck jmp target */
1367
PCQ_ENTRY; /* save old PC */
1368
PC = op[1]; /* jump */
1369
ion_defer = 1; /* defer intr */
1374
case 020: /* XMM 105720 (OP_N) */
1376
if (XR == 0) break; /* nop? */
1377
while (XR != 0) { /* loop */
1378
if (XR & SIGN) { /* store? */
1379
t = dms_rmap (AR); /* map to mem */
1380
WriteW (BR & VAMASK, t);
1381
XR = (XR + 1) & DMASK;
1384
dms_viol (err_PC, MVI_PRV); /* priv viol if prot */
1385
t = ReadW (BR & VAMASK); /* mem to map */
1387
XR = (XR - 1) & DMASK;
1389
AR = (AR + 1) & DMASK;
1390
BR = (BR + 1) & DMASK;
1391
if (intrq && ((XR & 017) == 017)) { /* intr, grp of 16? */
1392
PC = err_PC; /* stop for now */
1398
case 021: /* XMS 105721 (OP_N) */
1399
if ((XR & SIGN) || (XR == 0)) break; /* nop? */
1400
dms_viol (err_PC, MVI_PRV); /* priv viol if prot */
1402
dms_wmap (AR, BR); /* AR to map */
1403
XR = (XR - 1) & DMASK;
1404
AR = (AR + 1) & DMASK;
1405
BR = (BR + 1) & DMASK;
1406
if (intrq && ((XR & 017) == 017)) { /* intr, grp of 16? */
1413
case 022: /* XMA, XMB 10x722 (OP_N) */
1414
dms_viol (err_PC, MVI_PRV); /* priv viol if prot */
1415
if (ABREG[absel] & 0100000) mapi = UMAP;
1417
if (ABREG[absel] & 0000001) mapj = PBMAP;
1419
for (i = 0; i < MAP_LNT; i++) {
1420
t = dms_rmap (mapi + i); /* read map */
1421
dms_wmap (mapj + i, t); /* write map */
1425
case 024: /* XLA, XLB 10x724 (OP_A) */
1426
ABREG[absel] = ReadWA (op[0]); /* load alt */
1429
case 025: /* XSA, XSB 10x725 (OP_A) */
1430
WriteWA (op[0], ABREG[absel]); /* store alt */
1433
case 026: /* XCA, XCB 10x726 (OP_A) */
1434
if (ABREG[absel] != ReadWA (op[0])) /* compare alt */
1435
PC = (PC + 1) & VAMASK;
1438
case 027: /* LFA, LFB 10x727 (OP_N) */
1439
if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */
1440
dms_sr = (dms_sr & ~(MST_FLT | MST_FENCE)) |
1441
(ABREG[absel] & (MST_FLT | MST_FENCE));
1444
case 030: /* RSA, RSB 10x730 (OP_N) */
1445
ABREG[absel] = dms_upd_sr (); /* save stat */
1448
case 031: /* RVA, RVB 10x731 (OP_N) */
1449
ABREG[absel] = dms_vr; /* save viol */
1452
case 032: /* DJP 105732 (OP_A) */
1453
if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */
1454
mp_dms_jmp (op[0]); /* validate jump addr */
1455
PCQ_ENTRY; /* save curr PC */
1456
PC = op[0]; /* new PC */
1457
dms_enb = 0; /* disable map */
1462
case 033: /* DJS 105733 (OP_A) */
1463
if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */
1464
WriteW (op[0], PC); /* store ret addr */
1465
PCQ_ENTRY; /* save curr PC */
1466
PC = (op[0] + 1) & VAMASK; /* new PC */
1467
dms_enb = 0; /* disable map */
1469
ion_defer = 1; /* defer intr */
1472
case 034: /* SJP 105734 (OP_A) */
1473
if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */
1474
mp_dms_jmp (op[0]); /* validate jump addr */
1475
PCQ_ENTRY; /* save curr PC */
1476
PC = op[0]; /* jump */
1477
dms_enb = 1; /* enable system */
1479
ion_defer = 1; /* defer intr */
1482
case 035: /* SJS 105735 (OP_A) */
1483
if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */
1484
t = PC; /* save retn addr */
1485
PCQ_ENTRY; /* save curr PC */
1486
PC = (op[0] + 1) & VAMASK; /* new PC */
1487
dms_enb = 1; /* enable system */
1489
WriteW (op[0], t); /* store ret addr */
1490
ion_defer = 1; /* defer intr */
1493
case 036: /* UJP 105736 (OP_A) */
1494
if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */
1495
mp_dms_jmp (op[0]); /* validate jump addr */
1496
PCQ_ENTRY; /* save curr PC */
1497
PC = op[0]; /* jump */
1498
dms_enb = 1; /* enable user */
1500
ion_defer = 1; /* defer intr */
1503
case 037: /* UJS 105737 (OP_A) */
1504
if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */
1505
t = PC; /* save retn addr */
1506
PCQ_ENTRY; /* save curr PC */
1507
PC = (op[0] + 1) & VAMASK; /* new PC */
1508
dms_enb = 1; /* enable user */
1510
WriteW (op[0], t); /* store ret addr */
1511
ion_defer = 1; /* defer intr */
1514
default: /* others NOP */
1521
/* Extended Instruction Group
1523
The Extended Instruction Group (EIG) adds 32 index and 10 bit/byte/word
1524
manipulation instructions to the 21MX base set. These instructions
1525
use the new X and Y index registers that were added to the 21MX.
1527
Option implementation by CPU was as follows:
1529
2116 2100 21MX-M 21MX-E 21MX-F
1530
------ ------ ------ ------ ------
1533
The instruction codes are mapped to routines as follows:
1535
Instr. 21MX-M/E/F Instr. 21MX-M/E/F
1536
------ ---------- ------ ----------
1537
10x740 S*X 10x760 ISX
1538
10x741 C*X 10x761 DSX
1539
10x742 L*X 10x762 JLY
1540
10x743 STX 10x763 LBT
1541
10x744 CX* 10x764 SBT
1542
10x745 LDX 10x765 MBT
1543
10x746 ADX 10x766 CBT
1544
10x747 X*X 10x767 SFB
1546
10x750 S*Y 10x770 ISY
1547
10x751 C*Y 10x771 DSY
1548
10x752 L*Y 10x772 JPY
1549
10x753 STY 10x773 SBS
1550
10x754 CY* 10x774 CBS
1551
10x755 LDY 10x775 TBS
1552
10x756 ADY 10x776 CMW
1553
10x757 X*Y 10x777 MVW
1555
Instructions that use IR bit 9 to select the A or B register are designated
1556
with a * above (e.g., 101740 is SAX, and 105740 is SBX). For those that do
1557
not use this feature, either the 101xxx or 105xxx code will execute the
1558
corresponding instruction, although the 105xxx form is the documented
1563
1. The LBT, SBT, MBT, and MVW instructions are used as part of the 2100 IOP
1564
implementation. When so called, the MBT and MVW instructions have the
1565
additional restriction that the count must be positive.
1568
static const OP_PAT op_eig[32] = {
1569
OP_A, OP_N, OP_A, OP_A, /* S*X C*X L*X STX */
1570
OP_N, OP_K, OP_K, OP_N, /* CX* LDX ADX X*X */
1571
OP_A, OP_N, OP_A, OP_A, /* S*Y C*Y L*Y STY */
1572
OP_N, OP_K, OP_K, OP_N, /* CY* LDY ADY X*Y */
1573
OP_N, OP_N, OP_A, OP_N, /* ISX DSX JLY LBT */
1574
OP_N, OP_KV, OP_KV, OP_N, /* SBT MBT CBT SFB */
1575
OP_N, OP_N, OP_C, OP_KA, /* ISY DSY JPY SBS */
1576
OP_KA, OP_KK, OP_KV, OP_KV /* CBS TBS CMW MVW */
1579
static t_stat cpu_eig (uint32 IR, uint32 intrq)
1581
t_stat reason = SCPE_OK;
1583
uint32 entry, absel;
1584
uint32 t, v1, v2, wc;
1587
absel = (IR & I_AB)? 1: 0; /* get A/B select */
1588
entry = IR & 037; /* mask to entry point */
1590
if (op_eig[entry] != OP_N) {
1591
if (reason = get_ops (op_eig[entry], op, intrq)) /* get instruction operands */
1595
switch (entry) { /* decode IR<4:0> */
1599
case 000: /* SAX, SBX 10x740 (OP_A) */
1600
op[0] = (op[0] + XR) & VAMASK; /* indexed addr */
1601
WriteW (op[0], ABREG[absel]); /* store */
1604
case 001: /* CAX, CBX 10x741 (OP_N) */
1605
XR = ABREG[absel]; /* copy to XR */
1608
case 002: /* LAX, LBX 10x742 (OP_A) */
1609
op[0] = (op[0] + XR) & VAMASK; /* indexed addr */
1610
ABREG[absel] = ReadW (op[0]); /* load */
1613
case 003: /* STX 105743 (OP_A) */
1614
WriteW (op[0], XR); /* store XR */
1617
case 004: /* CXA, CXB 10x744 (OP_N) */
1618
ABREG[absel] = XR; /* copy from XR */
1621
case 005: /* LDX 105745 (OP_K)*/
1622
XR = op[0]; /* load XR */
1625
case 006: /* ADX 105746 (OP_K) */
1626
t = XR + op[0]; /* add to XR */
1627
if (t > DMASK) E = 1; /* set E, O */
1628
if (((~XR ^ op[0]) & (XR ^ t)) & SIGN) O = 1;
1632
case 007: /* XAX, XBX 10x747 (OP_N) */
1633
t = XR; /* exchange XR */
1638
case 010: /* SAY, SBY 10x750 (OP_A) */
1639
op[0] = (op[0] + YR) & VAMASK; /* indexed addr */
1640
WriteW (op[0], ABREG[absel]); /* store */
1643
case 011: /* CAY, CBY 10x751 (OP_N) */
1644
YR = ABREG[absel]; /* copy to YR */
1647
case 012: /* LAY, LBY 10x752 (OP_A) */
1648
op[0] = (op[0] + YR) & VAMASK; /* indexed addr */
1649
ABREG[absel] = ReadW (op[0]); /* load */
1652
case 013: /* STY 105753 (OP_A) */
1653
WriteW (op[0], YR); /* store YR */
1656
case 014: /* CYA, CYB 10x754 (OP_N) */
1657
ABREG[absel] = YR; /* copy from YR */
1660
case 015: /* LDY 105755 (OP_K) */
1661
YR = op[0]; /* load YR */
1664
case 016: /* ADY 105756 (OP_K) */
1665
t = YR + op[0]; /* add to YR */
1666
if (t > DMASK) E = 1; /* set E, O */
1667
if (((~YR ^ op[0]) & (YR ^ t)) & SIGN) O = 1;
1671
case 017: /* XAY, XBY 10x757 (OP_N) */
1672
t = YR; /* exchange YR */
1679
case 020: /* ISX 105760 (OP_N) */
1680
XR = (XR + 1) & DMASK; /* incr XR */
1681
if (XR == 0) PC = (PC + 1) & VAMASK; /* skip if zero */
1684
case 021: /* DSX 105761 (OP_N) */
1685
XR = (XR - 1) & DMASK; /* decr XR */
1686
if (XR == 0) PC = (PC + 1) & VAMASK; /* skip if zero */
1689
case 022: /* JLY 105762 (OP_A) */
1690
mp_dms_jmp (op[0]); /* validate jump addr */
1692
YR = PC; /* ret addr to YR */
1693
PC = op[0]; /* jump */
1696
case 023: /* LBT 105763 (OP_N) */
1697
AR = ReadB (BR); /* load byte */
1698
BR = (BR + 1) & DMASK; /* incr ptr */
1701
case 024: /* SBT 105764 (OP_N) */
1702
WriteB (BR, AR); /* store byte */
1703
BR = (BR + 1) & DMASK; /* incr ptr */
1706
case 025: /* MBT 105765 (OP_KV) */
1707
wc = ReadW (op[1]); /* get continuation count */
1708
if (wc == 0) wc = op[0]; /* none? get initiation count */
1709
if ((wc & SIGN) && (UNIT_CPU_TYPE == UNIT_TYPE_2100))
1710
break; /* < 0 is NOP for 2100 IOP */
1711
while (wc != 0) { /* while count */
1712
WriteW (op[1], wc); /* for MP abort */
1713
t = ReadB (AR); /* move byte */
1715
AR = (AR + 1) & DMASK; /* incr src */
1716
BR = (BR + 1) & DMASK; /* incr dst */
1717
wc = (wc - 1) & DMASK; /* decr cnt */
1718
if (intrq && wc) { /* intr, more to do? */
1719
PC = err_PC; /* back up PC */
1723
WriteW (op[1], wc); /* clean up inline */
1726
case 026: /* CBT 105766 (OP_KV) */
1727
wc = ReadW (op[1]); /* get continuation count */
1728
if (wc == 0) wc = op[0]; /* none? get initiation count */
1729
while (wc != 0) { /* while count */
1730
WriteW (op[1], wc); /* for MP abort */
1731
v1 = ReadB (AR); /* get src1 */
1732
v2 = ReadB (BR); /* get src2 */
1733
if (v1 != v2) { /* compare */
1734
PC = (PC + 1 + (v1 > v2)) & VAMASK;
1735
BR = (BR + wc) & DMASK; /* update BR */
1736
wc = 0; /* clr interim */
1739
AR = (AR + 1) & DMASK; /* incr src1 */
1740
BR = (BR + 1) & DMASK; /* incr src2 */
1741
wc = (wc - 1) & DMASK; /* decr cnt */
1742
if (intrq && wc) { /* intr, more to do? */
1743
PC = err_PC; /* back up PC */
1747
WriteW (op[1], wc); /* clean up inline */
1750
case 027: /* SFB 105767 (OP_N) */
1751
v1 = AR & 0377; /* test byte */
1752
v2 = (AR >> 8) & 0377; /* term byte */
1753
for (;;) { /* scan */
1754
t = ReadB (BR); /* read byte */
1755
if (t == v1) break; /* test match? */
1756
BR = (BR + 1) & DMASK;
1757
if (t == v2) { /* term match? */
1758
PC = (PC + 1) & VAMASK;
1761
if (intrq) { /* int pending? */
1762
PC = err_PC; /* back up PC */
1768
case 030: /* ISY 105770 (OP_N) */
1769
YR = (YR + 1) & DMASK; /* incr YR */
1770
if (YR == 0) PC = (PC + 1) & VAMASK; /* skip if zero */
1773
case 031: /* DSY 105771 (OP_N) */
1774
YR = (YR - 1) & DMASK; /* decr YR */
1775
if (YR == 0) PC = (PC + 1) & VAMASK; /* skip if zero */
1778
case 032: /* JPY 105772 (OP_C) */
1779
op[0] = (op[0] + YR) & VAMASK; /* index, no indir */
1780
mp_dms_jmp (op[0]); /* validate jump addr */
1782
PC = op[0]; /* jump */
1785
case 033: /* SBS 105773 (OP_KA) */
1786
WriteW (op[1], ReadW (op[1]) | op[0]); /* set bits */
1789
case 034: /* CBS 105774 (OP_KA) */
1790
WriteW (op[1], ReadW (op[1]) & ~op[0]); /* clear bits */
1793
case 035: /* TBS 105775 (OP_KK) */
1794
if ((op[1] & op[0]) != op[0]) /* test bits */
1795
PC = (PC + 1) & VAMASK;
1798
case 036: /* CMW 105776 (OP_KV) */
1799
wc = ReadW (op[1]); /* get continuation count */
1800
if (wc == 0) wc = op[0]; /* none? get initiation count */
1801
while (wc != 0) { /* while count */
1802
WriteW (op[1], wc); /* for abort */
1803
v1 = ReadW (AR & VAMASK); /* first op */
1804
v2 = ReadW (BR & VAMASK); /* second op */
1805
sop1 = (int32) SEXT (v1); /* signed */
1806
sop2 = (int32) SEXT (v2);
1807
if (sop1 != sop2) { /* compare */
1808
PC = (PC + 1 + (sop1 > sop2)) & VAMASK;
1809
BR = (BR + wc) & DMASK; /* update BR */
1810
wc = 0; /* clr interim */
1813
AR = (AR + 1) & DMASK; /* incr src1 */
1814
BR = (BR + 1) & DMASK; /* incr src2 */
1815
wc = (wc - 1) & DMASK; /* decr cnt */
1816
if (intrq && wc) { /* intr, more to do? */
1817
PC = err_PC; /* back up PC */
1821
WriteW (op[1], wc); /* clean up inline */
1824
case 037: /* MVW 105777 (OP_KV) */
1825
wc = ReadW (op[1]); /* get continuation count */
1826
if (wc == 0) wc = op[0]; /* none? get initiation count */
1827
if ((wc & SIGN) && (UNIT_CPU_TYPE == UNIT_TYPE_2100))
1828
break; /* < 0 is NOP for 2100 IOP */
1829
while (wc != 0) { /* while count */
1830
WriteW (op[1], wc); /* for abort */
1831
t = ReadW (AR & VAMASK); /* move word */
1832
WriteW (BR & VAMASK, t);
1833
AR = (AR + 1) & DMASK; /* incr src */
1834
BR = (BR + 1) & DMASK; /* incr dst */
1835
wc = (wc - 1) & DMASK; /* decr cnt */
1836
if (intrq && wc) { /* intr, more to do? */
1837
PC = err_PC; /* back up PC */
1841
WriteW (op[1], wc); /* clean up inline */
1844
default: /* all others NOP */
1851
/* Get instruction operands
537
/* Read a multiple-precision operand value. */
539
OP ReadOp (uint32 va, OPSIZE precision)
544
if (precision == in_s)
545
operand.word = ReadW (va); /* read single integer */
547
else if (precision == in_d)
548
operand.dword = ReadW (va) << 16 | /* read double integer */
549
ReadW ((va + 1) & VAMASK); /* merge high and low words */
552
for (i = 0; i < (uint32) precision; i++) { /* read fp 2 to 5 words */
553
operand.fpk[i] = ReadW (va);
554
va = (va + 1) & VAMASK;
559
/* Write a multiple-precision operand value. */
561
void WriteOp (uint32 va, OP operand, OPSIZE precision)
565
if (precision == in_s)
566
WriteW (va, operand.word); /* write single integer */
568
else if (precision == in_d) {
569
WriteW (va, (operand.dword >> 16) & DMASK); /* write double integer */
570
WriteW ((va + 1) & VAMASK, operand.dword & DMASK); /* high word, then low word */
574
for (i = 0; i < (uint32) precision; i++) { /* write fp 2 to 5 words */
575
WriteW (va, operand.fpk[i]);
576
va = (va + 1) & VAMASK;
582
/* Get instruction operands.
1853
584
Operands for a given instruction are specifed by an "operand pattern"
1854
585
consisting of flags indicating the types and storage methods. The pattern
1855
586
directs how each operand is to be retrieved and whether the operand value or
1856
587
address is returned in the operand array.
1858
Eight operand encodings are defined:
1860
Code Operand Description Example Return
1861
------ ----------------------------- ----------- ------------
1862
OP_NUL No operand present [inst] None
1864
OP_CON Inline constant [inst] Value of C
1867
OP_VAR Inline variable [inst] Address of V
1870
OP_ADR Address [inst] Address of A
1875
OP_ADK Address of a 1-word constant [instr] Value of K
1880
OP_ADF Address of a 2-word constant [inst] Value of F
1885
OP_ADX Address of a 3-word constant [inst] Value of X
1890
OP_ADT Address of a 4-word constant [inst] Value of T
589
Typically, a microcode simulation handler will define an OP_PAT array, with
590
each element containing an operand pattern corresponding to the simulated
591
instruction. Operand patterns are defined in the header file accompanying
592
this source file. After calling this function with the appropriate operand
593
pattern and a pointer to an array of OPs, operands are decoded and stored
594
sequentially in the array.
596
The following operand encodings are defined:
598
Code Operand Description Example Return
599
------ ---------------------------------------- ----------- ------------
600
OP_NUL No operand present [inst] None
602
OP_IAR Integer constant in A register LDA I Value of I
607
OP_DAB Double integer constant in A/B registers DLD J Value of J
612
OP_FAB 2-word FP constant in A/B registers DLD F Value of F
617
OP_CON Inline 1-word constant [inst] Value of C
621
OP_VAR Inline 1-word variable [inst] Address of V
625
OP_ADR Inline address [inst] Address of A
630
OP_ADK Address of integer constant [inst] Value of K
635
OP_ADD Address of double integer constant [inst] Value of D
640
OP_ADF Address of 2-word FP constant [inst] Value of F
645
OP_ADX Address of 3-word FP constant [inst] Value of X
650
OP_ADT Address of 4-word FP constant [inst] Value of T
655
OP_ADE Address of 5-word FP constant [inst] Value of E
1895
660
Address operands, i.e., those having a DEF to the operand, will be resolved
1896
661
to direct addresses. If an interrupt is pending and more than three levels