Files
x86_microcode/80386/microcode_notes.txt
T
2026-05-23 11:01:52 +01:00

2905 lines
226 KiB
Plaintext

000 // RESET - Probably CPU starts here after reset and there is 1 empty uop for random logic things to settle
001 IND = LDTR; goto BOOTUP // TODO: What is IND actually set to here? This is an LJUMP so this stomps alu2. Is this value actually used? Yes, to initialise CR3
002 COUNTR = 0x29; OPR_W = 0; // TODO: Why set OPR_W here? Are we going to do a bus access? (386EX doesn't do any before first instruction fetch)
------------------------------------------|----------------------------------------------------------------------------------------------
003 SIGMA = SRCREG; RNI; // 0 MOV r,r
004 DSTREG = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
005 SIGMA = IMM; RNI; // 0 MOV r,i
006 DSTREG = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
007 DSTREG = SEGREG; RNI; // 0 MOV(ZX) rw,segreg
008
------------------------------------------|----------------------------------------------------------------------------------------------
009 SIGMA = DSTREG; DES_SR.BASE = DSTREG << 4; RnI; DLY; // 0 r MOV ES/SS/DS/FS/GS,rw Use of RnI here suppresses interrupts for the next instruction? DES_SR == DES_ES, DES_SS, DES_DS, DES_FS or DES_GS depending on the operand?
00A SEGREG = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
00B if (PM) goto PM_LD_SS; RD_W; // 1 MOV SS,mw RD_W triggers a 16-bit read from the bus
00C PTR = &DES_SR; PTSAV7 TST_DES_SS; DLY; // TST_DES_SS goes to PROT_TESTS_PASSED (KN) (RETURNs) or #SS(I0,E0) or continues. Must continue in !PROTECTED_MODE case, so the other cases only happen in PM_LD_SS
00D DES_SR.BASE = OPR_R << 4; SIGMA = OPR_R; RnI; UNL;
00E SEGREG = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
00F if (PM) goto PM_LD_DSESFSGS; RD_W; // 1 MOV ES/DS/FS/GS,mw
010 PTR = &DES_SR; PTSAV1 TST_DES_SIMPLE; DLY; // TST_DES_SIMPLE goes to #NP(I0,E0) or PROT_TESTS_PASSED (N) (RETURNs) or continues
011 DES_SR.BASE = OPR_R << 4; SIGMA_OPR_R; UNL; RNI;
012 SEGREG = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
013 OPR_W = SRCREG; WR; RNI; // 1 MOV [i],A MOV m,r
014 DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
015 OPR_W = IMM; WR; RNI; // 1 MOV m,i
016 DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
017 OPR_W = SEGREG; WR_W; RNI; // 1 MOV mw,segreg
018 DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
019 RD; // 1 MOV A,[i] MOV r,m
01A DLY;
01B RNI;
01C DSTREG = OPR_R; UNL;
------------------------------------------|----------------------------------------------------------------------------------------------
01D SIGMA = DSTREG +-&|^ SRCREG; RNI; // 0 ADD/OR/ADC/SBB/AND/SUB/XOR r,r
01E DSTREG = SIGMA:
------------------------------------------|----------------------------------------------------------------------------------------------
01F SIGMA = DSTREG CMPTST SRCREG; RNI; // 0 CMP r,r TEST r,r
020
------------------------------------------|----------------------------------------------------------------------------------------------
021 SIGMA = ++--~- DSTREG; RNI; // 0 INC/DEC/NOT/NEG r
022 DSTREG = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
023 SIGMA = DSTREG +-&|^ IMM; RNI; // 0 ADD/OR/ADC/SBB/AND/SUB/XOR r,i
024 DSTREG = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
025 SIGMA = DSTREG CMPTST IMM; RNI; // 0 CMP/TEST A,i
026
------------------------------------------|----------------------------------------------------------------------------------------------
027 RD; // 1 ADD/OR/ADC/SBB/AND/SUB/XOR r,m
028 DLY;
029 TMPB = OPR_R; UNL;
02A SIGMA = DSTREG +-&|^ TMPB; RNI;
02B DSTREG = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
02C RD; // 1 CMP r,m
02D DLY;
02E TMPB = OPR_R; UNL;
02F SIGMA = DSTREG CMPTST TMPB; RNI;
030
------------------------------------------|----------------------------------------------------------------------------------------------
031 RD; // 1 CMP/TEST m,i
032 DLY;
033 SIGMA = OPR_R CMPTST IMM; RNI; UNL;
034
------------------------------------------|----------------------------------------------------------------------------------------------
035 RD; // 1 CMP/TEST m,r
036 DLY;
037 SIGMA = OPR_R CMPTST SRCREG; RNI; UNL;
038
------------------------------------------|----------------------------------------------------------------------------------------------
039 RD; FLAGSB = EFLAGS; RD; // 9 ADD/OR/ADC/SBB/AND/SUB/XOR m,i
03A DLY;
03B TMPB = OPR_R; UNL; goto WRITE_RESULT;
03C SIGMA = TMPB +-&|^ IMM;
------------------------------------------|----------------------------------------------------------------------------------------------
03D if (!cond) goto SETCONDR_FALSE; // 0 SETcond rb
03E BITS8;
03F SIGMA = 1; RNI;
040 DSTREG = 1;
------------------------------------------|----------------------------------------------------------------------------------------------
041 SETCONDR_FALSE: DSTREG = 0; RNI;
042
------------------------------------------|----------------------------------------------------------------------------------------------
043 if (!cond) goto SETCONDM_FALSE; // 1 SETcond mb
044 BITS8;
045 SIGMA = 1;
046 WRITE_RESULT: OPR_W = SIGMA; WR; RNI;
047 DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
048 SETCONDM_FALSE: OPR_W = 0; WR; RNI;
049 DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
04A FLAGSB = EFLAGS; FLAGS_BACKED_UP = true; RD; // 9 ADD/OR/ADC/SBB/AND/SUB/XOR m,r
04B DLY;
04C TMPB = OPR_R; UNL; goto WRITE_RESULT;
04D SIGMA = TMPB +-&|^ SRCREG;
------------------------------------------|----------------------------------------------------------------------------------------------
04E RD; // 9 INC/DEC/NOT/NEG m
04F DLY; goto WRITE_RESULT;
050 SIGMA = ++--~- OPR_R; UNL;
------------------------------------------|----------------------------------------------------------------------------------------------
051 COUNTR = eCX; DLY; // 0 JeCXZ cb
052 DESCOD; SIGMA = EIP + IMM8; IND_DELTA = IMM8; IND = EIP + IND_DELTA;
053 if (COUNTR != 0) goto Jcond_DONE; // COUNTR == 0 case goes to 054 (no RNI), 055, 056 (delay slot - RNI), 069 - RNi is RNI but only if it's executed in the delay slot
054 RNi; PREF; // COUNTR != 0 case goes to 054 (delay slot - RNI), 069 PREF starts prefetch at IND? Only if not in delay slot? Is PREF just an optimisation hint?
055 eIP = SIGMA; DLY; goto Jcond_DONE;
056 RNi;
------------------------------------------|----------------------------------------------------------------------------------------------
057 COUNTR = eCX; DLY; // 0 LOOP cb
058 DESCOD; SIGMA = EIP + IMM8; IND_DELTA = IMM8; IND = EIP + IND_DELTA;
059 if (COUNTR == 1) goto LOOP_UNTAKEN; // COUNTR != 1 case goes to 05A (PREF at EIP + IMM8, COUNTR = -1), 05B (sets EIP = EIP + IMM8), 05C (ECX = -1, delay slot = RNI), 069
05A --COUNTR; PREF; // COUNTR == 1 case goes to 05A (PREF at EIP + IMM8, --COUNTR), 05D (IND = EIP), 05E (delay slot, SIGMA = EIP, PREF at EIP), 05B (sets EIP = EIP), 05C (RNi), 069
05B LOOP_DONE: eIP = SIGMA; DLY; goto Jcond_DONE;
05C eCX = COUNTR; RNi;
------------------------------------------|----------------------------------------------------------------------------------------------
05D LOOP_UNTAKEN: DESCOD; IND = EIP; DLY; goto LOOP_DONE;
05E SIGMA = EIP; PREF; // If PREF is suppressed in delay slot, then it never has an effect here
------------------------------------------|----------------------------------------------------------------------------------------------
05F COUNTR = eCX; DLY; // 0 LOOPE/LOOPNE cb
060 DESCOD; SIGMA = EIP + IMM8; IND_DELTA = IMM8; IND = EIP + IND_DELTA;
061 if (LOOPnE) goto LOOP_UNTAKEN; // This instruction is the same as LOOP apart from using LOOPnE instead of JCNTZ
062 --COUNTR; PREF;
063 eIP = SIGMA; DLY; goto Jcond_DONE;
064 eCX = COUNTR; RNi;
------------------------------------------|----------------------------------------------------------------------------------------------
065 DESCOD; DLY; IND_DELTA = IMM8?; IND = EIP + IND_DELTA; if (!cond) goto Jcond_DONE; // 0 Jcond cb/cv From other routines, we'd think that IND = EIP + EBX here. Not sure what's going on
066 SIGMA = EIP + IMM8; RNi; PREF; // If PREF actually runs in the non-taken case, then perhaps it stops prefetching and writes to EIP (or RNI) restart it.
067 JMP_PREFINAL: DLY; // in that case, why modify IND at all? It might be dead code - they might have previously started prefetching at IND but there were too many bugs so they said "screw it, we'll just start prefetching at the new EIP when it's written to - that's guaranteed to work".
068 JMP_FINAL: eIP = SIGMA; RNI;
069 Jcond_DONE:
------------------------------------------|----------------------------------------------------------------------------------------------
06A DESCOD; IND_DELTA = IMM8; IND = EIP + IND_DELTA; SIGMA = ESP + IMM8; DLY; // 0 JMP c
06B JMP_PREF: PREF; JMP JMP_FINAL;
06C DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
06D DESCOD; IND = DSTREG; DLY; goto JMP_PREFINAL; // 0 r JMP rmv
06E SIGMA = DSTREG; PREF;
------------------------------------------|----------------------------------------------------------------------------------------------
06F RD; // 1 m JMP rmv
070 DLY; goto JMP_PREF;
071 DESCOD; IND = OPR_R; SIGMA = OPR_R; UNL;
------------------------------------------|----------------------------------------------------------------------------------------------
072 SIGMA += IMM; RD; // 3 RET/RET iw
073 eSP = SIGMA; DLY; goto JMP_PREF;
074 DESCOD; IND = OPR_R; SIGMA = OPR_R; UNL;
------------------------------------------|----------------------------------------------------------------------------------------------
075 OPR_W = EIP; WR; // 2 CALL cw
076 DESCOD; IND_DELTA = IMM8; IND = EIP + IND_DELTA; DLY;
077 eSP = SIGMA; PREF; goto JMP_FINAL;
078 SIGMA = EIP + IMM8; DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
079 OPR_W = EIP; WR; // 2 r CALL rmv
07A DESCOD; IND = DSTREG; DLY; goto JMP_PREFINAL;
07B eSP = SIGMA; SIGMA = DSTREG; PREF;
------------------------------------------|----------------------------------------------------------------------------------------------
07C RD; // 1 m CALL rmv
07D DESSTK; IND_DELTA = NEGWSZ; IND = ESP + IND_DELTA; SIGMA = ESP + NEGWSZ; DLY;
07E OPR_W = EIP; WR;
07F eSP = SIGMA; DLY; goto JMP_PREF;
080 DESCOD; IND = OPR_R; SIGMA = OPR_R; UNL;
------------------------------------------|----------------------------------------------------------------------------------------------
081 RD; // 1 m PUSH rmv
082 DESSTK; IND_DELTA = NEGWSZ; IND = ESP + IND_DELTA; SIGMA = ESP + NEGWSZ; DLY;
083 eSP = SIGMA; wr;
084 RNI; DLY;
085 OPR_R; UNL; // Weird - OPR_R source doesn't seem to be used?
------------------------------------------|----------------------------------------------------------------------------------------------
086 OPR_W = DSTREG; WR; RNI; // 2 r PUSH rmv/rv
087 eSP = SIGMA; DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
088 SIGMA = ESP - BITS_V; DLY; // 0 PUSHAd
089 DESSTK; IND_DELTA = -1; IND = SIGMA + IND_DELTA; SIGMA -= 1; // IND = ESP - (BITS_V + 1) SIGMA = ESP - (BITS_V + 1)
08A OPR_W = EDI; COUNTR = 6; WR; // Write eDI first (last in the PUSH sequence, lowest address) COUNTR = 6 => ESI
08B IND_DELTA = WORDSZ; IND += IND_DELTA; DLY; // set IND for slot 1
08C OPR_W = IRF[COUNTR]; --COUNTR; WR; // Write eSI, COUNTR = 5
08D PUSHAd_LOOP:
08E IND += IND_DELTA; DLY; if (COUNTR != 0) goto PUSHAd_LOOP; // IND_DELTA set to WORDSZ at 08B
08F OPR_W = IRF[COUNTR]; --COUNTR; WR; RNI; // Write eBP, eSP, eBX, eDX, eCX, eAX decrease COUNTR to -1
090 eSP = SIGMA; DLY; // ESP -= (BITS_V + 1)
------------------------------------------|----------------------------------------------------------------------------------------------
091 eSP = SIGMA; COUNTR = 0x47; RD; // 3 POPA Read DI
092 POPAd_LOOP: DESSTK; IND = ESP; SIGMA = ESP + WORDSZ; DLY;
093 IRF[COUNTR] = OPR_R; UNL; RD; if ((COUNTR & 15) != 1) goto POPAd_LOOP;
094 eSP = SIGMA; --COUNTR; // Loop reading SI, BP, SP, BX, DX, CX, AX
095 DLY; RNI;
096 IRF[COUNTR] = OPR_R; UNL; // Store AX
------------------------------------------|----------------------------------------------------------------------------------------------
097 eSP = SIGMA; COUNTR = 7; RD; // 3 POPAD
098 DESSTK; IND = ESP; SIGMA = ESP + WORDSZ; DLY;
099 IRF = OPR_R; UNL; RD; goto POPAd_LOOP;
09A eSP = SIGMA; --COUNTR;
------------------------------------------|----------------------------------------------------------------------------------------------
09B OPR_W = SEGREG; WR_W; RNI; // 2 PUSH segreg
09C eSP = SIGMA; DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
09D OPR_W = IMM; WR; RNI; // 2 PUSH i
09E eSP = SIGMA; DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
09F eSP = SIGMA; RD; // 3 r POP rmv
0A0 RNI; DLY;
0A1 DSTREG = OPR_R; UNL;
------------------------------------------|----------------------------------------------------------------------------------------------
0A2 eSP = SIGMA; RD_W; // 3 POP SS
0A3 if (PM) goto PM_LD_SS;
0A4 PTR = &DES_SR; DLY; PTSAV7 TST_DES_SS; // TST_DES_SS goes to PROT_TESTS_PASSED (KN) (RETURNs) or #SS(I0,E0) or continues.
0A5 DES_SR.BASE = OPR_R << 4; SIGMA = OPR_R; UNL; RnI;
0A6 SEGREG = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
0A7 eSP = SIGMA; RD_W; // 3 POP ES/DS/FS/GS
0A8 if (PM) goto PM_LD_DSESFSGS;
0A9 PTR = &DES_SR; DLY; PTSAV1 TST_DES_SIMPLE; // TST_DES_SIMPLE goes to #NP(I0,E0) or PROT_TESTS_PASSED (N) (RETURNs) or continues
0AA DES_SR.BASE = OPR_R << 4; SIGMA = OPR_R; UNL; RNI;
0AB SEGREG = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
0AC eSP = SIGMA; RD; // 3 m POP rmv
0AD DES_OS; IND_DELTA = 0; IND = EA + IND_DELTA; DLY; // Why add 0?
0AE wr;
0AF DLY; RNI;
0B0 OPR_R; UNL; // Weird - OPR_R source doesn't seem to be used?
------------------------------------------|----------------------------------------------------------------------------------------------
0B1 rd; // 9 m XCHG rm,r
0B2 DLY
0B3 OPR_W = SRCREG; WR;
0B4 RNI; DLY;
0B5 SRCREG = OPR_R; UNL;
------------------------------------------|----------------------------------------------------------------------------------------------
0B6 COUNTR = SRCREG; SIGMA = DSTREG; // 0 r XCHG EAX,rv XCHG rm,r
0B7 DSTREG = COUNTR; RNI;
0B8 SRCREG = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
0B9 SRCREG = IRF2; IND_DELTA = 0; IND += IND_DELTA; RNI; // 1 m LEA rv,m Weird - why add 0?
0BA
------------------------------------------|----------------------------------------------------------------------------------------------
0BB SIGMA = 3; RD; // 1 m LDS rv,m Read offset
0BC IND_DELTA = WORDSZ; IND += IND_DELTA; DLY;
0BD RD_W; if (PM) goto PM_LDS; // Read segment
0BE TMPD = OPR_R; UNL; // TMPD = offset
0BF DLY; // This onwards is real mode only
0C0 DS = OPR_R; DS.BASE = OPR_R << 4; SIGMA = TMPD; UNL; RNI;
0C1 SRCREG = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
0C2 SIGMA = 0; RD; // 1 LES rv,m Can this SIGMA ever actually get used?
0C3 IND_DELTA = WORDSZ; IND += IND_DELTA; DLY;
0C4 RD_W; if (PM) goto PM_LES;
0C5 TMPD = OPR_R; UNL;
0C6 DLY;
0C7 ES = OPR_R; ES.BASE = OPR_R << 4; SIGMA = TMPD; UNL; RNI;
0C8 SRCREG = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
0C9 SIGMA = IMM ^ 0x10; RD; // 1 LSS rv,m
0CA COUNTR = SIGMA; IND_DELTA = WORDSZ; IND += IND_DELTA; DLY;
0CB RD_W; if (PM) goto PM_LSS;
0CC TMPD = OPR_R; UNL;
0CD DLY;
0CE IRF[COUNTR] = OPR_R; IRF[COUNTR].BASE = OPR_R << 4; SIGMA = TMPD; UNL; RNI; // COUNTR must be 0x22 for SS so IMM must be 0x32. Not sure why we can't just use SS directly like in LES. Maybe this code was shared with LSS until they realised that needed different protection tests?
0CF SRCREG = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
0D0 SIGMA = IMM ^ 0x10; RD; // 1 LFS/LGS rv,m
0D1 COUNTR = SIGMA; IND_DELTA = WORDSZ; IND += IND_DELTA; DLY;
0D2 RD_W; if (PM) goto PM_LFS_LGS;
0D3 TMPD = OPR_R; UNL;
0D4 DLY;
0D5 IRF[COUNTR] = OPR_R; IRF[COUNTR].BASE = OPR_R << 4; SIGMA = TMPD; UNL; RNI; // COUNTR must be 0x24/0x25 for FS/GS so IMM must be 0x34/0x35.
0D6 SRCREG = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
0D7 SIGMA = EFLAGS & 0x37fd7; RNI; // 0 LAHF
0D8 AH = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
0D9 BITS8; // 0 SAHF Need BITS8 here so that eDX_AH refers to AH
0DA eDX_AH = FLAGSL; RNI;
0DB
------------------------------------------|----------------------------------------------------------------------------------------------
0DC if (PM && CPL > 0) goto NO_PRIVILEGE; // 0 CLTS
0DD SIGMA = -1 ^ 8; // SIGMA = -9 = 0xfffffff7
0DE TMPB = SIGMA;
0DF SIGMA = CR0 & TMPB; RNI;
0E0 CR0 = SIGMA; // Turn off bit 3 in CR0 = TS "Task switched" Allows saving x87 task context upon a task switch only after x87 instruction used
------------------------------------------|----------------------------------------------------------------------------------------------
0E1 if (!C) goto SALC_DONE; // 0 SALC
0E2 AL = 0; RNi; // !C case: 0e2 (RNi) AL = 0, 0e4
0E3 AL = -1; RNI; // C case: 0e2 (delay slot - RNi has no effect), 0e3 (RNI) AL = -1, 0e4
0E4 SALC_DONE:
------------------------------------------|----------------------------------------------------------------------------------------------
0E5 COUNT5 = IMM; SIGMA = BITS_V; // 0 r RCL/RCR rm,ib
0E6 SIGMA += 1;
0E7 TMPB = SIGMA; goto RCLRCR_R_COMM;
0E8 TMPC = COUNTR; SIGMA = COUNTR - TMPB;
------------------------------------------|----------------------------------------------------------------------------------------------
0E9 COUNT5 = ECX; SIGMA = BITS_V; // 0 r RCL/RCR rm,CL
0EA SIGMA += 1;
0EB TMPB = SIGMA;
0EC TMPC = COUNTR; SIGMA = COUNTR - TMPB; // TMPC = c = amount to shift by SIGMA = c - (BITS_V + 1) Why compute this and then not use it?
0ED RCLRCR_R_COMM: TMPD = DSTREG; SIGMA = DSTREG <<>>? TMPC;
0EE TMPE = SIGMA; if (G) goto RCLRCR_R_LOOP;
0EF SIGMA = TMPE >><<? TMPD; RNI;
0F0 DSTREG = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
0F1 RCLRCR_R_LOOP: SIGMA = TMPC - TMPB;
0F2 TMPC = SIGMA; SIGMA -= TMPB;
0F3 SIGMA = -1 <<>>? BITS_V;
0F4 SIGMA = (TMPE:TMPD) >> SHRCNT; // No BSRU/BSLU/BSRM/BSLM - implicit default or from the another alu op?
0F5 TMPD = TMPE; if (G) goto RCLRCR_R_LOOP;
0F6 TMPE = SIGMA; SIGMA = SIGMA <<>>? TMPC;
0F7 SIGMA = TMPE >><<? TMPD; RNI;
0F8 DSTREG = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
0F9 SIGMA = DSTREG <<>>? IMM; // 0 r ROL/ROR/SHL/SHR/SAR rm,ib
0FA SIGMA = SIGMA >><<? DSTREG; RNI;
0FB DSTREG = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
0FC SIGMA = DSTREG <<>>? IMM; // 0 r SHxD rmv,rv,ib
0FD SIGMA = SRCREG >><<? DSTREG; RNI;
0FE DSTREG = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
0FF SIGMA = DSTREG <<>>? ECX; // 0 r ROL/ROR/SHL/SHR/SAR rm,CL
100 SIGMA = SIGMA >><<? DSTREG; RNI;
101 DSTREG = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
102 SIGMA = DSTREG <<>>? ECX; // 0 r SHxD rmv,rv,CL
103 SIGMA = SRCREG >><<? DSTREG; RNI;
104 DSTREG = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
105 SIGMA = DSTREG <<>>? 1; // 0 r rot rm,1
106 SIMA = SIGMA >><<? DSTREG; RNI;
107 DSTREG = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
108 COUNT5 = IMM; SIGMA = BITS_V; RD; // 1 m RCL/RCR rm,ib
109 SIGMA = SIGMA + 1;
10A TMPB = SIGMA; DLY; goto RCLRCR_M_COMM;
10B TMPC = COUNTR; SIGMA = COUNTR - TMPB;
------------------------------------------|----------------------------------------------------------------------------------------------
10C COUNT5 = ECX; SIGMA = BITS_V; RD; // 1 m RCL/RCR rm,CL
10D SIGMA += 1;
10E TMPB = SIGMA; DLY;
10F TMPC = COUNTR; SIGMA = COUNTR - TMPB;
110 RCLRCR_M_COMM: TMPD = OPR_R; SIGMA = OPR_R <<>>? TMPC; UNL; CW;
111 TMPE = SIGMA; DLY; if (G) goto RCLRCR_M_LOOP;
112 SIGMA = TMPE >><<? TMPD;
113 OPR_W = SIGMA; WR; RNI;
114 DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
115 RCLRCR_M_LOOP: SIGMA = TMPC - TMPB;
116 TMPC = SIGMA; SIGMA -= TMPB;
117 SIGMA = -1 <<>>? BITS_V;
118 SIGMA = (TMPE:TMPD) >> SHRCNT; // No BSRU/BSLU/BSRM/BSLM - implicit default or from the another alu op?
119 TMPD = TMPE; if (G) goto RCLRCR_M_LOOP;
11A TMPE = SIGMA; SIGMA = SIGMA <<>>? TMPC;
11B SIGMA = TMPE >><<? TMPD;
11C OPR_W = SIGMA; WR; RNI;
11D DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
11E TMPC = IMM; RD; // 1 ROL/ROR/SHL/SHR/SAR m,ib
11F FLAGSB = EFLAGS; FLAGS_BACKED_UP = true; DLY;
120 ROSHSA_M_COMM: TMPC = OPR_R; SIGMA = OPR_R <<>>? TMPC; UNL;
121 SIGMA = SIGMA >><<? TMPB;
122 OPR_W = SIGMA; WR; RNI;
123 DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
124 TMPC = IMM; RD; // 1 SHxD mv,rv,ib
125 FLAGSB = EFLAGS; FLAGS_BACKED_UP = true; DLY;
126 SHxD_M_COMM: TMPB = OPR_R; SIGMA = OPR_R <<>>? TMPC; UNL;
127 SIGMA = SRCREG >><<? TMPB;
128 OPR_W = SIGMA; WR; RNI;
129 DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
12A SIGMA = 1; RD; // 1 rot m,1
12B TMPC = SIGMA; goto ROSHSA_M_COMM;
12C FLAGSB = EFLAGS; FLAGS_BACKED_UP = true; DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
12D TMPC = ECX; RD; goto ROSHSA_M_COMM; // 1 ROL/ROR/SHL/SHR/SAR m,CL
12E FLAGSB = EFLAGS; FLAGS_BACKED_UP = true; DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
12F TMPC = ECX; RD; goto SHxD_M_COMM; // 1 SHxD mv,rv,CL
130 FLAGSB = EFLAGS; FLAGS_BACKED_UP = true; DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
131 SHRCNT = SRCREG & BITS_V; // 0 BT rv,rv
132 SIGMA = (DSTREG:DSTREG) >> SHRCNT; CF = SIGMA & 1; RNI;
133
------------------------------------------|----------------------------------------------------------------------------------------------
134 SIGMA = SIGN SRCREG; // 1 BT m,rv
135 SHRCNT = 3;
136 SIGMA = (SIGMA:SRCREG) >> SHRCNT;
137 SIGMA &= NEGWSZ;
138 TMPB = SIGMA;
139 IND_DELTA = TMPB; IND += IND_DELTA; DLY;
13A RD;
13B DLY;
13C TMPB = OPR_R; SHRCNT = SRCREG & BITS_V; UNL;
13D SIGMA = (TMPB:TMPB) >> SHRCNT; CF = SIGMA & 1; RNI;
13E
------------------------------------------|----------------------------------------------------------------------------------------------
13F SHRCNT = IMM & BITS_V; // 0 BT rv,ib
140 SIGMA = (DSTREG:DSTREG) >> SHRCNT; CF = SIGMA & 1; RNI; // SIGMA not used, only CF updated
141
------------------------------------------|----------------------------------------------------------------------------------------------
142 RD; // 1 BT m,ib
143 DLY;
144 TMPB = OPR_R; SHRCNT = IMM & BITS_V; UNL;
145 SIGMA = (TMPB:TMPB) >> SHRCNT; CF = SIGMA & 1; RNI;
146
------------------------------------------|----------------------------------------------------------------------------------------------
147 SHRCNT = SRCREG & BITS_V; // 0 BTS/BTR/BTC rv,rv
148 SIGMA = (DSTREG:DSTREG) >> SHRCNT; CF = SIGMA & 1; // This must do a rotate as well as setting CF
149 SIGMA = SIGMA SERECO 1; // SERECO must set, reset or complement bit 0 must leave CF alone
14A TMPB = SIGMA; SHLCNT = SRCREG & BITS_V;
14B SIGMA = (TMPB:TMPB) << SHLCNT; RNI; // Rotate bit 0 back into position rv must leave CF alone
14C DSTREG = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
14D SIGMA = SIGN SRCREG; // 9 BTS/BTR/BTC m,rv sign-extend 8/16-bit inputs to 32 bits?
14E SHRCNT = 3;
14F SIGMA = (SIGMA:SRCREG) >> SHRCNT; // SIGMA = SRCREG >> 3 using arithmetic shift = byte offset
150 SIGMA = SIGMA & NEGWSZ; // clear low bit or 2 bits (align SIGMA)
151 TMPB = SIGMA; SIGMA = 1;
152 IND_DELTA = TMPB; IND += IND_DELTA; DLY; // IND = address to access
153 SHLCNT = SRCREG & BITS_V; RD; // bit within vword
154 SIGMA = (SIGMA:1) << SHLCNT; // not sure why we use SIGMA in the high dword here
155 TMPB = SIGMA; SHRCNT = SRCREG & BITS_V; DLY; // TMPB = 1 shifted to the desired position
156 TMPC = OPR_R; SIGMA = OPR_R SERECO TMPB; UNL; // TMPC = read vword SIGMA = vword after set/reset/complement
157 OPR_W = SIGMA; WR; // Write back modified vword
158 SIGMA = (TMPC:TMPC) >> SHRCNT; CF = SIGMA & 1; DLY; RNI; // shift bit right again and test to set CF
159
------------------------------------------|----------------------------------------------------------------------------------------------
15A SHRCNT = IMM & BITS_V; // 0 BTS/BTR/BTC rv,ib
15B SIGMA = (DSTREG:DSTREG) >> SHRCNT;
15C SIGMA = SIGMA SERECO 1;
15D TMPB = SIGMA; SHLCNT = IMM & BITS_V;
15E SIGMA = (TMPB:TMPB) << SHLCNT; RNI;
15F DSTREG = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
160 SIGMA = 1; RD; // 9 BTS/BTR/BTC m,ib
161 SHLCNT = IMM & BITS_V;
162 SIGMA = (SIGMA:1) << SHLCNT; // Seems like this must be size-sensitive since ib is taken modulo bitsize
163 TMPB = SIGMA; SHRCNT = IMM & BITS_V; DLY;
164 TMPC = OPR_R; SIGMA = OPR_R SERECO TMPB; UNL;
165 OPR_W = SIGMA; WR;
166 SIGMA = (TMPC:TMPC) >> SHRCNT; DLY; RNI;
167
------------------------------------------|----------------------------------------------------------------------------------------------
168 TMPB = DSTREG; COUNTR = BITS_V; // 0 BSF rv,rv
169 BSF_COMMON: SIGMA = 0 CMP TMPB;
16A TMPE = COUNTR; SHRCNT = 0; // TMPE = BITS_V
16B if (!C) goto BSF_DONE: // if (DSTREG == 0) goto BSF_DONE? (only 1 (empty) line at BSF_DONE actually executed due to RNi at 16c)
16C SIGMA = (0:TMPB) >> SHRCNT; CF = SIGMA & 1; RNi; // SHRCNT is 0 here so CF = TMPB & 1
16D SHRCNT = 1;
16E if (!C) goto BSF_LOOP; // if ((TMPB & 1) == 0) goto BSF_LOOP;
16F SIGMA = (0:TMPB) >> SHRCNT; // SIGMA = TMPB >> 1
170 SRCREG = 0; CLZF; RNI; // The ZF flag is cleared if the bits are all 0
171 BSF_DONE:
172 BSF_LOOP: --COUNTR;
173 TMPB = SIGMA; if (!C) goto BSF_LOOP;
174 TMPC = COUNTR; SIGMA = COUNTR BITTST TMPB; // SHRCNT is 1 here
175 SIGMA = TMPE CMP TMPC; RNI;
176 SRCREG = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
177 RD; // 1 BSF rv,mv
178 DLY; goto BSF_COMMON;
179 TMPB = OPR_R; COUNTR = BITS_V; UNL;
------------------------------------------|----------------------------------------------------------------------------------------------
17A TMPB = DSTREG; COUNTR = BITS_V; // 0 BSR rv,rv
17B BSR_COMMON: SIGMA = 0 CMP TMPB;
17C SHLCNT = 1;
17D if (!C) goto BSR_DONE;
17E SIGMA = 0 CMP 0; RNi;
17F BSR_LOOP: SRCREG = TMPC; SIGMA = TMPC >><<? TMPB;
180 TMPC = COUNTR; if (!C) goto BSR_LOOP;
181 TMPB = SIGMA; --COUNTR;
182 CLZF; RNI;
183 BSR_DONE:
------------------------------------------|----------------------------------------------------------------------------------------------
184 RD; // 1 BSR rv,mv
185 DLY; goto BSR_COMMON;
186 TMPB = OPR_R; COUNTR = BITS_V; UNL;
------------------------------------------|----------------------------------------------------------------------------------------------
187 BITS8; // 0 AAA/AAS presumably BITS8 is needed to avoid some special-casing for AAAAAS in the ALU
188 SIGMA = EAX;
189 SIGMA = AAAAAS SIGMA; RNI;
18A AX = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
18B BITS8; // 0 DAA/DAS presumably BITS8 is needed to avoid some special-casing for DAADAS in the ALU
18C SIGMA = EAX;
18D SIGMA = DAADAS SIGMA; RNI;
18E AL = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
18F BITS8; // 0 AAM ib
190 MDTMP4 = EAX_AL; COUNTR = 7;
191 SIGMA = 0;
192 TMPB = IMM;
193 SIGMA = SIGMA DIV7 TMPB; RPT; DLY; // Meat of the division algorithm
194 SIGMA = SIGMA DIV5 TMPB;
195 SIGMA = SIGMA; // Not sure why this is here. ALU needs an extra cycle?
196 AH = MDTMP;
197 SIGMA = SIGMA + 0 + CF; RNI; // The SF, ZF, and PF flags are set according to the resulting binary value in the AL register. The OF, AF, and CF flags are undefined.
198 AL = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
199 BITS8; // 0 AAD ib
19A MDTMP = IMM; COUNTR = 7;
19B TMPB = eDX_AH; SIGMA = 0;
19C SIGMA = SIGMA IMUL3 TMPB; RPT; DLY; // Meat of the multiplication algorithm
19D SIGMA = SIGMA; // Not sure why this is here. ALU needs an extra cycle?
19E TMPD = COUNTR;
19F TMPC = MDTMP; SHRCNT = TMPD & BITS_V;
1A0 TMPD = SIGMA; SIGMA = (SIGMA:TMPC) >> SHRCNT; // Shift right by number of remaining bits in COUNTR
1A1 TMPB = SIGMA;
1A2 SIGMA = EAX_AL + TMPB + CF; // {-0D-} must be an addition. Possibly ADC and we know that CF = 0
1A3 AH = 0; RNI;
1A4 AL = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
1A5 MDTMP = DSTREG; COUNTR = BITS_V; // 0 MUL/IMUL r
1A6 TMPB = EAX_AL; SIGMA = 0;
1A7 iMUL_COMMON: SIGMA = SIGMA IMUL3 TMPB; RPT; DLY; // iMUL_COMMON implements the parts of MUL/IMUL common to both register and memory versions
1A8 SIGMA = SIGMA; // Not sure why this is here. ALU needs an extra cycle?
1A9 TMPD = COUNTR; // TMPD = remaining_bits
1AA TMPC = MDTMP; SHRCNT = TMPD & BITS_V;
1AB TMPD = SIGMA; SIGMA = (SIGMA:TMPC) >> SHRCNT; // SIGMA = (SIGMA:TMPC) >> remaining_bits
1AC eAX_AL = SIGMA; SIGMA = SZ_EX2 TMPD; // {-07-} corrects for sign in IMUL case? Only used here - presumably looks at modrm byte bit 3 to determine SX or ZX whereas SZ_EXT looks at opcode byte bit 3
1AD SIGMA = (SIGMA:TMPD) >> SHRCNT; RNI; // SIGMA = (SIGMA:TMPD) >> remaining_bits
1AE eDX_AH = SIGMA; // eDX_AH = upper part of result
------------------------------------------|----------------------------------------------------------------------------------------------
1AF TMPB = EAX_AL; RD; COUNTR = BITS_V; // 1 MUL/IMUL m
1B0 DLY;
1B1 MDTMP = OPR_R; UNL; goto iMUL_COMMON;
1B2 SIGMA = 0;
------------------------------------------|----------------------------------------------------------------------------------------------
1B3 MDTMP = DSTREG; COUNTR = BITS_V; // 0 IMUL rv,rv
1B4 TMPB = SRCREG; SIGMA = 0;
1B5 IMUL2_COMMON: SIGMA = SIGMA IMUL4 TMPB; RPT; DLY; // Meat of the multiplication algorithm
1B6 SIGMA = SIGMA; // Not sure why this is here. ALU needs an extra cycle?
1B7 TMPD = COUNTR;
1B8 TMPC = MDTMP; SHRCNT = TMPD & BITS_V;
1B9 TMPD = SIGMA; SIGMA = (SIGMA:TMPC) >> SHRCNT; // Shift right by number of remaining bits in COUNTR
1BA SRCREG = SIGMA; SIGMA = SIGMA IMCS TMPD; // IMCS corrects for sign always? Only used here
1BB SIGMA = (SIGMA:TMPD) >> SHRCNT; RNI; // Dead code? Seems like we could have RNIed a couple of cycles earlier. Needed for flags?
1BC
------------------------------------------|----------------------------------------------------------------------------------------------
1BD COUNTR = BITS_V; RD; // 1 IMUL rv,mv
1BE TMPB = SRCREG; DLY;
1BF MDTMP = OPR_R; UNL; goto IMUL2_COMMON;
1C0 SIGMA = 0;
------------------------------------------|----------------------------------------------------------------------------------------------
1C1 MDTMP = IMM; COUNTR = BITS_V; RD; // 1 IMUL rv,mv,i
1C2 DLY; goto IMUL2_COMMON;
1C3 TMPB = OPR_R; SIGMA = 0; UNL;
------------------------------------------|----------------------------------------------------------------------------------------------
1C4 MDTMP = IMM; COUNTR = BITS_V; // 0 IMUL rv,rv,i
1C5 goto IMUL2_COMMON;
1C6 TMPB = DSTREG; SIGMA = 0;
------------------------------------------|----------------------------------------------------------------------------------------------
1C7 MDTMP4 = EAX_AL; COUNTR = BITS_V; // 0 DIV r
1C8 SIGMA = EDX_AH;
1C9 TMPB = DSTREG;
1CA DIV_COMMON: SIGMA = SIGMA DIV7 TMPB; RPT; DLY; // Meat of the division algorithm
1CB SIGMA = SIGMA DIV5 TMPB;
1CC SIGMA = SIGMA; // Not sure why this is here. ALU needs an extra cycle?
1CD EAX_AL = MDTMP; RNI;
1CE EDX_AH = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
1CF MDTMP4 = EAX_AL; COUNTR = BITS_V; RD; // 1 DIV m
1D0 SIGMA = EDX_AH;
1D1 DLY; goto DIV_COMMON;
1D2 TMPB = OPR_R; UNL;
------------------------------------------|----------------------------------------------------------------------------------------------
1D3 SIGMA = -1 + BITS_V; // 0 IDIV r
1D4 COUNTR = SIGMA;
1D5 SIGMA = EDX_AH;
1D6 MDTMP4 = EAX_AL;
1D7 TMPB = DSTREG;
1D8 IDIV_COMMON: SIGMA = SIGMA IDIV0 TMPB; // First iteration is different for IDIV? Hence COUNTR being one less
1D9 SIGMA = SIGMA DIV7 TMPB; RPT; DLY; // Meat of the division algorithm
1DA SIGMA = SIGMA DIV5 TMPB;
1DB SIGMA = SIGMA IDIV1 TMPB; // Correct for signs?
1DC SIGMA = SIGMA; // Not sure why this is here. ALU needs an extra cycle?
1DD TMPB = SIGMA;
1DE SIGMA = MDTMP IDIV2; // More correcting for signs?
1DF EDX_AH = TMPB; RNI;
1E0 EAX_AL = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
1E1 SIGMA = BITS_V - 1; RD; // 1 IDIV m
1E2 COUNTR = SIGMA;
1E3 SIGMA = EDX_AH;
1E4 MDTMP4 = EAX_AL; DLY; goto IDIV_COMMON;
1E5 TMPB = OPR_R;
------------------------------------------|----------------------------------------------------------------------------------------------
1E6 SIGMA = SIGN EAX; RNI; // 0 CWD / CDQ
1E7 EDX = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
1E8 SIGMA = SZ_EXT DSTREG; // 0 r CBW / CWDE MOVZX/MOVSX r,rm (16-bit?)
1E9 BITS16; RNI;
1EA SRCREG = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
1EB RD; // 1 m MOVZX/MOVSX r,rm (16-bit?)
1EC DLY;
1ED SIGMA = SZ_EXT OPR_R; UNL;
1EE BITS16; RNI;
1EF SRCREG = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
1F0 SIGMA = SZ_EXT DSTREG; // 0 r CBW / CWDE MOVZX/MOVSX r,rm (32-bit?)
1F1 BITS32; RNI;
1F2 SRCREG = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
1F3 RD; // 1 m MOVZX/MOVSX r,rm (32-bit?)
1F4 DLY;
1F5 SIGMA = SZ_EXT OPR_R; UNL;
1F6 BITS32; RNI;
1F7 SRCREG = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
1F8 COUNTR = eCX; // 0 REP MOVS
1F9 REPF = true;
1FA if (COUNTR != 0) goto REP_MOVS_NOT0;
1FB DES_OS; IND = ESI; SIGMA = ESI + INCREM; DLY; RNI; // RNI is suppressed if it's in the delay slot
1FC
------------------------------------------|----------------------------------------------------------------------------------------------
1FD REP_MOVS_NOT0: TMPB = SIGMA; --COUNTR; RD;
1FE DES_ES; IND = EDI; SIGMA = EDI + INCREM; DLY;
1FF TMPC = SIGMA; wr; if (COUNTR == 0) goto REP_MOVS_DONE; // jump if interrupt requested? No, see 250. Jump if COUNTR == 0?
200 DES_OS; IND = TMPB; SIGMA = TMPB + INCREM; DLY;
201 REP_MOVS_LOOP: TMPB = SIGMA; --COUNTR; RD;
202 DES_ES; IND = TMPC; SIGMA = TMPC + INCREM; DLY;
203 TMPC = SIGMA; UNL; wr; if (COUNTR != 0 && !INTERRUPT_REQUESTED) goto REP_MOVS_LOOP; // {-47-} aka JCNZNI (only used here) must test both conditions since it's the only test in the loop
204 DES_OS; IND = TMPB; SIGMA = TMPB + INCREM; DLY;
205 REP_MOVS_DONE: eCX = COUNTR; if (COUNTR != 0) goto REP_MOVS_RPTI;
206 eDI = TMPC; SIGMA = TMPB; UNL; RNI; // RNI suppressed if in delay slot
207 REP_MOVS_RPTI: eSI = SIGMA;
208 RPTI: DESCSW; IND = TMPeIP; SIGMA = 0xffff; DLY;
209 SIGMA += 1; // SIGMA = 0x10000
20A TMPB = SIGMA; // TMPB = 0x10000
20B SIGMA = EFLAGS | TMPB; // SIGMA = EFLAGS | 0x10000
20C EFLAGS = SIGMA; // EFLAGS |= 0x10000 Turn on resume flag
20D EIP = TMPeIP; PREF;
20E DLY;
20F RNI;
210
------------------------------------------|----------------------------------------------------------------------------------------------
211 DES_OS; IND = ESI; SIGMA = ESI + INCREM; DLY; // 0 MOVS
212 TMPB = SIGMA; RD;
213 DES_ES; IND = EDI; SIGMA = EDI + INCREM; DLY;
214 wr;
215 DLY;
216 eSI = TMPB; UNL; RNI;
217 eDI = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
218 COUNTR = eCX; // 0 REP CMPS
219 // blank line must be needed between COUNTR load and test
21A if (COUNTR != 0) goto REP_CMPS_NOT0;
21B DES_ES; IND = EDI; SIGMA = EDI + INCREM; DLY; RNI;
21C REP_CMPS_DONE: // Just a convenient place for the jumps on lines 21e and 227 to have their destinations
21D REP_CMPS_LOOP: eSI = TMPD; --COUNTR;
21E eCX = COUNTR; if (LOOPnE) goto REP_CMPS_DONE; // The goto here is just so that the RNi on line 21f will be activated
21F eDI = TMPB; SIGMA = TMPB + INCREM; DLY; RNi;
220 REP_CMPS_NOT0: TMPB = SIGMA; RD;
221 DES_OS; IND = ESI; SIGMA = ESI + INCREM; DLY;
222 TMPD = SIGMA; RD;
223 TMPC = OPR_R; UNL;
224 DES_ES; IND = TMPB; DLY; if (!INTERRUPT_REQUESTED) goto REP_CMPS_LOOP;
225 SIGMA = OPR_R CMP TMPC; UNL;
226 eSI = TMPD; --COUNTR;
227 eCX = COUNTR; if (LOOPnE) goto REP_CMPS_DONE; // The goto here is just so that the RNi on line 228 will be activated
228 TMPB = eDI; IND_DELTA = INCREM; IND += IND_DELTA; SIGMA = eDI + INCREM; DLY; RNi;
229 goto RPTI;
22A
------------------------------------------|----------------------------------------------------------------------------------------------
22B DES_ES; IND = EDI; SIGMA = EDI + INCREM; DLY; // 0 CMPS
22C TMPB = SIGMA; RD;
22D DES_OS; IND = ESI; SIGMA = ESI + INCREM; DLY;
22E RD;
22F TMPC = OPR_R; UNL;
230 DLY;
231 eDI = TMPB;
232 eSI = SIGMA;
233 SIGMA = OPR_R CMP TMPC; UNL; RNI;
234
------------------------------------------|----------------------------------------------------------------------------------------------
235 COUNTR = eCX; // 0 REP SCAS
236
237 if (COUNTR != 0) goto REP_SCAS_NOT0;
238 DES_ES; IND = EDI; SIGMA = EDI + INCREM; DLY; RNI;
239 REP_SCAS_DONE: // Just a convenient place for the jumps on lines 23b and 243 to have their destinations
23A REP_SCAS_LOOP: --COUNTR;
23B eCX = COUNTR; if (LOOPnE) goto REP_SCAS_DONE; // The goto here is just so that the RNi on line 23c will be activated
23C DES_ES; IND = EDI; SIGMA = EDI + INCREM; DLY; RNi;
23D REP_SCAS_NOT0: RD;
23E DLY;
23F eDI = SIGMA;
240 TMPC = OPR_R; UNL; if (!INTERRUPT_REQUESTED) goto REP_SCAS_LOOP;
241 SIGMA = EAX CMP TMPC;
242 --COUNTR;
243 eCX = COUNTR; if (LOOPnE) goto REP_SCAS_DONE; // The goto here is just so that the RNi on line 244 will be activated
244 RNi;
245 goto RPTI;
246
------------------------------------------|----------------------------------------------------------------------------------------------
247 DES_ES; IND = EDI; SIGMA = EDI + INCREM; DLY; // 0 SCAS
248 RD;
249 DLY;
24A eDI = SIGMA;
24B TMPB = OPR_R; UNL;
24C SIGMA = EAX CMP TMPB; RNI;
24D
------------------------------------------|----------------------------------------------------------------------------------------------
24E COUNTR = eCX; goto REP_LODS_LOOP; // 0 REP LODS pointless goto?
24F REP_LODS_DONE: // Just a convenient place for the jumps on lines 250 and 256 to have their destinations
250 REP_LODS_LOOP: eCX = COUNTR; if (COUNTR == 0) goto REP_LODS_DONE; // The goto here is just so that the RNi on line 251 will be activated
251 DES_OS; IND = ESI; SIGMA = ESI + INCREM; DLY; RNi;
252 --COUNTR; RD;
253 DLY;
254 eSI = SIGMA; if (!INTERRUPT_REQUESTED) goto REP_LODS_LOOP;
255 eAX_AL = OPR_R; UNL;
256 eCX = COUNTR; if (COUNTR == 0) goto REP_LODS_DONE; // Jump if COUNTR == 0? The goto here is just so that the RNi on line 257 will be activated
257 DES_OS; IND = ESI; SIGMA = ESI + INCREM; RNi; DLY;
258 goto RPTI;
259
------------------------------------------|----------------------------------------------------------------------------------------------
25A DES_OS; IND = ESI; SIGMA = ESI + INCREM; DLY; // 0 LODS
25B RD;
25C DLY;
25D eSI = SIGMA; RNI;
25E eAX_AL = OPR_R; UNL;
------------------------------------------|----------------------------------------------------------------------------------------------
25F DES_OS; IND_DELTA = EBX; IND = eAX_AL + IND_DELTA; DLY; // 0 XLATB
260 RD;
261 DLY; RNI;
262 eAX_AL = OPR_R; UNL;
------------------------------------------|----------------------------------------------------------------------------------------------
263 COUNTR = eCX; goto REP_STOS_LOOP; // 0 REP STOS
264 REP_STOS_DONE: // Just a convenient place for the jumps on lines 265 and 26a to have their destinations
265 REP_STOS_LOOP: eCX = COUNTR; if (COUNTR == 0) goto REP_STOS_DONE; // Jump if COUNTR == 0? The goto here is just so that the RNi on line 266 will be activated
266 DES_ES; IND = EDI; SIGMA = EDI + INCREM; DLY; RNi;
267 OPR_W = EAX; --COUNTR; WR;
268 DLY; if (!INTERRUPT_REQUESTED) goto REP_STOS_LOOP;
269 eDI = SIGMA;
26A eCX = COUNTR; if (COUNTR == 0) goto REP_STOS_DONE; // Jump if COUNTR == 0? The goto here is just so tha tthe RNi on line 26b will be activated
26B DES_ES; IND = EDI; SIGMA = EDI + INCREM; DLY; RNi;
26C goto RPTI;
26D
------------------------------------------|----------------------------------------------------------------------------------------------
26E DES_ES; IND = EDI; SIGMA = EDI + INCREM; DLY; // 0 STOS
26F OPR_W = EAX; WR;
270 DLY; RNI;
271 eDI = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
272 if (CPL <= IOPL) goto IN_IMM_NOCHK // 0 p IN A,ib
273 DES_IO; IND = IMM; SIGMA = IMM; DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
274 PORTIO_PROTCHK(); // 0 r IN A,ib
275 DES_IO; SIGMA = IMM; IND = IMM; DLY;
276 IN_IMM_NOCHK: RD;
277 DLY; RNI;
278 IN_DONE: EAX = OPR_R; UNL;
------------------------------------------|----------------------------------------------------------------------------------------------
279 if (CPL <= IOPL) goto IN_DX_NOCHK; // 0 p IN A,DX
27A SIGMA = EDX & 0xffff; // 0 r IN A,DX
27B PORTIO_PROTCHK();
27C IN_DX_NOCHK: DES_IO; IND = SIGMA; DLY;
27D RD; goto IN_DONE;
27E DLY; RNi;
------------------------------------------|----------------------------------------------------------------------------------------------
27F if (CPL <= IOPL) goto INS_NOCHK; // 0 p INS
280 DES_ES; DLY; IND = EDI;
------------------------------------------|----------------------------------------------------------------------------------------------
281 PORTIO_PROTCHK(); // 0 r INS
282 SIGMA = EDX & 0xffff;
283 DES_ES; IND = EDI; DLY;
284 INS_NOCHK: SIGMA = EDX & 0xffff; CW;
285 DES_IO; IND = SIGMA; DLY;
286 RD;
287 DES_ES; IND = EDI; SIGMA = EDI + INCREM; DLY;
288 wr; UNL; RNI;
289 eDI = SIGMA; DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
28A if (CPL <= IOPL) goto REP_INS_NOCHK; // 0 p REP INS
28B COUNTR = eCX; // 0 r REP INS
28C PORTIO_PROTCHK();
28D REP_INS_NOCHK: SIGMA = EDX & 0xffff;
28E TMPC = SIGMA; if (COUNTR != 0) goto REP_INS_NOT0;
28F DES_ES; IND = EDI; SIGMA = EDI + INCREM; DLY; RNI;
290 REP_INS_DONE: eCX = COUNTR;
291 REP_INS_LOOP: eDI = SIGMA; UNL; wr; if (COUNTR == 0) goto REP_INS_DONE;
292 DES_ES; IND = EDI; SIGMA = EDI + INCREM; DLY; RNi;
293 REP_INS_NOT0: eCX = COUNTR; --COUNTR; CW;
294 DES_IO; IND = TMPC; DLY;
295 RD; if (!INTERRUPT_REQUESTED) goto REP_INS_LOOP;
296 DES_ES; DLY; IND = EDI;
297 eDI = SIGMA; UNL; wr; if (COUNTR == 0) goto REP_INS_DONE;
298 DES_ES; SIGMA = EDI + INCREM; IND = EDI; DLY; RNi;
299 goto RPTI;
29A eCX = COUNTR;
------------------------------------------|----------------------------------------------------------------------------------------------
29B if (CPL <= IOPL) goto OUT_IMM_NOCHK; // 0 p OUT ib,A
29C DES_IO; SIGMA = IMM; IND = IMM; DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
29D PORTIO_PROTCHK(); // 0 r OUT ib,A
29E DES_IO; SIGMA = IMM; IND = IMM; DLY;
29F OUT_IMM_NOCHK: OPR_W = EAX; WR; RNI;
2A0 DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
2A1 if (CPL <= IOPL) goto OUT_DX_NOCHK; // 0 p OUT DX,A
2A2 SIGMA = EDX & 0xffff; // 0 r OUT DX,A
2A3 PORTIO_PROTCHK();
2A4 OUT_DX_NOCHK: DES_IO; DLY; IND = SIGMA;
2A5 OPR_W = EAX; WR; RNI;
2A6 DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
2A7 if (CPL <= IOPL) goto OUTS_NOCHK; // 0 p OUTS
2A8 DES_OS; SIGMA = ESI + INCREM; IND = ESI; DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
2A9 PORTIO_PROTCHK(); // 0 r OUTS
2AA SIGMA = EDX & 0xffff;
2AB DES_OS; SIGMA = ESI + INCREM; IND = ESI; DLY;
2AC OUTS_NOCHK: TMPB = SIGMA; RD;
2AD SIGMA = EDX & 0xffff;
2AE DES_IO; IND = SIGMA; DLY;
2AF eSI = TMPB; wr; UNL; RNI;
2B0 DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
2B1 if (CPL <= IOPL) goto REP_OUTS_NOCHK; // 0 p REP OUTS
2B2 COUNTR = eCX; // 0 r REP OUTS
2B3 PORTIO_PROTCHK();
2B4 REP_OUTS_NOCHK: SIGMA = EDX & 0xffff;
2B5 TMPC = SIGMA; if (COUNTR != 0) goto REP_OUTS_NOT0;
2B6 DES_OS; SIGMA = ESI + INCREM; IND = ESI; DLY; RNI;
2B7 REP_OUTS_DONE: // Just a convenient place for the jumps on lines 2b8 and 2bd to have their destinations
2B8 REP_OUTS_LOOP: DES_OS; DLY; IND = TMPB; if (COUNTR == 0) goto REP_OUTS_DONE; // The goto here is just so that the RNi on line 2b9 will be activated
2B9 eSI = TMPB; SIGMA = TMPB + INCREM; UNL; RNi;
2BA REP_OUTS_NOT0: TMPB = SIGMA; --COUNTR; RD;
2BB DES_IO = TMPC; IND = TMPC; DLY; if (!INTERRUPT_REQUESTED) goto REP_OUTS_LOOP;
2BC eCX = COUNTR; wr;
2BD DES_OS; IND = TMPB; DLY; if (COUNTR == 0) goto REP_OUTS_DONE; // The goto here is just so that the RNi on line 2bd will be activated
2BE eSI = TMPB; SIGMA = TMPB + INCREM; UNL; RNi;
2BF goto RPTI;
2C0
------------------------------------------|----------------------------------------------------------------------------------------------
2C1 PORTIO_PROTCHK: if (PM && CPL > 0) goto IO_PERM_BITMAP; // Skip IO permission bitmap check in real mode case (in protected mode case we've already checked for CPL <= IOPL and skipped calling this routine if so)
2C2 TMPB = SIGMA; SIGMA = NEGWSZ; // TMPB = IO_PORT (to check)
2C3 goto PORTIO_ALLOWED;
2C4 IO_PERM_BITMAP: SIGMA += NEGWSZ; // SIGMA = 2*NEGWSZ
2C5 TMPD = SIGMA; SIGMA = 6; // TMPD = 2*NEGWSZ (So -2, -4 or -8 depending on word size i.e. 0xfffffffe, 0xfffffffc or 0xfffffff8)
2C6 DES_TR; IND_DELTA = 0x60; IND = SIGMA + IND_DELTA; BITS32; DLY; // Access TSS. IND = 0x66 = address of I/O MAP BASE pointer in TSS
2C7 SLCTR2 = 0; SHRCNT = 3; RD_W; // Read IO_MAP_BASE
2C8 PROTUN = 0; SIGMA = (0:TMPB) >> SHRCNT; // SIGMA = TMPB >> 3 = byte in bitmap to look at
2C9 TMPC = SIGMA; DLY; PTGEN READ_RPL; // (L) TMPC = TMPB >> 3 From APRL it seems like READ_RPL copies PROTUN.RPL into latch. So this zeroes latch - what for? We don't do anything else with latch here. Used for privilege level check in TST_POIRTIO_BIT?
2CA SIGMA = OPR_R & 0xffff; UNL;
2CB DES_TR; DLY; IND_DELTA = TMPC; IND = SIGMA + IND_DELTA; // IND = (TMPB >> 3) + IO_MAP_BASE
2CC SIGMA = TMPB & 7; RD_W; // SIGMA = bit address within byte Read a word because our mask might straddle 2 bytes
2CD TMPC = SIGMA; if (BITS == 16) goto PORTIO_16BIT; // TMPC = TMPB & 7 Why, in 16-bit mode, do we skip the shift and looking at the value from the bitmap? - seems like this will cause it to always fault
2CE SIGMA = TMPD ^ -1; // SIGMA = ~(2*NEGWSZ) = 1, 3 or 7 = mask to test against. Hmm, shouldn't it be 15 in the dword case? Is NEGWSZ -8 in this case rather than -4?
2CF TMPD = SIGMA; SHLCNT = TMPC & 0x1f; // TMPD = ~(2*NEGWSZ)
2D0 SIGMA = (0:TMPD) << SHLCNT; // SIGMA = (~(2*NEGWSZ)) << (IO_PORT & 7) Surprising that the read bit mask word isn't shifted right instead
2D1 TMPD = SIGMA; BITSDE; DLY; // TMPD = (~(2*NEGWSZ)) << (IO_PORT & 7)
2D2 SIGMA = OPR_R & TMPD; UNL; // SIGMA = OPR_R & ((~(2*NEGWSZ)) << (IO_PORT & 7)) = masked bits
2D3 PORTIO_16BIT: PROTUN = SIGMA; PTSELA TST_PORTIO_BIT; // TST_PORTIO_BITMAP can continue (if both bits b and e are 1) or go to #GP(0) (otherwise) Test here should be SIGMA != 0
2D4 PORTIO_ALLOWED: RETURN;
2D5 DES_IO; SIGMA = TMPB; IND = TMPB;
------------------------------------------|----------------------------------------------------------------------------------------------
2D6 if (PM) goto CALL_FAR_PM; // 2 CALL cp
2D7 TMPG = IMM; COUNTR = IMM8; // COUNTR is the selector of the destination in CALL_FAR_PM, and TMPG is the offset
2D8 OPR_W = CS; WR; goto CALL_FAR_RM;
2D9 DLY; IND_DELTA = NEGWSZ; IND += IND_DELTA;
------------------------------------------|----------------------------------------------------------------------------------------------
2DA RD; // 1 CALL mp
2DB IND_DELTA = WORDSZ; IND += IND_DELTA; DLY;
2DC TMPG = OPR_R; UNL; RD_W;
2DD DLY; if (PM) goto CALL_FAR_PM;
2DE COUNTR = OPR_R; UNL; // COUNTR is the selector of th destination in CALL_FAR_PM, and TMPG is the offset
2DF DESSTK; SIGMA = ESP + NEGWSZ; DLY; IND_DELTA = NEGWSZ; IND = ESP + IND_DELTA;
2E0 OPR_W = CS; WR;
2E1 IND_DELTA = NEGWSZ; IND += IND_DELTA; DLY;
2E2 CALL_FAR_RM: SIGMA += NEGWSZ;
2E3 OPR_W = EIP; WR; goto JUMP_FAR_RM;
2E4 eSP = SIGMA; DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
2E5 if (PM) goto JUMP_FAR_PM; // 0 JMP cp
2E6 TMPG = IMM; COUNTR = IMM8; // TMPG is the new offset, COUNTR is the new segment/selector
2E7 IRF2 = DES_CS.AR; DLY; // Real mode handling
2E8 SIGMA = IRF2 & 0xffff0000; // Keep base address bits 24-31, G, DB, A, Limit bits 16-19. Clear P/DPL/S/Type and base address 16-23
2E9 SIGMA |= 0x8200; // Set to P=1, DPL=0, S=0, Type=2 (LDT)?
2EA DES_CS.AR = SIGMA; DLY; // Setting limit bits 16..19, A, DB, G, and base bits 24..31 as well?
2EB JMP_FAR_RM: IRF2 = DES_CS.LIMIT; DLY;
2EC TMPB = IRF2;
2ED JMP_FAR_RM_1: DES_CS.BASE = COUNTR << 4; SIGMA = COUNTR; // Seems like SBRM doesn't change AR field SIGMA = segment
2EE DES_CS.LIMIT = TMPB; // Re-install limit?
2EF PAGER5.PCR; // paging hint? It'd have to be DES_CS.BASE + TMPG
2F0 JMP_FAR_COMMON: DESCOD; DLY; IND = TMPG;
2F1 JMP_FAR_DONE: eIP = TMPG; PREF; // Start prefetching before CS set? Or does it not take effect for a couple of cycles?
2F2 PROTUN = 0; DLY; // Why do we set PROTUN here?
2F3 CS = SIGMA; RNI;
2F4
------------------------------------------|----------------------------------------------------------------------------------------------
2F5 RD; // 1 JMP mp
2F6 IND_DELTA = WORDSZ; IND += IND_DELTA; DLY;
2F7 TMPG = OPR_R; UNL; RD_W;
2F8 DLY; if (PM) goto JUMP_FAR_PM;
2F9 COUNTR = OPR_R; UNL;
2FA IRF2 = DES_CS.LIMIT; DLY; goto JMP_FAR_RM_1;
2FB TMPB = IRF2;
------------------------------------------|----------------------------------------------------------------------------------------------
2FC SIGMA += WORDSZ; RD; // 3 RETF/RETF iw
2FD IND_DELTA = WORDSZ; IND += IND_DELTA; DLY;
2FE SIGMA += IMM; RD;
2FF TMPG = OPR_R; UNL;
300 DLY; if (PM) goto RETF_PM;
301 COUNTR = OPR_R; UNL;
302 eSP = SIGMA; goto JMP_FAR_RM;
303
------------------------------------------|----------------------------------------------------------------------------------------------
304 ENTER_COMMON(); // 2 ENTER (16-bit?)
305 eSP = SIGMA; SIGMA = IMM8; // Seems like this PASS2 is immediately overwritten? No, this happens before ENTER_COMMON()
306 SIGMA = TMPC; DLY; RNI;
307 BP = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
308 ENTER_COMMON(); // 2 ENTER (32-bit?) Why are these separate routines?
309 eSP = SIGMA; SIGMA = IMM8;
30A SIGMA = TMPC; DLY; RNI;
30B EBP = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
30C ENTER_COMMON: COUNT5 = SIGMA;
30D SIGMA = ESP - IMM;
30E OPR_W = EBP; WR; if (COUNTR == 0) goto ENTER_DONE;
30F DLY; if (COUNTR == 1) goto ENTER_LASTW;
310 IND_DELTA = NEGWSZ; IND += IND_DELTA; SIGMA += NEGWSZ;
311 DESSTK; SIGMA = EBP + NEGWSZ; IND_DELTA = NEGWSZ; IND = EBP + IND_DELTA;
312 TMPB = SIGMA; --COUNTR; RD;
313 DESSTK; SIGMA = ESP + NEGWSZ; IND_DELTA = NEGWSZ; IND = ESP + IND_DELTA;
314 eSP = SIGMA; wr; if (COUNTR == 1) goto ENTER_LAST;
315 DESSTK; SIGMA = TMPB + NEGWSZ; DLY; IND_DELTA = NEGWSZ; IND = TMPB + IND_DELTA;
316 ENTER_LOOP: TMPB = SIGMA; --COUNTR; RD;
317 DESSTK; SIGMA = ESP + NEGWSZ; IND_DELTA = NEGWSZ; IND = ESP + IND_DELTA; DLY;
318 eSP = SIGMA; if (COUNTR != 1) goto ENTER_LOOP; UNL; wr;
319 DESSTK; SIGMA = TMPB + NEGWSZ; IND_DELTA = NEGWSZ; IND = TMPB + IND_DELTA; DLY; // Pointless ADD and IN=+? Not if the jump to 316 is taken
31A ENTER_LAST: DESSTK; SIGMA = ESP + NEGWSZ; IND_DELTA = NGEWSZ; IND = ESP + IND_DELTA; UNL;
31B SIGMA -= IMM;
31C ENTER_LASTW: OPR_W = TMPC; WR;
31D ENTER_DONE: DESSTK; IND = SIGMA; DLY; RETURN;
31E eSP = SIGMA; CW;
------------------------------------------|----------------------------------------------------------------------------------------------
31F DESSTK; SIGMA = EBP + WORDSZ; DLY; IND = EBP; DLY; // 0 LEAVE (16-bit?)
320 eSP = SIGMA; RD;
321 DLY; RNI;
322 BP = OPR_R; UNL;
------------------------------------------|----------------------------------------------------------------------------------------------
323 DESSTK; SIGMA = EBP + WORDSZ; DLY; IND = EBP; DLY; // 0 LEAVE (32-bit?) Why are these separate routines?
324 eSP = SIGMA; RD;
325 DLY; RNI;
326 EBP = OPR_R; UNL;
------------------------------------------|----------------------------------------------------------------------------------------------
327 if (PM && CPL > 0) goto NO_PRIVILEGE; // 0 HLT
328 DESABS; IND = 2; ICESIG; // ICESIG runs even in NO_PRIVILEGE case "For a halt condition, BE2# is active." (HRM 3.1.8)
329 HLT_SHUTDOWN: HLTS; // "A halt or shutdown signal is initiated by activatin ADS# and the bus status pins as follows: M/IO# and W/R# are driven high, and D/C# is driven low"
32A DLY;
32B RPT; WIO;
32C RNI;
32D
------------------------------------------|----------------------------------------------------------------------------------------------
32E PTR = &DESIDT; if (PM && CPL > 0) goto NO_PRIVILEGE; // 1 LIDT mw
32F SHLCNT = BITS_V;
330 RD_W; goto LIDTGDT_COMMON;
331 DLY; IND_DELTA = 2; IND += IND_DELTA;
------------------------------------------|----------------------------------------------------------------------------------------------
332 PTR = &DESGDT; if (PM && CPL > 0) goto NO_PRIVILEGE; // 1 LGDT mw
333 SHLCNT = BITS_V; // 15 or 31
334 RD_W;
335 IND_DELTA = 2; IND += IND_DELTA; DLY;
336 LIDTGDT_COMMON: SIGMA = (0xffffffff:0x000001ff) << SHLCNT; RD_D; // SIGMA = 0xffffffff (32-bit mode) or 0xffffff (16-bit mode)
337 TMPB = SIGMA;
338 SIGMA = OPR_R & 0xffff; UNL;
339 DESPTR->LIMIT = SIGMA; DLY;
33A SIGMA = OPR_R & TMPB; UNL;
33B DESPTR->BASE = SIGMA; RNI;
33C
------------------------------------------|----------------------------------------------------------------------------------------------
33D IRF2 = DESIDT.BASE; DLY; // 0 SIDT mw
33E TMPC = IRF2; goto SIDTGDT_COMMON;
33F IRF2 = DESIDT.LIMIT;
------------------------------------------|----------------------------------------------------------------------------------------------
340 IRF2 = DESGDT.BASE; DLY; // 0 SGDT mw
341 TMPC = IRF2;
342 IRF2 = DESGDT.LIMIT;
343 SIDTGDT_COMMON: TMPB = IRF2; // TMPB = limit, TMPC = base
344 DES_OS; IND_DELTA = 0; IND = EA + IND_DELTA; DLY; // Why set IND_DELTA = 0?
345 OPR_W = TMPB; WR_W;
346 IND_DELTA = 2; IND += IND_DELTA; DLY;
347 OPR_W = TMPC; WR_D; RNI;
348 DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
349 if (PM && CPL > 0) goto NO_PRIVILEGE; // 1 LMSW mw
34A SIGMA = CR0 & 1;
34B TMPB = SIGMA; RD_W;
34C DLY; goto LMSW_COMMON;
34D SIGMA = OPR_R | TMPB; UNL; // SIGMA = OPR_W | (CR0 & 1); Can't use LMSW to switch back to real mode
------------------------------------------|----------------------------------------------------------------------------------------------
34E if (PM && CPL > 0) goto NO_PRIVILEGE; // 0 LMSW rw
34F SIGMA = CR0 & 1;
350 SIGMA |= DSTREG; // SIGMA = (CR0 & 1) | DSTREG;
351 LMSW_COMMON: SIGMA &= 0x0f; // SIGMA = ((CR0 & 1) | rmw) & 0x0f
352 TMPB = SIGMA; // TMPB = ((CR0 & 1) | rmw) & 0x0f
353 SIGMA = -1 ^ 0x0f; // SIGMA = 0xfffffff0
354 TMPC = SIGMA; // TMPC = 0xfffffff0
355 SIGMA = CR0 & TMPC; // SIGMA = CR0 & 0xfffffff0
356 SIGMA |= TMPB; RNI; // SIGMA = (CR0 & 0xfffffff0) | (((CR0 & 1) | rmw) & 0x0f)
357 CR0 = SIGMA; // CR0 = (CR0 & 0xfffffff0) | (((CR0 & 1) | rmw) & 0x0f)
------------------------------------------|----------------------------------------------------------------------------------------------
358 DSTREG = CR0; RNI; // 0 SMSW rw
359
------------------------------------------|----------------------------------------------------------------------------------------------
35A OPR_W = CR0; WR_W; RNI; // 1 SMSW mw
35B DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
35C if (PM && CPL > 0) goto NO_PRIVILEGE; // 0 MOV CR0,rd
35D BITS32;
35E TMPB = SRCREG; SHLCNT = 1;
35F SIGMA = (TMPB:TMPB) << SHLCNT; // SIGMA = SRCREG rotl 1?
360 SIGMA &= 3; // SIGMA = (SRCREG rotl 1) & 3?
361 COUNTR = SIGMA; // COUNTR = (SRCREG rotl 1) & 3?
362 // Why do we have a blank line?
363 if (COUNTR == 1) goto PAGING_RM; // Setting system to real mode with paging?
364 SIGMA = TMPB; RNI;
365 CR0 = SIGMA;
366 PAGING_RM: goto #GP/#TS(I0,E0); // It's #GP here
367 SLCTR2 = 0; PTGEN SET_FAULT;
------------------------------------------|----------------------------------------------------------------------------------------------
368 if (PM && CPL > 0) goto NO_PRIVILEGE; // 0 MOV CR2,rd
369 BITS32;
36A CR2 = SRGREG; RNI; // CR2 is Page Fault Linear Address
36B
------------------------------------------|----------------------------------------------------------------------------------------------
36C if (PM && CPL > 0) goto NO_PRIVILEGE; // 0 MOV CR3,rd
36D BITS32;
36E DESABS; IND = SRCREG; // CR3 == PDBR == Page Directory Base Register
36F PDBR.PCR = IND; RNI; // Sets PDBR = SRCREG and flushes TLB cache (same as 794)
370 PDBR; DLY; // Not sure why we reference PDBR again again here
------------------------------------------|----------------------------------------------------------------------------------------------
371 goto STORE_CR; // 0 MOV rd,CR0 Not sure why we have this apparently pointless jump
372 SIGMA = CR0;
373 STORE_CR: if (PM && CPL > 0) goto NO_PRIVILEGE;
374 BITS32;
375 RNI;
376 DSTREG = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
377 goto STORE_CR; // 0 MOV rd,CR2
378 SIGMA = CR2;
------------------------------------------|----------------------------------------------------------------------------------------------
379 IRF2 = PDBR.PCR; goto STORE_CR; // 0 MOV rd,CR3
37A PDBR; SIGMA = IRF2; DLY; // Not sure why we reference PDBR again again here
------------------------------------------|----------------------------------------------------------------------------------------------
37B GENERAL_DETECT(); // 0 MOV DR4/6,rd
37C if (PM && CPL > 0) goto NO_PRIVILEGE;
37D DR6 = SRCREG; goto LD_DR4567_DONE; // Seems like we need an empty cycle in between loading a DR and the RNI
37E
------------------------------------------|----------------------------------------------------------------------------------------------
37F GENERAL_DETECT(); // 0 MOV DR5/7,rd
380 if (PM && CPL > 0) goto NO_PRIVILEGE;
381 DR7 = SRCREG;
382
383 LD_DR4567_DONE: RNI
384
------------------------------------------|----------------------------------------------------------------------------------------------
385 SELECT_DR_TR: SIGMA = (IMM:IMM) >> SHRCNT; // IMM here must be the modrm byte, not the opcode like in LSS/LFS/LGS SHRCNT is always 3 here
386 SIGMA &= 7;
387 SIGMA |= 0x70;
388 COUNTR = SIGMA; RETURN; // COUNTR vlues for DR/TR registers are 0x70-0x77
389
------------------------------------------|----------------------------------------------------------------------------------------------
38A GENERAL_DETECT(); // 0 MOV DR0-3,rd
38B if (PM && CPL > 0) goto no_PRIVILEGE;
38C SELECT_DR_TR(); // register-indexing bits are 3-5
38D SHRCNT = 3; // For use in SELECT_DR_TR
38E IRF[COUNTR].BASE = SRCREG; DLY;
38F DESABS; IND = 0; DLY; RNI; // Clear cached physical address? (maybe not, happens with "MOV rd,DR0-3" as well)
390
------------------------------------------|----------------------------------------------------------------------------------------------
391 if (PM && CPL > 0) goto NO_PRIVILEGE; // 0 MOV TRn,rd
392 BITS32;
393 SELECT_DR_TR();
394 SHRCNT = 3;
395 DESABS; DLY; IND = SRCREG; // TODO: compare this method of writing to TRn with methods of writing to other special registers, especially the ones involved in paging.
396 IRF[COUNTR].PCR; RNI;
397 IRF[COUNTR] = -1; DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
398 GENERAL_DETECT: BITS32;
399 TMPB = DR7; SHLCNT = 0x0d;
39A SIGMA = (0:1) << SHLCNT; // SIGMA = 1 << 13 = 0x2000
39B TMPC = SIGMA; SIGMA &= TMPB; // TMPC = 1 << 13 = 0x2000 SIGMA = DR7 & 0x2000
39C COUNTR = SIGMA; // COUNTR = DR7 & 0x2000
39D
39E if (COUNTR != 0) goto GD_HIT; // DR7 bit 13 is GD = General Detect Enable. If set, will cause a debug exception on any attempt at accessing the DR0-DR7 registers.
39F
3A0 RETURN;
3A1
------------------------------------------|----------------------------------------------------------------------------------------------
3A2 GD_HIT: EIP = TMPeIP; ICEBRK;
3A3 SIGMA = DR6 | TMPC;
3A4 goto BREAKPOINT_CMN;
3A5 DR6 = SIGMA; BITS32;
------------------------------------------|----------------------------------------------------------------------------------------------
3A6 GENERAL_DETECT(); // 0 MOV rd,DR4/6
3A7 if (PM && CPL > 0) goto NO_PRIVILEGE;
3A8 SIGMA = DR6; RNI; // RNI must be suppressed if it's in the delay slot
3A9 DSTREG = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
3AA GENERAL_DETECT(); // 0 MOV rd,DR5/7
3AB if (PM && CPL > 0) goto NO_PRIVILEGE;
3AC SIGMA = DR7; RNI;
3AD DSTREG = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
3AE GENERAL_DETECT(); // 0 MOV rd,DR0-3
3AF if (PM && CPL > 0) goto NO_PRIVILEGE;
3B0 SELECT_DR_TR();
3B1 SHRCNT = 3; DLY;
3B2 IRF2 = IRF[COUNTR].BASE;
3B3 DSTREG = IRF2;
3B4 DESABS; IND = 0; DLY; RNI;
3B5
------------------------------------------|----------------------------------------------------------------------------------------------
3B6 if (PM && CPL > 0) goto NO_PRIVILEGE; // 0 MOV rd,TRn
3B7 BITS32;
3B8 SELECT_DR_TR();
3B9 SHRCNT = 3; DLY;
3BA IRF2 = IRF[COUNTR].PCR;
3BB IRF[COUNTR] = IRF2; SIGMA = IRF2; DLY; RNI;
3BC DSTREG = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
3BD PROTUN = CR0; PTGEN FPU_WAIT; // 0 WAIT FPU_WAIT can go to #NM if TS && MP (g==1 && i==1) (#NM) or continue
3BE WAIT_LOOP: if (!BUSY# && !ERROR#) goto WAIT_DONE; // WAIT is supposed to wait until BUSY# is high, and #MF if ERROR#
3BF if (ERROR#) goto WAIT_ERRT; // 3c5 is a subroutine to help implement the test "if (JBUSY# && JPEREQ) goto #MF6"
3C0
3C1 WAIT_IRQT: if (!INTERRUPT_REQUESTED) goto WAIT_LOOP;
3C2
3C3 goto RPTI;
3C4
------------------------------------------|----------------------------------------------------------------------------------------------
3C5 WAIT_ERRT: if (!PEREQ) goto #MF6; // WAIT does #MF (Interrupt 0x10 Coprocessor Error) if the ERROR# input pin is asserted (i.e., the 80287 has detected an unmasked numeric error). Which of these is ERROR and what is the other?
3C6
3C7 goto WAIT_IRQT;
3C8 WAIT_DONE:
3C9 RNI;
3CA
------------------------------------------|----------------------------------------------------------------------------------------------
3CB #MF6: goto FAULT;
3CC SIGMA = 0x10; // "Interrupt 16 Coprocessor Error" (#MF)
------------------------------------------|----------------------------------------------------------------------------------------------
3CD PROTUN = CR0; PTGEN FPU_OTHER; // 0 FENI/FDISI/FCLEX/FINIT/FSETPM/FRSTPM FPU_OTHER goes to #NM or continues
3CE RPT; // Exhaust a cycle of the PTGEN?
3CF DES_IO; IND = 0x800000f8; DLY;
3D0 OPR_W = IMM; BITS32; WR_W;
3D1 FPU_FLAG_LOOP: ICESIG; DLY;
3D2
3D3 if (JICEWT) goto FPU_FLAG_LOOP;
3D4 DESCOD; IND = EIP;
3D5 PREF; // These instructions need to restart prefetching for some reason? Same reason that CLI/STI do?
3D6 DLY;
3D7 RNI;
3D8
------------------------------------------|----------------------------------------------------------------------------------------------
3D9 MISC1 = true; // 0 FSTCW/FSTSW mw
3DA PROTUN = CR0; PTGEN FPU_OTHER; // 0 FSTSW AX/FNSTDW AX (387SL only?)/FNSTSG AX (387SL only?) FPU_OTHER goes to #NM or continues
3DB FPU_MISC_WAIT: if (!PEREQ) goto FPU_MISC_CORE;
3DC
3DD // Why two blank lines? To avoid hitting the delay slots of the PTGEN on line 3da?
3DE if (!INTERRUPT_REQUESTED) goto FPU_MISC_WAIT;
3DF
3E0 goto RPTI;
3E1
------------------------------------------|----------------------------------------------------------------------------------------------
3E2 FPU_MISC_CORE: IND = 0x800000f8; SIGMA = 0x800000f8; DES_IO;
3E3 OPR_W = IMM; WR_W; // Write IMM to FPU command port
3E4 DES_IO; IND = SIGMA; DLY; if (MISC1) goto FPU_MISC_WRITE;
3E5 RD_W; // Read from FPU status port
3E6 DLY; RNI;
3E7 AX = OPR_R; UNL;
------------------------------------------|----------------------------------------------------------------------------------------------
3E8 FPU_MISC_WRITE: DES_OS; IND_DELTA = 0; IND = EA + IND_DELTA; DLY; // Why set IND_DELTA = 0? This handles FSTCW/FSTSW mw
3E9 wr_W; UNL; RNI;
3EA DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
3EB #MF5: goto FAULT; // Unreachable?
3EC SIGMA = 0x10; // "Interrupt 16 Coprocessor Error"
------------------------------------------|----------------------------------------------------------------------------------------------
3ED PROTUN = CR0; PTGEN FPU_OTHER; // 1 FSTENV m FPU_OTHER goes to #NM or continues
3EE DLY; goto FSAVE_WAIT;
3EF TMPG = IRF2; IND_DELTA = 0x0d; IND += IND_DELTA; MISC1 = true; // MISC1 is flag to say we're doing an FLDENV and not FRSTOR, tested by JMISC1 IND = dest + 0x0d
------------------------------------------|----------------------------------------------------------------------------------------------
3F0 PROTUN = CR0; PTGEN FPU_OTHER; // 1 FSAVE m FPU_OTHER goes to #NM or continues
3F1 DLY; goto FSAVE_WAIT; // pointless jump?
3F2 TMPG = IRF2; IND_DELTA = 0x5d; IND += IND_DELTA; // IND = dest + 0x5d
------------------------------------------|----------------------------------------------------------------------------------------------
3F3 FSAVE_WAIT: SIGMA = WORDSZ; // SIGMA = 2 or 4
3F4 if (!PEREQ) goto FSAVE_CORE; // JPEREQ is jump if FPU ready?
3F5 SHLCNT = 3;
3F6 if (!INTERRUPT_REQUESTED) goto FSAVE_WAIT;
3F7
3F8 goto RPTI;
3F9
------------------------------------------|----------------------------------------------------------------------------------------------
3FA FSAVE_CORE: SIGMA -= 2; // SIGMA = 0 or 2
3FB TMPC = SIGMA; // TMPC = 0 or 2
3FC SIGMA = (0:TMPC) << SHLCNT; // SIGMA = 0 or 16 SHLCNT is always 3 here
3FD SIGMA -= WORDSZ; // SIGMA = -2 or 12
3FE TMPC = SIGMA; BITS32; // TMPC = -2 or 12 BITS32 changes ALU but not WORDSZ or bus
3FF IND_DELTA = TMPC; IND += IND_DELTA; DLY; // IND = dest + (0x0d or 0x5d) + (-2 or 12)
400 SHRCNT = 0x10; CW_B; // limit should be (0x0d or 0x1b) for FSTENV or (0x5d or 0x6b) for FSAVE - IND here is (dest?+) (0x0b or 0x19) or (0x5b or 0x69) - two less than limit
401 DES_OS; IND = TMPG; DLY; // IND = IRF2
402 TMPC = CSOPCD; CW_B; // checking start as well?
403 DES_IO; IND = 0x800000f8; DLY;
404 OPR_W = IMM; WR_W; // Write opcode?
405 SIGMA = (0:TMPC) >> SHRCNT; // SIGMA = CSOPCD >> 16 = CS from CSOPCD?
406 TMPC = SIGMA; BITSDE; // TMPC = CSOPCD >> 16 = CS from CSOPCD?
407 FSAVE_COR_WAIT: if (!PEREQ) goto FSAVE_COR_WAIT;
408 TMPH = TMPG; // TMPH is detination that FSAVE_REGFILE writes to
409 FSAVE_REGFILE(); // First call to FSAVE_REGFILE has COUNTR = 3 and MISC2 = false => read 3 vwords and store (control/status/tag)
40A COUNTR = 3;
40B TMPB = TMPH; COUNTR = 4; // TMPB = dest + (6 or 12)
40C FSAVE_REGFILE(); // Second call to FSAVE_REGFILE has COUNTR = 4 and MISC2 = true => read 4 vwords and discard (?/?/?/?)
40D MISC2 = true;
40E if (PM) goto FSAVE_PM;
40F DES_OS; IND = TMPB; DLY;
410 SIGMA = CSOPCD & 0xffff; // Handle real mode case
411 TMPB = SIGMA; BITS32; // TMPB = opcode (from CSOPCD)
412 SHLCNT = 4;
413 SIGMA = (0:TMPB) << 4; // SIGMA = opcode << 4
414 TMPB = SIGMA; // TMPB = opcode << 4
415 SIGMA = FSVeIP + TMPB; // SIGMA = (opcode << 4) + eIP
416 TMPB = SIGMA; // TMPB = (opcode << 4) + eIP
417 SIGMA = (0:TMPC) << 4; // SIGMA = CS << 4
418 TMPC = SIGMA; // TMPC = CS << 4
419 SIGMA = OPROFF + TMPC; // SIGMA = OPROFF + (CS << 4)
41A TMPG = SIGMA; SHRCNT = 4; // TMPG = OPROFF + (CS << 4)
41B SIGMA = TMPG & 0xffff0000; // SIGMA = (OPROFF + (CS << 4)) & 0xffff0000
41C TMPD = SIGMA; // TMPD = (OPROFF + (CS << 4)) & 0xffff0000
41D SIGMA = (0:TMPD) >> 4; // SIGMA = ((OPROFF + (CS << 4)) & 0xffff0000) >> 4
41E TMPE = SIGMA; // TMPE = ((OPROFF + (CS << 4)) & 0xffff0000) >> 4
41F SIGMA = TMPB & 0xffff0000; // SIGMA = ((opcode << 4) + eIP) & 0xffff0000
420 TMPD = SIGMA; // TMPD = ((opcode << 4) + eIP) & 0xffff0000
421 SIGMA = (0:TMPD) >> 4; // SIGMA = (((opcode << 4) + eIP) & 0xffff0000) >> 4
422 TMPD = SIGMA; BITS16; // TMPD = (((opcode << 4) + eIP) & 0xffff0000) >> 4
423 TMPC = TMPF; SHLCNT = 8; // TMPC = TMPF (where does this come from?)
424 SIGMA = (TMPC:TMPC) << 8; // SIGMA = (TMPF << 8) - does this swap the bytes?
425 BITSDE; // Could this be restoring instruction's original bit size?
426 OPR_W = TMPB; WR; // Write (opcode << 4) + eIP should be Instruction Pointer lower word (seems like it puts other stuff at 0x0e in 32-bit mode)
427 SIGMA &= 0x7ff; // SIGMA = (TMPF << 8) & 0x7ff
428 SIGMA |= TMPD; // SIGMA = ((TMPF << 8) & 0x7ff) | ((((opcode << 4) + eIP) & 0xffff0000) >> 4)
429 IND_DELTA = WORDSZ; IND += IND_DELTA; DLY;
42A OPR_W = SIGMA; WR; // Write ((TMPF << 8) & 0x7ff) | ((((opcode << 4) + eIP) & 0xffff0000) >> 4) should be Opcode (0-0x7ff) + ((IP (upper word or upper 4 bits)) << 12) So TMPF is the opcode with the bytes swapped?
42B PROTUN = CR0; DLY; IND += IND_DELTA; PTGEN FPU_FSAVE; // FPU_FSAVE can go to FSAVE_387 or FSAVE_287 (always jumps) IND_DELTA set to WORDSZ at 429
42C OPR_W = TMPG; COUNTR = 0x29; WR; // Write OPROFF + (CS << 4) should be Operand Pointer (lower word)
42D TMPB = COUNTR; SHRCNT = 1; DLY; IND += IND_DELTA; // IND_DELTA set to WORDSZ at 429
42E OPR_W = TMPE; WR; // Write ((OPROFF + (CS << 4)) & 0xffff0000) >> 4 should be operand pointer (upper word or 4 bits) << 12 ?
------------------------------------------|----------------------------------------------------------------------------------------------
42F FSAVE_PM: OPR_W = FSVeIP; WR; // Write IP offset (address 6 or 12)
430 IND_DELTA = WORDSZ; IND += IND_DELTA; DLY;
431 OPR_W = CSOPCD; WR; // Write Opcode:CS or CS (address 8 or 16)
432 PROTUN = CR0; DLY; IND += IND_DELTA; PTGEN FPU_FSAVE; // FPU_FSAVE can go to FSAVE_387 or FSAVE_287 (always jumps) IND_DELTA set to WORDSZ at 430
433 OPR_W = OPROFF; COUNTR = 0x29; WR; // Write Operand Offset (address 10 or 20)
434 TMPB = COUNTR; SHRCNT = 1; DLY; IND += IND_DELTA; // IND_DELTA set to WORDSZ at 430
435 OPR_W = TMPC; WR; // Write Operand Selector (address 12 or 24) - write a dword though it's only a word long
------------------------------------------|----------------------------------------------------------------------------------------------
436 FSAVE_REGFILE: DES_IO; IND = 0x800000fc; DLY;
437 FIO; WIO; if (MISC2) goto FSAVE_NOWRITE;
438 --COUNTR; RD; // Read data from FPU - first word/dword?
439 DES_OS; SIGMA = TMPH + WORDSZ; IND = TMPH; DLY;
43A TMPH = SIGMA; wr; if (COUNTR == 0) goto FSAVE_DONEFILE; // Write same data back to memory
43B UNL;
43C FSAVE_LOOP: SIGMA = 0x800000fc; DLY;
43D DES_IO; IND = SIGMA; FIO; WIO; if (MISC2) goto FSAVE_NOWRITE; // MISC2 causes the write back to be skipped
43E --COUNTR; RD; // Read data from FPU
43F DES_OS; SIGMA = TMPH + WORDSZ; DLY; IND = TMPH; // TMPH is address to write to
440 TMPH = SIGMA; wr; if (COUNTR != 0) goto FSAVE_LOOP; // Write same data back to memory TMPH += WORDSZ
441 UNL;
442 FSAVE_DONEFILE: DLY; RETURN;
443
------------------------------------------|----------------------------------------------------------------------------------------------
444 FSAVE_NOWRITE: DLY;
445 if (COUNTR != 0) goto FSAVE_LOOP;
446 SIGMA = TMPH + WORDSZ; UNL;
447 TMPH = SIGMA; RETURN;
448
------------------------------------------|----------------------------------------------------------------------------------------------
449 FSAVE_387: if (MISC1) goto FSAVE_DONE; // TMPB is 0x29 on entry
44A SIGMA = (0:TMPB) >> SHRCNT; // Shift right by 1 SIGMA = 20 SHRCNT is always 1 here
44B COUNTR = SIGMA; MISC2 = false; DLY; // COUNTR = 20 Number of DWords to transfer for ST(0)-ST(7) for 32-bit transfers
44C SIGMA = IRF2 + WORDSZ; IND_DELTA = WORDSZ; IND += IND_DELTA;
44D FSAVE_REGFILE();
44E TMPH = SIGMA; BITS32;
44F RNI;
450
------------------------------------------|----------------------------------------------------------------------------------------------
451 FSAVE_287: if (MISC1) goto FSAVE_DONE; // TMPB = 0x29 on entry
452 SIGMA = TMPB - 1; // SIGMA = 40
453 COUNTR = SIGMA; MISC2 = false; DLY; // COUNTR = 40 Number of Words to transfer for ST(0)-ST(7) for 16-bit transfers
454 SIGMA = IRF2 + WORDSZ; IND_DELTA = WORDSZ; IND += IND_DELTA;
455 FSAVE_REGFILE();
456 TPHS = SIGMA; BITS16;
457 FSAVE_DONE: RNI;
458 DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
459 PROTUN = CR0; PTGEN FPU_OTHER; // 1 FLDENV m FPU_OTHER goes to #NM or continues
45A DLY; goto FRSTOR_WAIT;
45B TMPG = IRF2; MISC1 = true; IND_DELTA = 0x0d; IND += IND_DELTA; // MISC1 is flag to say we're doing an FLDENV and not FRSTOR, tested by JMISC1 IND = src + 0x0d
------------------------------------------|----------------------------------------------------------------------------------------------
45C PROTUN = CR0; PTOVRR FPU_OTHER; // 1 FRSTOR m FPU_OTHER goes to #NM or continues
45D DLY; goto FRSTOR_WAIT;
45E TMPG = IRF2; IND_DELTA = 0x5d; IND += IND_DELTA; // IND = src + 0x5d
------------------------------------------|----------------------------------------------------------------------------------------------
45F #MF4: goto FAULT;
460 SIGMA = 0x10; // "Interrupt 16 Coprocessor Error"
------------------------------------------|----------------------------------------------------------------------------------------------
461 FRSTOR_WAIT: SIGMA = WORDSZ; // SIGMA = 2 or 4
462 if (!BUSY# && !ERROR#) goto FRSTOR_CORE;
463 SHLCNT = 3;
464 if (ERROR#) goto FRSTOR_ERRT;
465
466 FRSTOR_IRQT: if (!INTERRUPT_REQUESTED) goto FRSTOR_WAIT;
467
468 goto RPTI;
469
------------------------------------------|----------------------------------------------------------------------------------------------
46A FRSTOR_ERRT: if (!PEREQ) goto #MF4;
46B
46C goto FRSTOR_IRQT;
46D
------------------------------------------|----------------------------------------------------------------------------------------------
46E FRSTOR_CORE: SIGMA -= 2; // SIGMA = 0 or 2
46F TMPC = SIGMA; // TMPC = 0 or 2
470 SIGMA = (0:TMPC) << SHLCNT; // SIGMA = 0 or 16 SHLCNT is always 3 here
471 SIGMA -= WORDSZ; // SIGMA = -2 or 12
472 TMPC = SIGMA; SHLCNT = BITS_V; // TMPC = -2 or 12 SHLCNT = 15 or 31
473 DLY; IND_DELTA = TMPC; IND += IND_DELTA; // IND = src + (0x0d or 0x5d) + (-2 or 12)
474 CR_B; SIGMA = 1; // limit should be (0x0d or 0x1b) for FLDENV or (0x5d or 0x6b) for FRSTOR - IND here is (dest?+) (0x0b or 0x19) or (0x5b or 0x69) - two less than limit. Mostly harmless bug?
475 DES_OS; DLY; IND = TMPG; // IND = IRF2
476 TMPC = SIGMA; CR_B; // checking start as well? TMPC = 1
477 DES_IO; DLY IND = 0x800000f8;
478 OPR_W = IMM; SIGMA = -1; WR_W; // Write opcode?
479 SIGMA = (SIGMA:TMPC) << SHLCNT; // SIGMA = (-1:1) << BITS_V = 0x0000ffff or 0xffffffff
47A
47B FRSTOR_CORWAIT: TMPC = SIGMA; if (!PEREQ) goto FRSTOR_CORWAIT; // Waiting for something? TMPC = 0x0000ffff or 0xffffffff
47C TMPH = TMPG; COUNTR = 3; // TMPH is destination that FRSTOR_REGFILE reads from
47D FRSTOR_REGFILE(); // First call to FSAVE_REGFILE has COUNTR = 3 => write 3 vwords (control/status/tag)
47E
47F FRSTOR_REGFILE(); // Second call to FSAVE_REGFILE has COUNTR = 4 => write 4 vwords (opcode/eIP/operand address/CS/operand selector)
480 TMPB = TMPH; COUNTR = 4; // TMPB = src + (6 or 12)
481 DES_OS; IND = TMPB; DLY; // IND = src + (6 or 12)
482 COUNTR = 0x29; RD; // Read eIP
483 IND_DELTA = WORDSZ; IND += IND_DELTA; DLY;
484 if (PM) goto FRSTOR_PM; RD; // Read CS Selector or Opcode (0-0x7ff) + ((IP (upper word or 4 bits)) << 12)
485 SIGMA = OPR_R & 0xffff; UNL; // SIGMA = eIP & 0xffff
486 TMPB = SIGMA; DLY; IND += IND_DELTA; // IND_DELTA set to WORDSZ at 483 TMPB = eIP & 0xffff real mode from here
487 SIGMA = OPR_R & TMPC; UNL; RD; // SIGMA = (Opcode (0-0x7ff) + ((IP (upper word or 4 bits)) << 12)) & (0x0000ffff or 0xffffffff)) Read operand offset
488 TMPD = SIGMA; DLY; IND += IND_DELTA; // IND_DELTA set to WORDSZ at 483 TMPD = (Opcode (0-0x7ff) + ((IP (upper word or 4 bits)) << 12)) & (0x0000ffff or 0xffffffff))
489 SHLCNT = 8; RD; // Read operand selector (or upper part of pointer)
48A SIGMA = OPR_R & 0xffff; UNL; // SIGMA = (operand offset) & 0xffff
48B TMPE = SIGMA; BITS16; DLY; // TMPE = (operand offset) & 0xffff
48C SIGMA = (TMPD:TMPD) << SHLCNT; // SIGMA = TMPD with bytes swapped?
48D TMPF = SIGMA; BITS32; // TMPF = TMPD with bytes swapped?
48E SHLCNT = 4;
48F CSOPCD = 0; SIGMA = (0:TMPD) << SHLCNT; // SIGMA = TMPD << 4
490 SIGMA &= 0xffff0000; // SIGMA = (TMPD << 4) & 0xffff0000
491 SIGMA |= TMPB; // SIGMA = ((TMPD << 4) & 0xffff0000) | (eIP & 0xffff)
492 FSVeIP = SIGMA; // FSVeIP = reconstructed from read values
493 SIGMA = OPR_R & TMPC; UNL; // SIGMA = (Read operand selector (or upper part of pointer)) & (0x0000ffff or 0xffffffff)
494 TMPD = SIGMA; // TMPD = (Read operand selector (or upper part of pointer)) & (0x0000ffff or 0xffffffff)
495 SIGMA = (0:TMPD) << SHLCNT; // SIGMA = ((Read operand selector (or upper part of pointer)) & (0x0000ffff or 0xffffffff)) << 4
496 TMPB = TMPE; // TMPB = (operand offset) & 0xffff
497 PROTUN = CR0; PTGEN FPU_FRSTOR; // FPU_FRSTOR can go to FRSTOR_387 or FRSTOR_287 (always jumps)
498 SIGMA += TMPB; // SIGMA = ((operand offset) & 0xffff) + (((Read operand selector (or upper part of pointer)) & (0x0000ffff or 0xffffffff)) << 4)
499 OPROFF = SIGMA; // OPROFF = reconstructed from read values
49A TMPB = COUNTR; SHRCNT = 1; // TMPB = 0x29
------------------------------------------|----------------------------------------------------------------------------------------------
49B FRSTOR_PM: SIGMA = OPR_R & TMPC; // SIGMA = eIP & 0xffff
49C FSVeIP = SIGMA; DLY; IND += IND_DELTA; // IND_DELTA set to WORDSZ at 483
49D SIGMA = OPR_R & 0xffff; UNL; RD;
49E TMPD = SIGMA; DLY; IND += IND_DELTA; // IND_DELTA set to WORDSZ at 483
49F SIGMA = OPR_R & TMPC; UNL; RD;
4A0 OPROFF = SIGMA; BITS32; DLY;
4A1 TMPB = OPR_R; UNL; SHLCNT = 0x10;
4A2 SIGMA = (0:TMPB) << SHLCNT;
4A3 PROTUN = CR0; PTGEN FPU_FRSTOR; // FPU_FRSTOR can go to FRSTOR_387 or FRSTOR_287 (always jumps)
4A4 SIGMA |= SIGMA | TMPD;
4A5 CSOPCD = SIGMA:
4A6 TMPB = COUNTR; SHRCNT = 1;
------------------------------------------|----------------------------------------------------------------------------------------------
4A7 FRSTOR_REGFILE: DES_OS; IND = TMPH; DLY;
4A8 --COUNTR; RD;
4A9 DES_IO; IND = 0x800000fc; DLY;
4AA SIGMA = TMPH + WORDSZ;
4AB TMPH = SIGMA; FIO; WIO; if (COUNTR == 0) goto FRSTOR_DONEFIL;
4AC UNL; wr;
4AD FRSTOR_LOOP: DES_OS; IND = TMPH; DLY;
4AE --COUNTR; RD;
4AF DES_IO; IND = 0x800000fc; DLY;
4B0 SIGMA = TMPH + WORDSZ; FIO;
4B1 TMPH = SIGMA; FIO; WIO; if (COUNTR != 0) goto FRSTOR_LOOP;
4B2 UNL; wr;
4B3 FRSTOR_DONEFIL: DLY; RETURN;
4B4
------------------------------------------|----------------------------------------------------------------------------------------------
4B5 FRSTOR_387: if (MISC1) goto FRSTOR_DONE:
4B6 SIGMA = (0:TMPB) >> SHRCNT; RNi; // SHRCNT is always 1 here
4B7 FRSTOR_REGFILE();
4B8 COUNTR = SIGMA; BITS32; DLY;
4B9 RNI;
4BA FRSTOR_DONE:
------------------------------------------|----------------------------------------------------------------------------------------------
4BB FRSTOR_287: if (MISC1) goto FRSTOR_DONE:
4BC SIGMA = TMPB - 1; RNi;
4BD FRSTOR_REGFILE();
4BE COUNTR = SIGMA; BITS16; DLY;
4BF RNI;
4C0
------------------------------------------|----------------------------------------------------------------------------------------------
4C1 PROTUN = CR0; PTGEN FPU_OTHER; // 0 FP instructions that don't access memory FPU_OTHER goes to #NM or continues
4C2 FPU_REG_WAIT: if (!BUSY# && !ERROR#) goto FPU_REG_CORE;
4C3 if (ERROR#) goto FPU_REG_ERRT;
4C4
4C5 FPU_REG_IRQT: if (!INTERRUPT_REQUESTED) goto FPU_REG_WAIT;
4C6
4C7 goto RPTI;
4C8
------------------------------------------|----------------------------------------------------------------------------------------------
4C9 FPU_REG_ERRT: if (JPEREQ) goto #MF3;
4CA
4CB goto FPU_REG_IRQT;
4CC FPU_REG_CORE: DES_IO; SIGMA = IMM; IND = 0x800000f8; DLY;
4CD OPR_W = IMM; WR_W;
4CE FPU_REG_CORWAI: FSVeIP = TMPeIP; if (JPEREQ) goto FPU_REG_CORWAI; // Waiting for something?
4CF CSOPCD = CS; RNI;
4D0 TMPF = SIGMA; DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
4D1 #MF3: goto FAULT;
4D2 SIGMA = 0x10; // "Interrupt 16 Coprocessor Error"
------------------------------------------|----------------------------------------------------------------------------------------------
4D3 PROTUN = CR0; PTGEN FPU_LOAD_80; // 1 FBLD/FLD mt FPU_LOAD_80 can go to FPU_LD80_287, FPU_LD80_387, or #NM (always jumps) - transfer 10 bytes FPU -> bus
4D4 TMPB = OPCODE; SIGMA = 2; DLY;
4D5 TMPG = IRF2; IND_DELTA = 9; IND += IND_DELTA; BITS32;
4D6 COUNTR = SIGMA; SHLCNT = 0x10; // COUNTR = 2
------------------------------------------|----------------------------------------------------------------------------------------------
4D7 PROTUN = CR0; PTGEN FPU_LOAD_3264; // 1 FADD/FMUL/FCOM/FCOMP/FSUB/FSUBR/FDIV/FDIVR/FIADD/FIMUL/FICOM/FICOMP/FISUB/FISUBR/FIDIV/FIDIVR/FLD/FILD md FPU_LOAD_3264 can go to FPU_LD3264_287, FPU_LD3264_387 or #NM (always jumps) - transfer 4 bytes fPU -> bus
4D8 TMPB = OPCODE; SIGMA = 1; DLY;
4D9 TMPG = IRF2; IND_DELTA = 3; IND += IND_DELTA; BITS32;
4DA COUNR = SIGMA; SHLCNT = 0x10; // COUNTR = 1
------------------------------------------|----------------------------------------------------------------------------------------------
4DB PROTUN = CR0; PTGEN FPU_LOAD_3264; // 1 FLD/FILD/FADD/FMUL/FCOM/FCOMP/FSUBR/FSUB/FDIVR/FDIV mq FPU_LOAD_3264 can go to FPU_LD3264_287, FPU_LD3264_387 or #NM (always jumps) - transfer 8 bytes FPU -> bus
4DC TMPB = OPCODE; SIGMA = 2; DLY;
4DD TMPG = IRF2; IND_DELTA = 7; IND += IND_DELTA; BITS32;
4DE COUNTR = SIGMA; SHLCNT = 0x10; // COUNTR = 2
------------------------------------------|----------------------------------------------------------------------------------------------
4DF MISC2 = true; DLY; // 1 FLDCW mw
4E0 PROTUN = CR0; PTGEN FPU_OTHER; // 1 FIADD/FIMUL/FICOM/FICOMP/FISUB/FISUBR/FIDIV/FIDIVR/FILD mw FPU_OTHER goes to #NM or continues - transfer 2 bytes fPU -> bus
4E1 TMPB = OPCODE; SIGMA = 1; DLY;
4E2 TMPG = IRF2; IND_DELTA = 1; IND += IND_DELTA; BITS32;
4E3 COUNTR = SIGMA; SHLCNT = 0x10; // COUNTR = 1
4E4 SIGMA = (0:TMPB) << SHLCNT; // SIGMA = OPCODE << 16
4E5 goto FPU_LOAD_WAIT;
4E6 BITS16;
------------------------------------------|----------------------------------------------------------------------------------------------
4E7 FPU_LD80_287: MISC1 = true;
4E8 FPU_LD3264_287: TMPC = COUNTR;
4E9 SIGMA = COUNTR + TMPC; // SIGMA = COUNTR*2
4EA COUNTR = SIGMA; // COUNTR = COUNTR*2
4EB SIGMA = (0:TMPB) << SHLCNT; // SIGMA = OPCODE << 16 SHLCNT is always 16 here
4EC goto FPU_LOAD_WAIT;
4ED BITS16;
------------------------------------------|----------------------------------------------------------------------------------------------
4EE FPU_LD80_387: MISC1 = true; // This routine might be similar to FPU_LD3264_387
4EF SIGMA = (0:TMPB) << SHLCNT; // SIGMA = OPCODE << 16 SHLCNT is always 16 here
4F0 FPU_LOAD_WAIT: TMPB = SIGMA; if (!BUSY# && !ERROR#) goto FPU_LOAD_CORE; // TMPB = OPCODE << 16
4F1 SIGMA = CS | TMPB; // SIGMA = CS | (OPCODE << 16)
4F2 if (ERROR#) goto FPU_LD80_ERRT;
4F3
4F4 FPU_LOAD_IRQT: if (!INTERRUPT_REQUESTED) goto FPU_LOAD_WAIT;
4F5
4F6 goto RPTI;
4F7
------------------------------------------|----------------------------------------------------------------------------------------------
4F8 FPU_LOAD_ERRT: if (!PEREQ) goto #MF2;
4F9
4FA goto FPU_LOAD_IRQT;
4FB
------------------------------------------|----------------------------------------------------------------------------------------------
4FC FPU_LOAD_CORE: TMPB = SIGMA; CR_B; // TMPB = CS | (OPCODE << 16)
4FD DES_OS; DLY; SIGMA = TMPG + WORDSZ; IND = TMPG;
4FE TMPH = SIGMA; SIGMA = 0x800000f8; CR_B;
4FF DES_IO; DLY IND = SIGMA; if (MISC2) goto FLDCW;
500 OPR_W = IMM; SIGMA = IMM; WR_W;
501 DES_OS; SIGMA = 0x800000fc; IND = TMPG; DLY; // TMPG is the address to read from
502 CSOPCD = TMPB; --COUNTR; RD;
503 FPU_LOAD_CORWA: DES_IO; DLY; IND = SIGMA; if (!PEREQ) goto FPU_LOAD_CORWA; // Waiting for something?
504 FIO; WIO;
505 FSVeIP = TMPeIP; UNL; wr; if (COUNTR == 0) goto FPU_LOAD_DONE; // Write back read data to FPU data port
506 FPU_LOAD_LOOP: DES_OS; DLY; IND = TMPH;
507 TMPF = IMM; --COUNTR; RD; // Read from requested address given in TMPH
508 DES_IO; IND = 0x800000fc; DLY;
509 SIGMA = TMPH + WORDSZ; FIO;
50A TMPH = SIGMA; FIO; WIO; if (COUNTR != 0) goto FPU_LOAD_LOOP;
50B UNL; wr; // Write back read data to FPU data port
50C FPU_LOAD_DONE: OPROFF = TMPG; DLY; if (MISC1) goto FPU_LD80_DONE;
50D DES_OS; IND = TMPH; RNI;
50E FPU_LD80_DONE: DLY;
50F FIO; RD_W; // Read
510 TMPF = SIGMA; FIO; WIO;
511 DES_IO; DLY; IND = 0x800000fc;
512 wr_W; UNL; RNI; // Write back read data to FPU data port
513 DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
514 #MF2: goto FAULT;
515 SIGMA = 0x10; // "Interrupt 16 Coprocessor Error"
------------------------------------------|----------------------------------------------------------------------------------------------
516 FLDCW: DES_OS; IND = TMPG; DLY;
517 RD_W;
518 FLDCW_COR_WAIT: DLY; if (!PEREQ) goto FLDCW_COR_WAIT; // Waiting for something?
519 DES_IO; IND = 0x800000fc; FIO; WIO;
51A wr_W; UNL; RNI;
51B DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
51C FPU_LD3264_387: SIGMA = (0:TMPB) << SHLCNT; // SHLCNT is always 16 here
51D IND = 0x800000f8; DES_IO;
51E OPR_W = IMM; WR_W; // Write IMM to FPU command port
51F FPU_LD3264_WAIT: TMPB = SIGMA; if (!BUSY# && !ERROR#) goto FPU_LD3264_COR;
520 SIGMA = CS | TMPB;
521 if (ERROR#) goto FPU_LD364_ERRT;
522
523 FPU_LD3264_IRQT: if (!INTERRUPT_REQUESTED) goto FPU_LD3264_WAIT;
524
525 goto RPTI;
526
------------------------------------------|----------------------------------------------------------------------------------------------
527 FPU_LD3264_ERRT: if (!PEREQ) goto #MF2;
528
529 goto FPU_LD3264_IRQT;
52A FPU_LD3264_COR: DES_OS; IND = TMPG; DLY;
52B TMPB = SIGMA; RD; if (COUNTR == 1) goto FPU_LD32; // Read from requested address given in TMPG
52C IND = 0x800000fc; DES_IO; DLY;
52D wr; // Write back read data to FPU data port
52E DES_OS; IND_DELTA = WORDSZ; IND = TMPG + IND_DELTA;
52F UNL; RD; // Read from requested address given in TMPG
530 IND = 0x800000fc; DES_IO; DLY;
531 FPU_LD32: TMPF = IMM; wr; // Write back read data to FPU data port
532 CSOPCD = TMPB;
533 FPU_LD32_WAIT: FSVeIP = TMPeIP; DLY; if (!PEREQ) goto FPU_LD32_WAIT;
534 OPROFF = TMPG; RNI;
535 UNL;
------------------------------------------|----------------------------------------------------------------------------------------------
536 #NM: goto FAULT;
537 SIGMA = 7; // "Interrupt 7 Coprocessor Not Available"
------------------------------------------|----------------------------------------------------------------------------------------------
538 PROTUN = CR0; PTGEN FPU_STORE_80; // 1 FBSTP/FSTP mt FPU_STORE_80 can go to FPU_ST80_287, FPU_ST80_387, or #NM (always jumps) stores 10 bytes FPU -> bus
539 TMPB = OPCODE; SIGMA = 2; DLY;
53A TMPG = IRF2; IND_DELTA = 9; IND += IND_DELTA; BITS32;
53B COUNTR = SIGMA; SHLCNT = 0x10;
------------------------------------------|----------------------------------------------------------------------------------------------
53C PROTUN = CR0; PTGEN FPU_STORE_3264; // 1 FST/FSTP/FIST/FISTP md FPU_STORE_3264 can go to FPU_ST3264_287, FPU_ST3264_387, or #NM (always jumps) stores 4 bytes FPU -> bus
53D TMPB = OPCODE; SIGMA = 1; DLY;
53E TMPG = IRF2; IND_DELTA = 3; IND += IND_DELTA; BITS32;
53F COUNTR = SIGMA; SHLCNT = 0x10;
------------------------------------------|----------------------------------------------------------------------------------------------
540 PROTUN = CR0; PTGEN FPU_STORE_3264; // 1 FST/FSTP/FISTP mq FPU_STORE_3264 can go to FPU_ST3264_287, FPU_ST3264_387, or #NM (always jumps) stores 8 bytes FPU -> bus
541 TMPB = OPCODE; SIGMA = 2; DLY;
542 TMPG = IRF2; IND_DELTA = 7; IND += IND_DELTA; BITS32;
543 COUNTR = SIGMA; SHLCNT = 0x10;
------------------------------------------|----------------------------------------------------------------------------------------------
544 PROTUN = CR0; PTGEN FPU_OTHER; // 1 FIST/FISTP mw FPU_OTHER can go to #NM or continue stores 2 bytes FPU -> bus
545 TMPB = OPCODE; SIGMA = 1; DLY;
546 TMPG = IRF2; IND_DELTA = 1; IND += IND_DELTA; BITS32;
547 SHLCNT = 0x10; COUNTR = SIGMA;
548 SIGMA = (0:TMPB) << SHLCNT; // SIGMA = TMPB << 16
549 goto o556;
54A BITS16;
------------------------------------------|----------------------------------------------------------------------------------------------
54B #MF: goto FAULT;
54C SIGMA = 0x10; // "Interrupt 16 Coprocessor Error"
------------------------------------------|----------------------------------------------------------------------------------------------
54D FPU_ST80_287: MISC1 = true;
54E FPU_ST3264_287: TMPC = COUNTR;
54F SIGMA = COUNTR + TMPC;
550 COUNTR = SIGMA;
551 SIGMA = (0:TMPB) << SHLCNT; // SHLCNT is always 16 here
552 goto FPU_STORE_WAIT;
553 BITS16;
------------------------------------------|----------------------------------------------------------------------------------------------
554 FPU_ST80_387: MISC1 = true;
555 FPU_ST3264_387: SIGMA = (0:TMPB) << SHLCNT; // SHLCNT is always 16 here
556 FPU_STORE_WAIT: TMPB = SIGMA; if (!BUSY# && !ERROR#) goto FPU_STORE_CORE;
557 SIGMA = CS | TMPB;
558 if (JBUSY#) goto FPU_STORE_ERRT;
559
55A FPU_STORE_IRQT: if (!INTERRUPT_REQUESTED) goto FPU_STORE_WAIT;
55B
55C goto RPTI;
55D
------------------------------------------|----------------------------------------------------------------------------------------------
55E FPU_STORE_ERRT: if (JPEREQ) goto #MF;
55F
560 goto FPU_STORE_IRQT;
561
------------------------------------------|----------------------------------------------------------------------------------------------
562 FPU_STORE_CORE: TMPB = SIGMA; CW_B;
563 DES_OS; IND = TMPG; DLY;
564 CW_B;
565 IND = 0x800000f8; DES_IO; DLY;
566 OPR_W = IMM; WR_W;
567 IND = 0x800000fc; DES_IO; DLY;
568 FPU_STORE_CORW: if (!PEREQ) goto FPU_STORE_CORW;
569
56A TMPF = IMM; FIO; WIO; if (!PEREQ) goto FPU_STORE_ABRT; // This is a bit weird - PEREQ would have to go high and then immediately low again
56B CSOPCD = TMPB;
56C TMPH = TMPG; RD;
56D DES_OS; IND = TMPH; DLY; if (COUNTR == 1) goto FPU_STORE_DONE;
56E --COUNTR; FSVeIP = TMPeIP; wr;
56F FPU_STORE_LOOP: SIGMA = TMPH + WORDSZ; UNL;
570 TMPH = SIGMA; DLY;
571 IND = 0x800000fc; DES_IO; FIO; WIO;
572 RD;
573 DES_OS; IND = TMPH; if (COUNTR != 1) goto FPU_STORE_LOOP;
574 --COUNTR; wr;
575 FPU_STORE_DONE: OPROFF = TMPG; DLY; if (MISC1) goto FPU_STORE_287;
576 IND = 0x800000fc; DES_IO; UNL; RNI;
577 DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
578 FPU_STORE_287: FIO; WIO;
579 RD_W;
57A IND_DELTA = WORDSZ; IND = TMPH + IND_DELTA; DES_OS; DLY;
57B UNL; wr_W; RNI;
57C DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
57D FPU_STORE_ABRT: FSVeIP = TMPeIP; DLY;
57E OPROFF = TMPE; RNI;
57F
------------------------------------------|----------------------------------------------------------------------------------------------
580 PTR = &DES_SR; DLY; PTSAV1 TST_DES_SIMPLE; // 0 p MOV ES/DS/FS/GS,rw TST_DES_SIMPLE can go to #NP(I0,E0) or PROT_TESTS_PASSED (N) (RETURNs) or continue
581 LD_DESCRIPTOR(); // Load new ES/DS/FS/GS descriptor
582 SLCTR = DSTREG; DLY; PTSELE TST_SEL_NONSS; // TST_SEL_NONSS can go to NULL_SELECTOR (RETURNs) or continue (L)
583 SEGREG = SLCTR2; PTR->DEL = TMPC; RNI;
584 DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
585 PTR = &DES_SR; PTSAV7 TST_DES_SS; DLY; // 0 p MOV SS,rw TST_DES_SS can go to PROT_TESTS_PASSED (KN) (RETURNs), #SS(I0,E0), or continue
586 LD_DESCRIPTOR(); // Load new SS descriptor
587 SLCTR = DSTREG; PTSELE TST_SEL_SS; DLY; // TST_SEL_SS can go to #GP/#TS(I0,E0) or #GP/#TS(I0,E0) (L) or continue (L)
588 SEGREG = SLCTR2; PTR->DEL = TMPC; RnI;
589 DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
58A PM_LD_DSESFSGS: DLY; LD_DESCRIPTOR(); // Load new DS/ES/FS/GS descriptor
58B SLCTR = OPR_R; UNL; PTSELE TST_SEL_NONSS; // TST_SEL_NONSS can go to NULL_SELECTOR (RETURNs) or continue (L)
58C SEGREG = SLCTR2; PTR->DEL = TMPC; RNI; // descriptor selected previously?
58D DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
58E PM_LD_SS: DLY; LD_DESCRIPTOR(); // Load new SS descriptor
58F SLCTR = OPR_R; UNL; PTSELE TST_SEL_SS; // TST_SEL_SS can go to #GP/#TS(I0,E0) or #GP/#TS(I0,E0) (L) or continue (L)
590 SEGREG = SLCTR2; PTR->DEL = TMPC; RnI; // descriptor selected previously?
591 DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
592 NULL_SELECTOR: SIGMA = TMPD; UNL; RD_D; // Used by TST_SEL_NONSS, TST_SEL_LES, TST_SEL_LDS, TST_SEL_LFSLGS - interrupts LD_DESCRIPTOR and LD_DES_SSFSGS - this line happens after 5cb in LD_DESCRIPTOR or 5c6 in LD_DES_SSFSGS Why do an ignored RD from GDT entry 0 here?
593 PTR->DEH = 0; DLY; RETURN;
594 TMPC = 0; UNL; PTR->DES = 0; // descriptor selected on previous line
------------------------------------------|----------------------------------------------------------------------------------------------
595 PM_LES: PTR = &DES_ES; DLY; PTSAV1 TST_DES_SIMPLE; // TST_DES_SIMPLE can go to #NP(I0,E0) or PROT_TESTS_PASSED (N) (RETURNs) or continue
596 LD_DESCRIPTOR(); // Load new ES descriptor
597 SLCTR = OPR_R; PTSELE TST_SEL_LES; UNL; // TST_SEL_LES can go to NULL_SELECTOR (RETURNs) or continue (L)
598 ES = SLCTR2; DES_ES.DEL = TMPC; RNI; // descriptor selected previously? Or implicit by dest?
599 SRCREG = SIGMA; DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
59A PM_LSS: PTR = &DES_SS; DLY; PTSAV7 TST_DES_SS; // TST_DES_SS can go to PROT_TESTS_PASSED (KN) (RETURNs), #SS(I0,E0), or continue
59B LD_DES_SSFSGS();
59C SLCTR = OPR_R; UNL; PTSELE TST_SEL_SS; // TST_SEL_SS can go to #GP/#TS(I0,E0) or #GP/#TS(I0,E0) (L) or continue (L)
59D SS = SLCTR2; DES_SS.DEL = TMPC; RNI; // descriptor selected previously? Or implicit by dest?
59E SRCREG = SIGMA; DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
59F PM_LDS: PTR = &DES_DS; DLY; PTSAV1 TST_DES_SIMPLE; // TST_DES_SIMPLE can go to #NP(I0,E0) or PROT_TESTS_PASSED (N) (RETURNs) or continue
5A0 LD_DESCRIPTOR(); // Load new DS descriptor
5A1 SLCTR = OPR_R; UNL; PTSELE TST_SEL_LDS; // TST_SEL_LDS can go to NULL_SELECTOR (RETURNs) or continue (L) (same conditions as TST_SEL_LES)
5A2 DS = SLCTR2; DES_DS.DEL = TMPC; RNI; // descriptor selected previously? Or implicit by dest?
5A3 SRCREG = SIGMA; DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
5A4 PM_LFS_LGS: SIGMA |= 0x40; // FS is register 0x24 (DES_FS is register 0x64) and GS is register 0x25 (DES_GS is register 0x65)
5A5 COUNTR = SIGMA;
5A6
5A7 PTR = &IRF[COUNTR]; DLY; PTSAV1 TST_DES_SIMPLE; // TST_DES_SIMPLE can go to #NP(I0,E0) or PROT_TESTS_PASSED (N) (RETURNs) or continue
5A8 LD_DES_SSFSGS();
5A9 SLCTR = OPR_R; UNL; PTSELE TST_SEL_LFSLGS; // TST_SEL_LFSLGS can go to NULL_SELECTOR (RETURNs) or continue (L) (same conditions as TST_SEL_LES and TST_SEL_LDS)
5AA IRF[COUNTR] = SLCTR2; IRF[COUNTER].DEL = TMPC; RNI; // LD_DES_SSFSGS sets COUNTR to be 0x24 or 0x25 based on IMM (i.e. IMM ^ 0x10)
5AB SRCREG = SIGMA; DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
5AC JUMP_FAR_PM: PTR = &DES_CS; PTSAV7 TST_DES_JMP; // TST_DES_JMP can go to JUMP_FAR_PM_GATE, PROT_TESTS_PASSED (N) (RETURNs), #NP(I0,E0) or continue
5AD LD_DESCRIPTOR(); // Load new CS descriptor
5AE SLCTR = COUNTR; PTSELE TST_SEL_CS; // TST_SEL_CS can go to #GP/#TS(I0,E0) or continue (L)
5AF PROTUN = SLCTR2; PTGEN SET_RPL_TO_CPL; // (KM) we get here if we're jumping to a code segment
5B0 PTR->DEL = TMPC; // descriptor selected previously?
5B1 PAGER5.PCR; goto JMP_FAR_COMMON; // Write to special register?
5B2 SIGMA = PROTUN; // SIGMA in JMP_FAR_COMMON is CS selector value we're jumping to
------------------------------------------|----------------------------------------------------------------------------------------------
5B3 JUMP_FAR_PM_GATE: PTGATE TST_DES_JGATE; // TST_DES_JGATE can go to CALLGATE286, CALLGATE386, TASKGATE, AVAIL_TSS_PR, AVAIL_TSS_NP, #NP(I0,E0) or continue
5B4 TMPH = SIGMA; RPT; // Does RPT exhaust the delay slots for the protection test? Or one of them? SIGMA set to DES on line 5d0 (this is the destination selector)
5B5 PTR = &DES_CS; DLY; PTSAV7 TST_DES_JGDEST; // TST_DES_JGDEST can go to PROT_TESTS_PASSED2 (N) (RETURN), #NP(I0,E0), or continue. Not testing immediately but waiting for the next PTOVRR?
5B6 goto #GP/#TS(I0,E0);
5B7 PTGEN SET_FAULT;
------------------------------------------|----------------------------------------------------------------------------------------------
5B8 CALL_FAR_PM_GATE: COUNT5 = PROTUN; PTGATE TST_DES_CGATE; // TST_DES_CGATE can go to CALLGATE286, CALLGATE386, TASKGATE, AVAIL_TSS_PR, AVAIL_TSS_NP, #NP(I0,E0) or continue parameter count is low 5 bits of DEH
5B9 TMPH = SIGMA; INTERRUPT_HW = true; RPT; // Does RPT exhaust the delay slots for the protection test? Or one of them? (Must do or we'd always ends up in #GP/#TS(I0,E0) from here) SIGMA set to DES on line 5d0 (this is the destination selector) Not sure why we set INTERRUPT_HW here
5BA PTR = &DES_CS; DLY; PTSAV7 TST_DES_CGDEST; // TST_DES_CGDEST can go to PROT_TESTS_PASSED2 (N) (RETURN), MORE_PRIVILEGE (KLN), #NP(I0,E0), or continue.
5BB GENERAL_FAULTP: goto #GP/#TS(I0,E0);
5BC PTGEN SET_FAULT;
------------------------------------------|----------------------------------------------------------------------------------------------
5BD CALLGATE286: MISC2 = true;
5BE CALLGATE386: SIGMA = TMPC & 0xffff; // SIGMA = DEL & 0xffff (== offset & 0xffff) TMPC set to DEL at 5d0
5BF TMPC = SIGMA; // SIGMA = offset & 0xffff
5C0 SIGMA = TMPB & 0xffff0000; // SIGMA = DEH & 0xffff0000 (== offset & 0xffff0000) TMPB set to DEH at 5ce
5C1 SIGMA |= TMPC; // SIGMA = offset (reconstructed from gate)
5C2 TMPG = SIGMA; goto LD_DESCRIPTOR; // TMPG = offset Load new CS descriptor - Go back into LD_DESCRIPTOR which returns from where the first one was called (JUMP_FAR_PM or CALL_FAR_PM)
5C3 SLCTR = TMPH; DLY; PTSELE TST_SEL_CS; // TST_SEL_CS can go to #GP/#TS(I0,E0) or continue (L) TMPH set to DES at 5b4/5b9
------------------------------------------|----------------------------------------------------------------------------------------------
5C4 LD_DES_SSFSGS: DESSDT; IND_DELTA = 4; IND = SLCTR + IND_DELTA;
5C5 SIGMA = IMM ^ 0x10; rd_D;
5C6 COUNTR = SIGMA; IND_DELTA = -4; IND += IND_DELTA; DLY;
5C7 rd_D; goto LD_DESCRIPTOR2; // NULL DESCRIPTOR can take over here?
5C8 PROTUN = OPR_R; UNL; PTOVRR TST_DES_SIMPLE; // TST_DES_SIMPLE can go to #NP(I0,E0) or PROT_TESTS_PASSED (N) (RETURNs) or continue
------------------------------------------|----------------------------------------------------------------------------------------------
5C9 LD_DESCRIPTOR: DESSDT; IND_DELTA = 4; IND = SLCTR + IND_DELTA; // SLCTR is passed in as the selector of the descriptor to read
5CA rd_D; // First read = access/high = DEH
5CB DLY; IND_DELTA = -4; IND += IND_DELTA; // IND = SLCTR
5CC rd_D; // Second read = limit low / base low = DEL NULL_DESCRIPTOR can take over here?
5CD PTOVRR TST_DES_SIMPLE; PROTUN = OPR_R; // TST_DES_SIMPLE can go to #NP(I0,E0) or PROT_TESTS_PASSED (N) (RETURNs) or continue PROTUN = access/high = DEH
5CE LD_DESCRIPTOR2: TMPB = OPR_R; BITS32; // TMPB = access/high = DEH
5CF SHLCNT = 0x10; DLY;
5D0 TMPC = OPR_R; SIGMA = (OPR_R:TMPB) << SHLCNT; UNL; // SIGMA = (OPR_R:TMPB) << 16 = ((access byte) << 24) | ((base address) & 0xffffff) = DES
5D1 goto #GP/#TS(I0,E0); // we end up here if 5cd continues
5D2 PTGEN SET_FAULT;
------------------------------------------|----------------------------------------------------------------------------------------------
5D3 PRESENT_TSS: TMPC = SIGMA; goto PROT_TESTS_CMN;
5D4 PTR->DEH = TMPB; BITSDE;
------------------------------------------|----------------------------------------------------------------------------------------------
5D5 PROT_TESTS_PASSED: TMPC = SIGMA; IND_DELTA = 4; IND += IND_DELTA; DLY; // TMPC = DES
5D6 OPR_W = PROTUN; WR_W; // PROTUN must be to setting the accessed bit (bit 8 of DEH) - this is probably done by the N bit in the pla4 output
5D7 PTR->DEH = TMPB; BITSDE; DLY; // (sets byte 3 of base, byte 2 (G/DB/-/A bits) of access, and byte 2 (bits 16-19) of limit) Presumably setting DEH causes limit bits 16-19 to be shifted if G is set (and similarly with DEL)
5D8 PROT_TESTS_CMN: PTR->DES = TMPC; RETURN; // (sets byte 3 (P/DPL/S/Type) bits of access, and bytes 0-2 of base) descriptor selected previously
5D9 TMPC = OPR_R; SIGMA = TMPD; // restore SIGMA to TMPD TMPC = limit low / base low = DEL for later SDEL (sets bytes 0-1 of limit)
------------------------------------------|----------------------------------------------------------------------------------------------
5DA PROT_TESTS_PASSED2: TMPC = SIGMA; IND_DELTA = 4; IND += IND_DELTA; DLY;
5DB OPR_W = PROTUN; WR_W;
5DC PTR->DEH = TMPB; DLY; if (MISC2) goto PROT_TESTS_P16; // Because of RETURN in delay slot (next line), only 5df is executed at the destination (instead of 5de) in the MISC2 case MISC2 set at CALLGATE286/INTGATE286/TRAPGATE286
5DD PTR->DES = TMPC; RETURN; // descriptor seleted above?
5DE TMPC = OPR_R; BITS32;
------------------------------------------|----------------------------------------------------------------------------------------------
5DF PROT_TESTS_P16: TMPC = OPR_R; BITS16; // Only executed in the delay slot of RETURN at 5dd
------------------------------------------|----------------------------------------------------------------------------------------------
5E0 CALL_FAR_PM: PTR = &DES_CS; PTSAV7 TST_DES_CALL; DLY; // TST_DES_CALL can go CALL_FAR_PM_GATE, PROT_TESTS_PASSED (N) (RETURNs), #NP(I0,E0), or continue on entry, COUNTR = selector of destination and TMPG = offset of destination
5E1 LD_DESCRIPTOR(); // Load new CS descriptor
5E2 SLCTR = COUNTR; PTSELE TST_SEL_CS; // TST_SEL_CS can go to #GP/#TS(I0,E0) or continue (L)
5E3 PROTUN = SLCTR2; PTR->DEL = TMPC; // descriptor selected previously?
5E4 PAGER5.PCR; PTGEN SET_RPL_TO_CPL; // (KM)
5E5 DESSTK; SIGMA = ESP + NEGWSZ; DLY; IND_DELTA = NEGWSZ; IND = ESP + IND_DELTA;
5E6 OPR_W = CS; WR; // push CS
5E7 TMPB = PROTUN; DLY; IND += IND_DELTA; // IND_DELTA set to NEGWSZ at 5e5
5E8 OPR_W = EIP; WR; // push eIP
5E9 SIGMA += NEGWSZ;
5EA DLY; goto JMP_FAR_COMMON;
5EB eSP = SIGMA; SIGMA = TMPB;
------------------------------------------|----------------------------------------------------------------------------------------------
5EC MORE_PRIV16: SHRCNT = (-2) & BITS_V; // shift right by 0x1e (or 0x0e?)
5ED SIGMA = (SIGMA:0) >> SHRCNT; // SIGMA <<= 2 - each stack selector/offset pair is 4 bytes in the TSS
5EE goto FOUND_STACK;
5EF DES_TR; IND_DELTA = 2; IND = SIGMA + IND_DELTA; BITS16; DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
5F0 GENERAL_FAUL2P: goto #GP/#TS(I0,E0);
5F1 SLCTR2 = TMPH; PTGEN SET_FAULT;
------------------------------------------|----------------------------------------------------------------------------------------------
5F2 PUSH_V86_SREGS: SIGMA = TMPH & 3; // This seems to be the Push(GS) code in https://www.felixcloutier.com/x86/intn:into:int3:int1
5F3 OPR_W = GS; WR_W;
5F4 COUNTR = SIGMA; DLY; IND += IND_DELTA; // IND -= WORDSZ IND_DELTA set to NEGWSZ at 60a
5F5 OPR_W = FS; WR_W;
5F6 DLY; IND += IND_DELTA; if (COUNTR != 0) goto GENERAL_FAUL2P; // IND -= WORDSZ IND_DELTA set to NEGWSZ at 60a
5F7 OPR_W = DS: WR_W;
5F8 DLY; IND += IND_DELTA; // IND -= WORDSZ IND_DELTA set to NEGWSZ at 60a
5F9 OPR_W = ES; WR_W; goto MORE_PRIV2;
5FA DLY; IND += IND_DELTA; // IND -= WORDSZ IND_DELTA set to NEGWSZ at 60a
------------------------------------------|----------------------------------------------------------------------------------------------
5FB MORE_PRIVILEGE: TMPE = TMPB; IND_DELTA = 4; IND += IND_DELTA; BITS32; DLY; // Also handles the INTERRUPT-TO-INNER-PRIVILEGE case? TMPB is DEH from the last LD_DESCRIPTOR (which is the one in CALL_FAR_PM loading CS)
5FC OPR_W = PROTUN; SHRCNT = 0x5d & BITS_V; WR_W; // Actually loading 0x1d (Or 0x0d?)
5FD PROTUN = SLCTR2; PTGEN WRITE_RPL; // (M)
5FE MDTMP4 = TMPC; RPT; if (BITS == 16) goto MORE_PRIV16; // exhaust one of the PTGEN's delay slots? (BITS here clearly isn't affected by BITS32 on line 5fb)
5FF TMPH = PROTUN; SIGMA = PROTUN & 3; // determine privilege level
600 SIGMA = (SIGMA:0) >> SHRCNT; // SIGMA = ((PROTUN & 3) << 3) - each stack selector/offset pair is 8 bytes in the TSS
601 DES_TR; IND_DELTA = WORDSZ; IND = SIGMA + IND_DELTA; DLY;
602 FOUND_STACK: SLCTR2 = TR; TSS_ACCESS_FLAG = true; RD; // Read eSP for privilege level
603 DLY; IND += IND_DELTA; // IND_DELTA set to WORDSZ at 601
604 TMPD = OPR_R; UNL; RD_W; // Store eSP in TMPD. Read SS for privilege level
605 PTR = &DES_CS; DLY; PTSAV3 TST_DES_MOREPR; // TST_DES_MOREPR can go to #SS(I0,E0), PROT_TESTS_PASSED2 (N) (RETURNs), or continue. We're putting the new stack in CS temporarily so we still have access to the old stack and can copy params between them
606 LD_DESCRIPTOR(); // Load new CS descriptor
607 SLCTR = OPR_R; UNL; PTSELA TST_SEL_MOREPR; // TST_SEL_MOREPR can go to #GP/#TS(I0,E0) or continue
608 PTR->DEL = TMPC; TSS_ACCESS_FLAG = false; // descriptor selected previously?
609 if (VM) goto PUSH_V86_SREGS; // Can we actually get here in the VM case? Must be an interrupt?
60A DESCSW; IND_DELTA = NEGWSZ; IND = TMPD + IND_DELTA; DLY;
60B MORE_PRIV2: OPR_W = SS; WR_W; if (MISC1) goto MORE_PRIV_INT; // MISC1 is set on 8b2 in INTERRUPT_PM
60C TMPD = COUNTR; SIGMA = COUNTR + ESP; DLY; IND += IND_DELTA; // IND_DELTA set to NEGWSZ at 60a If we got here via 5f9 then COUNTR must be 0 COUNTR loaded at 5b8
60D OPR_W = ESP; if (COUNTR == 0) goto COPY_PRMS_SKIP; WR;
60E DLY; IND += IND_DELTA; // IND_DELTA set to NEGWSZ at 60a
60F if (MISC2) goto MORE_PRIV3; // We must be in the !VM case here
610 SIGMA += TMPD;
611 SIGMA += TMPD;
612 SIGMA += TMPD;
613 MORE_PRIV3: eSP = SIGMA; goto COPY_PARAMS; // SIGMA ends up as either ESP + 2*TMPD or ESP + 4*TMPD depending on MISC2 (MISC2 set for CALLGATE286)
614 TMPD = IRF2; IND_DELTA = 0; IND += IND_DELTA; // Not sure why we'd want IND_DELTA = 0
------------------------------------------|----------------------------------------------------------------------------------------------
615 MORE_PRIV_INT: OPR_W = ESP; WR;
616 SIGMA = FLAGSB & 0x37fd7; DLY; IND += IND_DELTA; // IND_DELTA set to NEGWSZ at 60a
617 OPR_W = SIGMA; WR; goto COPY_PRMS_SKIP;
618 CLT; DLY; IND += IND_DELTA; // IND_DELTA set to NEGWSZ at 60a
------------------------------------------|----------------------------------------------------------------------------------------------
619 COPY_PARAMS: DESSTK; SIGMA = ESP + NEGWSZ; IND_DELTA = NEGWSZ; IND = ESP + IND_DELTA; DLY;
61A eSP = SIGMA; --COUNTR; RD; // Read a param
61B DESCSW; SIGMA = TMPD + 0; IND = TMPD; DLY; // Why ADD 0 here?
61C TMPD = SIGMA; wr; if (COUNTR == 0) goto COPY_PRMS_DONE; // Write back param
61D DESSTK; SIGMA = ESP + NEGWSZ; IND_DELTA = NEGWSZ; IND = ESP + IND_DELTA; DLY;
61E COPY_PRMS_LOOP: eSP = SIGMA; --COUNTR; RD; // Read a param
61F DESCSW; SIGMA = TMPD + NEGWSZ; IND_DELTA = NEGWSZ; IND = TMPD + IND_DELTA; DLY;
620 TMPD = SIGMA; UNL; wr; if (COUNT != 0) goto COPY_PRMS_LOOP; // write back param
621 DESSTK; SIGMA = ESP + NEGWSZ; IND_DELTA = NEGWSZ; IND = ESP + IND_DELTA; DLY;
622 COPY_PRMS_DONE: DESCSW; UNL; IND_DELTA = NEGWSZ; IND = TMPD + IND_DELTA;
623 COPY_PRMS_SKIP: OPR_W = CS; WR_W; // Old CS onto new stack
624 IND_DELTA = NEGWSZ; IND += IND_DELTA; DLY;
625 OPR_W = ESP; COUNTR = TMPB; WR; // Old ESP onto new stack
626 eIP = TMPG; if (!ERROR_CODE_FLAG) goto NO_ERROR_CODE; DLY;
627 PROTUN = TMPE; BITS32; // TMPE set on line 5fb and is a CS AR?
628 SHRCNT = 0x10; TMPD = TMPF; // Where did TMPF get set?
629 SIGMA = (0:TMPD) >> SHRCNT; DLY; IND += IND_DELTA; // SIGMA = TMPD >> 16; IND_DELTA set to NEGWSZ at 624 This sort of looks like PUSH_ERRORCODE
62A OPR_W = SIGMA; WR_W; // Return address?
62B NO_ERROR_CODE: TMPD = MDTMP; PTGEN COPY_STACK_DPL; DLY; // (KN)
62C TMPG = IRF2; SHRCNT = 0x10; IND += IND_DELTA; // IND_DELTA set to NEGWSZ at 624
62D DES_CS.DEH = TMPE; SIGMA = (TMPE:TMPD) >> SHRCNT;
62E TMPB = SIGMA;
62F DES_CS.DES = TMPB; // descriptor selected above
630 TMPG = TMPB; DES_CS.DEL = TMPD; // descriptor selected above
631 PAGER5.PCR; if (VM) goto ZERO_V86_SREGS;
632 SIGMA = EFLAGS & 0xffff; DLY;
633 MORE_PRIV_DONE: EFLAGS = SIGMA; // clear resume flag and virtual mode 8086 flag
634 DESCOD; IND = 0; DLY;
635 SIGMA = (COUNTR:TMPC) >> SHRCNT; PREF; // SIGMA = (COUNTR << 16) | (TMPC >> 16)?
636 TMPD = SIGMA; DLY;
637 DES_SS.DEH = COUNTR; SIGMA = TMPB;
638 SS = SLCTR2; DES_SS.DES = TMPD; // descriptor selected above? Or implied by dest?
639 CS = TMPH; DES_SS.DEL = TMPC; RNI;
63A eSP = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
63B ZERO_V86_SREGS: DS.AR = 0;
63C ES.AR = 0;
63D FS.AR = 0; goto MORE_PRIV_DONE;
63E GS.AR = 0;
------------------------------------------|----------------------------------------------------------------------------------------------
63F IRETd_V86: DESSTK; IND = SIGMA; // STACK-RETURN-TO-V86 in PRM
640 SIGMA = 0xffff; RD_D; // Read from SS:ESP? Read new value for ESP
641 MDTMP4 = SIGMA; IND_DELTA = 4; IND += IND_DELTA; DLY; // MDTMP4 = 0xffff This can't be the same as COUNTR as that would result in DES_CS.BASE being set to 0xffff0
642 ESP = OPR_R; SHLCNT = 0x0d; UNL; RD_D; // Read new value for SS
643 SIGMA = (0:3) << SHLCNT; DLY; IND += IND_DELTA; // SIGMA = 3 << 13 = 0x6000 IND_DELTA set to WORDSZ at 676
644 TMPB = OPR_R; UNL; RD_D; // Read new value for ES
645 SIGMA |= 0x8200; DLY; IND += IND_DELTA; // SIGMA = 0xe200 IND_DELTA set to WORDSZ at 676
646 TMPD = OPR_R; UNL; RD_D; // Read new value for DS
647 TMPC = SIGMA; DLY; IND += IND_DELTA; // TMPC = 0xe200 IND_DELTA set to WORDSZ at 676
648 TMPE = OPR_R; UNL; RD_D; // Read new value for FS
649 IP = TMPG; DLY; IND += IND_DELTA; // IND_DELTA set to WORDSZ at 676
64A SLCTR2 = OPR_R; UNL; RD_D; // Read new value for GS
64B PROTUN = -1; PTF COPY_STACK_DPL; DLY; // (KN)
64C DES_CS.AR = TMPC;
64D DES_CS.BASE = COUNTR << 4; // COUNTR is set at 67a
64E DES_CS.LIMIT = MDTMP; // MDTMP seems to be the same register as MDTMP4
64F PAGER5.PCR;
650 DES_CS; IND = EIP; DLY;
651 SIGMA = COUNTR; PREF; // SIGMA = new CS value
652 FS = SLCTR2; FS.BASE = SLCTR2 << 4; COUNTR = 0x65; // Presumably FS.SBRM does the same thing as DES_FS.SBRM etc. Do other operations on dest activate DES_ dest|0x40 ? Register 0x65 == DES_GS
653 DS = TMPE; DS.BASE = TMPE << 4;
654 SS = TMPB; SS.BASE = TMPB << 4;
655 ES = TMPD; ES.BASE = TMPD << 4;
656 GS = OPR_R; GS.BASE = OPR_R << 4; UNL;
657 IRETd_V86_LOOP: DES_ES.AR = TMPC; // Loop to set all AR bytes to 0xe2 and all limits to MDTMP/MDTMP4 = 0xffff
658 IRF[COUNTR].AR = TMPC; if ((COUNTR & 15) != 1) goto IRETd_V86_LOOP;
659 IRF[COUNTR].LIMIT = MDTMP; --COUNTR;
65A DES_ES.LIMIT = MDTMP; RNI;
65B CS = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
65C TASK_RETURN: TMPD = SIGMA; COUNTR = 0x5d; // TASK-RETURN described in https://www.felixcloutier.com/x86/iret:iretd:iretq ? Happens when executing IRETd with NT flag set
65D SIGMA = (-1)^0x4000; // SIGMA = 0xbfff
65E TMPB = SIGMA; FLAGS_BACKED_UP = true;
65F FLAGSB = EFLAGS; SIGMA = EFLAGS & TMPB; // turn off NT (Nested Task) flag
660 EFLAGS = SIGMA;
661 SAVE_TASK();
662 SIGMA = COUNTR - 1;
663 DES_TR; IND = 0; DLY; TASK_SAVED = false; // Is this right? Why would be clearing the TASK_SAVED flag so soon after setting it (in SAVE_TASK())?
664 TSS_ACCESS_FLAG = true; RD_W; // Read backlink from old task
665 PTR = &DES_TR; DLY; PTSAV1 TST_DES_TSSTSR; // TST_DES_TSSTSR can go to #NP(I0,E0), PRESENT_TSS or continue
666 LD_DESCRIPTOR(); // Load new TR descriptor - for backlink
667 SLCTR = OPR_R; UNL; PTSELA TST_SEL_GDT; // TST_SEL_GDT can go to #GP/#TS(I0,E0) or continue SLCTR is backlink from old task
668 TMPG = SLCTR2; PTR->DEL = TMPC; BITS32; // descriptor selected previously? TMPG is backlink from old task (i.e. new TR)
669 TMPC = TR; SHLCNT = 0x10;
66A SIGMA = TMPC << 16; // SIGMA = TR << 16
66B TMPC = SIGMA; // TMPC = TR << 16
66C SIGMA = TMPG & 0xffff; // SIGMA = SLCTR2 & 0xffff
66D if (BITS == 16) goto LOAD_TASK_16B;
66E DESABS; IND_DELTA = TMPC; IND = SIGMA + IND_DELTA; DLY; // IND = (SLCTR2 & 0xffff) + (TR << 16)
66F TSDB; goto LOAD_TASK_32;
670 DES_TR; IND = 0x60; DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
671 LOAD_TASK_16B: TSDB; goto LOAD_TASK_16A;
672 COUNTR = 0x29;
------------------------------------------|----------------------------------------------------------------------------------------------
673 if (NT) goto TASK_RETURN; // 3 p IRETd
674 CLRNMI;
675 SIGMA += WORDSZ; RD; // Read from SS:ESP
676 IND_DELTA = WORDSZ; IND += IND_DELTA; DLY; // IND = ESP + WORDSZ;
677 SIGMA += WORDSZ; RD; // Read from SS:ESP+WORDSZ
678 TMPG = OPR_R; UNL; // TMPG = [SS:ESP] = eIP to return to
679 FLAGSB = EFLAGS; FLAGS_BACKED_UP = true; DLY; IND += IND_DELTA; // IND = ESP + WORDSZ*2 IND_DELTA set to WORDSZ at 676
67A COUNTR = OPR_R; UNL; RD; // COUNTR = [SS:ESP+WORDSZ] = CS to return to
67B DLY;
67C FLAGS = OPR_R; UNL; // FLAGS = [SS:ESP + WORDSZ*2] = eFLAGS to restore
67D DLY;
67E if (VM) goto IRETd_V86;
67F RETF_PM: PTR = &DES_CS; PTSAV3 TST_DES_RETF; // TST_DES_RETF can go to #NP(I0,E0), PROT_TESTS_PASSED (N) (RETURNs - must be from LD_DESCRIPTOR) or continue
680 eSP = SIGMA;
681 LD_DESCRIPTOR(); // Load new CS descriptor
682 SLCTR = COUNTR; PTSELE TST_SEL_RET; DLY; // TST_SEL_RET can go to #GP/#TS(I0,E0), RETF_OUTER_LEV (L), or continue (L) or continue
683 SIGMA = COUNTR; PTR->DEL = TMPC; // SAME-LEVEL case (RPL == CPL) only happens when LD_DESCRIPTOR() returns, i.e. TST_SEL_RET continues
684 PAGER5.PCR; goto JMP_FAR_DONE;
685 DESCOD; IND = TMPG; DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
686 RETF_OUTER_LEV: rd_D; LD_DESCRIPTOR2(); // OUTER-PRIVILEGE-LEVEL in PRM (RPL > CPL) - LD_DESCRIPTOR() was interrupted, so go back and finish it
687 PROTUN = OPR_R; PTOVRR TST_DES_SIMPLE; UNL; // TST_DES_SIMPLE can go to #NP(I0,E0), PROT_TESTS_PASSED (N) (RETURNs) or continue - this is actually the TST_DES_RETF though?
688 TMPB = COUNTR; PTR->DEL = TMPC; // descriptor selected previously?
689 PAGER5.PCR; SHLCNT = 0x0d;
68A DESSTK; IND = ESP; DLY;
68B SIGMA = (0:TMPB) << SHLCNT; RD; // SIGMA = TMPB << 13;
68C TMPH = COUNTR; IND_DELTA = WORDSZ; IND += IND_DELTA; DLY;
68D PROTUN = SIGMA; PTGEN COPY_STACK_DPL; RD; // (KN)
68E SIGMA = OPR_R + IMM; UNL;
68F DESCOD; DLY; IND = TMPG;
690 TMPD = SIGMA; COUNTR = 0x1f; PREF; // TMPD is eSP to restore at the end
691 PTR = &DES_SS; PTSAV3 TST_DES_RTOLSS; DLY; // TST_DES_RTOLSS can go to #SS(I0,E0), PROT_TESTS_PASSED (N) (which RETURNs) or continue
692 LD_DESCRIPTOR(); // Load new SS descriptor
693 SLCTR = OPR_R; PTSELA TST_SEL_RET_OL; UNL; // TST_SEL_RET_OL can go to #GP/#TS(I0,E0) or continue
694 SS = SLCTR2; PTR->DEL = TMPC; // descriptor selected previously?
695 IRF2 = DES_ES.AR; SIGMA = COUNTR + 1; DLY; // SIGMA = 0x20
696 PROTUN = IRF2; PTF TST_DES_RTOLOS; // TST_DES_RTOLOS can go to ZERO_SLCTR_AR or continue - test DES_ES.AR
697 RETF_OL_ES();
698 COUNTR = SIGMA; // COUNTR = 0x20
699 RETF_OL_ES: IRF2 = DES_DS.AR; SIGMA = COUNTR + 3; // If the test at 696 went to ZERO_SLCTR_AR, control flow will go 699->6a8->6a9->699, zeroing IRF[0x20]=ES SIGMA = 0x23
69A PROTUN = IRF2; PTF TST_DES_RTOLOS; // TST_DES_RTOLOS can go to ZERO_SLCTR_AR or continue - test DES_DS.AR
69B RETF_OL_DS();
69C COUNTR = SIGMA; // COUNTR = 0x23
69D RETF_OL_DS: IRF2 = DES_FS.AR; SIGMA = COUNTR + 1; // If the test at 69a went to ZERO_SLCTR_AR, control flow will go 69d->6a8->6a9->69d, zeroing IRF[0x23]=DS SIGMA = 0x24
69E PROTUN = IRF2; PTF TST_DES_RTOLOS; // TST_DES_RTOLOS can go to ZERO_SLCTR_AR or continue - test DES_FS.AR
69F RETF_OL_FS();
6A0 COUNTR = SIGMA; // COUNTR = 0x24
6A1 RETF_OL_FS: IRF2 = DES_GS.AR; SIGMA = COUNTR + 1; // If the test at 69e went to ZERO_SLCTR_AR, control flow will go 6a1->6a8->6a9->6a1, zeroing IRF[0x24]=FS SIGMA = 0x25
6A2 PROTUN = IRF2; PTF TST_DES_RTOLOS; // TST_DES_RTOLOS can go to ZERO_SLCTR_AR or continue - test DES_GS.AR
6A3 RETF_OL_GS();
6A4 COUNTR = SIGMA; // COUNTR = 0x25
6A5 RETF_OL_GS: CS = TMPH; SIGMA = TMPD; // If the test at 6a2 went to ZERO_SLCTR_AR, control flow will go 6a5->6a8->6a9->6a5, zeroing IRF[0x25]=GS
6A6 eIP = TMPG; RNI;
6A7 eSP = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
6A8 ZREO_SLCTR_AR: RETURN; // This subroutine zeroes a selector and corresponding AR in the case where the register setting is not valid for the outer level
6A9 IRF[COUNTR] = 0; IRF[COUNTR].DEH = 0;
------------------------------------------|----------------------------------------------------------------------------------------------
6AA PROTUN = SRCREG; PTSELA READ_RPL; RD_W; // 1 p ARPL mw,rw SET_L never jumps but sets pla4 output l
6AB RPT; // exhaust one of the PTSELA's delay slots?
6AC DLY;
6AD PROTUN = OPR_R; PTSELA TST_SEL_ARPL; UNL; // TST_SEL_ARPL can go to ARPL_FAILED or continue (M) or continue
6AE RPT; // exhaust one of the PTSELA's delay slots?
6AF
6B0 OPR_W = PROTUN; SEZF; WR_R;
6B1 RNI;
6B2 DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
6B3 ARPL_FAILED: CLZF;
6B4 RNI;
6B5
------------------------------------------|----------------------------------------------------------------------------------------------
6B6 PROTUN = SRCREG; PTSELA READ_RPL; // 0 p ARPL rw,rw SET_L never jumps but sets pla4 output l
6B7 RPT; // exhaust one of the PTSELA's delay slots?
6B8
6B9 PROTUN = DSTREG; PTSELA TST_SEL_ARPL; // TST_SEL_ARPL can go to ARPL_FAILED or continue (M) or continue
6BA RPT; // exhaust one of the PTSELA's delay slots?
6BB
6BC DSTREG = PROTUN; SEZF; RNI;
6BD
------------------------------------------|----------------------------------------------------------------------------------------------
6BE if (PM && CPL > 0) goto NO_PRIVILEGE; // 1 p LTR mw
6BF
6C0 RD_W;
6C1 goto LTR_COMMON; DLY;
6C2 SLCTR = OPR_R; UNL;
------------------------------------------|----------------------------------------------------------------------------------------------
6C3 if (PM && CPL > 0) goto NO_PRIVILEGE; // 0 p LTR rw
6C4 SLCTR = DSTREG;
6C5 LTR_COMMON: PTR = &DES_TR; PTSAV1 TST_DES_TSSLTR; DLY; // TST_DES_TSSLTR can go to #NP(I0,E0), PRESENT_TSS, or continue
6C6 LD_DESCRIPTOR(); // Load new TR descriptor
6C7 SLCTR2; PTSELA TST_SEL_GDT; // TST_SEL_GDT can go to #GP/#TS(I0,E0) or continue Why is SLCTR2 mentioned here as source with no dest?
6C8 TR = SLCTR2; PTR->DEL = TMPC; DLY;
6C9 DESSDT; IND_DELTA = 4; IND = SLCTR + IND_DELTA;
6CA SIGMA = PROTUN | 0x8200;
6CB OPR_W = SIGMA; WR_W; RNI;
6CC DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
6CD OPR_W = TR; WR_W; RNI; // 1 p STR mw
6CE
------------------------------------------|----------------------------------------------------------------------------------------------
6CF DSTREG = TR; RNI; // 0 p STR rw
6D0
------------------------------------------|----------------------------------------------------------------------------------------------
6D1 if (PM && CPL > 0) goto NO_PRIVILEGE; // 1 p LLDT mw
6D2
6D3 RD_W;
6D4 goto LLDT_COMMON; DLY;
6D5 SLCTR = OPR_R; UNL;
------------------------------------------|----------------------------------------------------------------------------------------------
6D6 if (PM && CPL > 0) goto NO_PRIVILEGE; // 0 p LLDT rw
6D7 SLCTR = DSTREG;
6D8 LLDT_COMMON: PTR = &DESLDT; PTSAV1 TST_DES_LDT; DLY; // TST_DES_LDT can go to #NP(I0,E0), PROT_TESTS_PASSED (RETURNs) or continue.
6D9 LD_DESCRIPTOR(); // Load new LDT descriptor
6DA PROTUN; PTSELA TST_SEL_LLDT; // TODO: What happens to PROTUN? Where does it come from? Presumably we're testing SLCTR here. TST_SEL_LLDT can go to LLDT_TEST_PASS or #GP/#TS(I0,E0) or continue
6DB LDTR = SLCTR2; RNI; PTR->DEL = TMPC; // is SLCTR2 the same as SLCTR? // descriptor selected previously?
6DC
------------------------------------------|----------------------------------------------------------------------------------------------
6DD LLDT_TEST_PASS: LDT = SLCTR2; UNL; RD_D;
6DE DESLDT.DEH = 0; RNI; DLY;
6DF UNL;
------------------------------------------|----------------------------------------------------------------------------------------------
6E0 OPR_W = LDT; RNI; WR_W; RNI; // 1 p SLDT mw
6E1 DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
6E2 DSTREG = LDT; RNI; // 0 p SLDT rw
6E3
------------------------------------------|----------------------------------------------------------------------------------------------
6E4 LAR_LSL_VERRWM(); RD_W; // 1 p LAR rv,mv
6E5 DLY; PTR = 0; PTSAV1 TST_DES_LAR; // TST_DES_LAR can go to LAR_VERRW_SUCCEEDED or continue PTR doesn't actually seem to be used - this may be vestigial
6E6 SRCREG = SIGMA; // Executed after RETURN in the RNI's delay slot (RNI is in the RETURN's delay slot in LAR_VERRW_SUCCEEDED)
------------------------------------------|----------------------------------------------------------------------------------------------
6E7 LAR_LSL_VERRWR(); // 0 p LAR rv,rv
6E8 DLY; PTR = 0; PTSAV1 TST_DES_LAR; // TST_DES_LAR can go to LAR_VERRW_SUCCEEDED or continue PTR doesn't actually seem to be used - this may be vestigial
6E9 SRCREG = SIGMA;
------------------------------------------|----------------------------------------------------------------------------------------------
6EA LAR_LSL_VERRWM(); RD_W; // 1 p LSL rv,mv
6EB DLY; PTR = 0; PTSAV1 TST_DES_LSL; // TST_DES_LSL can go to LSL_HELPER or continue. PTR doesn't actually seem to be used - this may be vestigial
------------------------------------------|----------------------------------------------------------------------------------------------
6EC LAR_LSL_VERRWR(); // 0 p LSL rv,rv
6ED DLY; PTR = 0; PTSAV1 TST_DES_LSL; // TST_DES_LSL can go to LSL_HELPER or continue. PTR doesn't actually seem to be used - this may be vestigial
------------------------------------------|----------------------------------------------------------------------------------------------
6EE LSL_HELPER: BITS32; DLY;
6EF TMPB = SLCTR2; SHRCNT = 8; UNL;
6F0 SIGMA = (0:TMPB) >> SHRCNT; // SIGMA = TMPB >> 8
6F1 PROTUN = SIGMA; PTF TST_DES_GRANUL; // TST_DES_GRANUL can go to LSL_GRANUARITY_COARSE or LSL_GRANULARITY_FINE based on pla4 input e.
6F2 SIGMA = TMPG & 0xffff;
6F3 TMPB = SIGMA; // TMPB = TMPG & 0xffff
6F4 SIGMA = SLCTR2 & 0xf0000;
------------------------------------------|----------------------------------------------------------------------------------------------
6F5 LSL_GRANULARITY_COARSE: SIGMA |= TMPB;
6F6 SIGMA += 1;
6F7 TMPC = SIGMA; SIGMA = 0x0d;
6F8 SIGMA -= 1; // SIGMA = 0x0c
6F9 TMPD = SIGMA; // TMPD = 0x0c
6FA TMPB = 0; SHLCNT = TMPD;
6FB SIGMA = (0:TMPC) << SHLCNT; // SIGMA = TMPC << 12
6FC SIGMA -= 1;
6FD LSL_GRANULARITY_FINE: BITSDE;
6FE SIGMA |= TMPB; RNI;
6FF SRCREG = SIGMA; SEZF; // Set zero flag happens in the case where the register is set
------------------------------------------|----------------------------------------------------------------------------------------------
700 LAR_LSL_VERRWM(); RD_W; // 1 p VERR mw
701 PTSAV1 TST_DES_VERR; DLY; PTR = 0; // TST_DES_VERR can go to LAR_VERRW_SUCCEEDED or continue PTR doesn't actually seem to be used - this may be vestigial
702
------------------------------------------|----------------------------------------------------------------------------------------------
703 LAR_LSL_VERRWR(); // 0 p VERR rw
704 PTSAV1 TST_DES_VERR; DLY; PTR = 0; // TST_DES_VERR can go to LAR_VERRW_SUCCEEDED or continue PTR doesn't actually seem to be used - this may be vestigial
705
------------------------------------------|----------------------------------------------------------------------------------------------
706 LAR_LSL_VERRWM(); RD_W; // 1 p VERW mw
707 PTSAV1 TST_DES_VERW; DLY; PTR = 0; // TST_DES_VERW can go to LAR_VERRW_SUCCEEDED or continue PTR doesn't actually seem to be used - this may be vestigial
708
------------------------------------------|----------------------------------------------------------------------------------------------
709 LAR_LSL_VERRWR(); // 0 p VERW rw
70A PTSAV1 TST_DES_VERW; DLY; PTR = 0; // TST_DES_VERW can go to LAR_VERRW_SUCCEEDED or continue PTR doesn't actually seem to be used - this may be vestigial
70B
------------------------------------------|----------------------------------------------------------------------------------------------
70C LAR_LSL_VERRWM: goto LAR_LSL_VERRW; DLY;
70D SLCTR = OPR_R; PTSELA TST_SEL_LLVV; UNL; // TST_SEL_LLVV can go to LAR_LSL_VERRW_NULL_SELECTOR or continue (L)
------------------------------------------|----------------------------------------------------------------------------------------------
70E LAR_LSL_VERRWR: SLCTR = DSTREG; PTSELA TST_SEL_LLVV; DLY; // TST_SEL_LLVV can go to LAR_LSL_VERRW_NULL_SELECTOR or continue (L)
70F LAR_LSL_VERRW: DESSDT; NO_FAULT = true; IND_DELTA = 4; IND = SLCTR + IND_DELTA;
710 BITS32; RPT; // exhaust one of the PTSELA's delay slots?
711 TMPE = SLCTR2; SHRCNT = 8; rd_D; // If this read would fault, NO_FAULT handling takes over?
712 IND_DELTA = -4; IND += IND_DELTA; DLY;
713 SIGMA = (0:0xffff0000) >> SHRCNT; rd_D; // SIGMA = 0xffff0000 >> 8 = 0x00ffff00 If this read would fault, NO_FAULT handling takes over?
714 SLCTR = OPR_R; UNL; PTOVRR TST_DES_LAR; // TST_DES_LAR can go to LAR_VERRW_SUCCEEDED or continue - default, overridden by TST_DES_LSL/TST_DES_VERR/TST_DES_VERW for LSL/VERR/VERW respectively
715 TMPB = SIGMA; BITSDE; DLY; // TMPB = 0x00ffff00
716 SIGMA = SLCTR2 & TMPB; RD_W; // SIGMA = SLCTR2 & 0x00ffff00
717 TMPG = OPR_R; UNL; // How is this TMPG used?
718 CLZF; RNI; DLY; // We get here if the test on line 714 continues - this is the failure case
719 OPR_R; UNL;
------------------------------------------|----------------------------------------------------------------------------------------------
71A LAR_VERRW_SUCCEEDED: DLY; RETURN;
71B OPR_R; SEZF; RNI; UNL; // RNI in RETURN delay slot? What happens to OPR_R?
------------------------------------------|----------------------------------------------------------------------------------------------
71C TASKGATE: PTR = &DES_TR; DLY; PTSAV1 TST_DES_TSSTSG; // TST_DES_TSSTSG can go to #NP(I0,E0) or AVAIL_TSS or continue Does PTSAV1 put addr from pla4 into ret? LD_DESCRIPTOR is normally called...
71D goto LD_DESCRIPTOR; // Load new TR descriptor
71E SLCTR = SIGMA; PTSELA TST_SEL_TASKGT; DLY; // TST_SEL_TASKGT can go to #GP/#TS(I0,E0) or continue (L)
------------------------------------------|----------------------------------------------------------------------------------------------
71F AVAIL_TSS: TMPG = SIGMA;
720 SIGMA = PROTUN | 0x8200; // Set Present and TSS Busy bits?
721 PROTUN = SIGMA;
722 goto SWITCH_TASK;
723 SIGMA = TMPG;
------------------------------------------|----------------------------------------------------------------------------------------------
724 SAVE_TASK: SLCTR2 = TR; if (BITS == 16) goto SAVE_TASK_16; // SIGMA is 0x5c on entry to SAVE_TASK = Offset of GS in 386 Task State Segment.
725 BITS16;
726 DES_TR; TASK_SAVED = true; DLY; IND = SIGMA;
727 OPR_W = GS; BITS32; WR_W; // Write GS
728 IND_DELTA = NEGWSZ; IND += IND_DELTA; TSS_ACCESS_FLAG = true; DLY;
729 OPR_W = FS; goto SAVE_TASK_COMM; WR_W; // Write FS
72A DLY; IND += IND_DELTA; // IND_DELTA set to NEGWSZ at 728
------------------------------------------|----------------------------------------------------------------------------------------------
72B SAVE_TASK_16: COUNTR = 0x29;
72C SIGMA = COUNTR - 1; // SIGMA = 0x28 = Offset of DS in 286 Task State Segment
72D DES_TR; TASK_SAVED = true; DLY; IND = SIGMA;
72E SAVE_TASK_COMM: OPR_W = DS; TSS_ACCESS_FLAG = true; WR_W; // Write DS
72F IND_DELTA = NEGWSZ; IND += IND_DELTA; DLY;
730 OPR_W = SS; WR_W; // Write SS
731 DLY; IND += IND_DELTA; // IND_DELTA set to NEGWSZ at 72f
732 OPR_W = CS; COUNTR = 7; WR_W; // Write CS
733 DLY; IND += IND_DELTA; // IND_DELTA set to NEGWSZ at 72f
734 OPR_W = ES; WR_W; // Write ES
735 DLY; IND += IND_DELTA; // IND_DELTA set to NEGWSZ at 72f
736 OPR_W = IRF[COUNTR] --COUNTR; WR; // Write EDI COUNTR = 6
737 SAVE_TASK_LOOP: DLY; IND += IND_DELTA; // IND_DELTA set to NEGWSZ at 72f
738 if (COUNTR != 0) goto SAVE_TASK_LOOP;
739 OPR_W = IRF[COUNTR]; --COUNTR; WR; // Write ESI, EBP, ESP, EBX, EDX, ECX, EAX
73A SIGMA = EFLAGS & 0x37fd7; DLY; IND += IND_DELTA; // IND_DELTA set to NEGWSZ at 72f
73B OPR_W = SIGMA; WR; // Write eFLAGS
73C COUNTR = 0x5d; DLY; IND += IND_DELTA; // IND_DELTA set to NEGWSZ at 72f
73D OPR_W = EIP; WR; RETURN; // Write EIP
73E CLT; DLY; IND += IND_DELTA; // IND_DELTA set to NEGWSZ at 72f
------------------------------------------|----------------------------------------------------------------------------------------------
73F CALL_SAVE_TASK: SAVE_TASK();
740 SIGMA = COUNTR - 1;
741 DES_TR.DEH = TMPB; DLY; goto LOAD_TASK;
742 SLCTR2 = TMPG; DES_TR.DES = TMPD; // descriptor selected above?
------------------------------------------|----------------------------------------------------------------------------------------------
743 AVAIL_TSS_PR: TMPG = SIGMA; // This is very similar to AVAIL_TSS but with an extra test
744 SIGMA = PROTUN | 0x8200; // Set Present and TSS Busy bits?
745 PROTUN = SLCTR2; PTSELA TST_SEL_TASKGT // TST_SEL_TASKGT can go to #GP/#TS(I0,E0) or continue (L)
746 RPT; // exhaust one of the PTSELA's delay slots?
747 PROTUN = SIGMA; goto SWITCH_TASK; // Odd, this jump seems to be a no-op?
748 SIGMA = TMPG;
------------------------------------------|----------------------------------------------------------------------------------------------
749 SWITCH_TASK: TMPD = SIGMA; COUNTR = 0x5d;
74A SIGMA = SLCTR2 & 0xffff; DLY;
74B DESSDT; TSS_ACCESS_FLAG = true; IND_DELTA = 4; IND = SLCTR + IND_DELTA;
74C OPR_W = PROTUN; WR_W; if (!TASK_SAVED) goto CALL_SAVE_TASK; // Mark TSS as busy in descriptor
74D TMPG = SIGMA; // TMPG = SLCTR2 & 0xffff
74E DES_TR.DEH = TMPB; DLY;
74F SLCTR2 = TMPG; DES_TR.DES = TMPD; // descriptor selected above?
750 LOAD_TASK: BITS32; DES_TR.DEL = TMPC; // descriptor selected above? TODO: Check that we're also referring to DES_TR when we come in here via a jump to LOAD_TASK
751 TMPC = TR; SHLCNT = 0x10;
752 SIGMA = (0:TMPC) << SHLCNT; // SIGMA = TR << 16;
753 TMPC = SIGMA; // TMPC = TR << 16
754 DESABS; DLY; IND_DELTA = TMPC; IND = TMPG + IND_DELTA
755 TSDB; if (!MISC1 && !INTERRUPT_HW) goto TR_BACKLINK_OK;
756 DES_TR; DLY; IND = 0;
757 OPR_W = TR; WR_W; // Update backlink in TSS
758 TR_BACKLINK_OK: TMPE = 0; if (BITS == 16) goto LOAD_TASK_16;
759 DES_TR; BITS32; DLY; IND = 0x60;
75A LOAD_TASK_32: SIGMA = -1; RD_W; // Read from TR:0x60
75B TMPD = SIGMA; IND_DELTA = -4; IND += IND_DELTA; DLY; // TMPD = -1 IND = 0x5c
75C LDT = OPR_R; UNL; RD_W; // LDT = W[TR:0x60] Read from TR:0x5c
75D DLY; IND += IND_DELTA; // IND = 0x58 IND_DELTA set to -4 at 75b
75E GS = OPR_R; UNL; RD_W; // GS = W[TR:0x5c] Read from TR:0x58
75F DLY; IND += IND_DELTA; // IND = 0x54 IND_DELTA set to -4 at 75b
760 FS = OPR_R; UNL; RD_W; // FS = W[TR:0x58] Read from TR:0x54
761 DLY; IND += IND_DELTA; // IND = 0x50 IND_DELTA set to -4 at 75b
762 DS = OPR_R; UNL; RD_W; goto LOAD_TASK_COMM; // DS = W[TR:0x54] Read from TR:0x50
763 DLY; IND += IND_DELTA; // IND = 0x4c IND_DELTA set to -4 at 75b
------------------------------------------|----------------------------------------------------------------------------------------------
764 LOAD_TASK_16: COUNTR = 0x29; // 16 bit 32 bit
765 LOAD_TASK_16A: DES_TR; BITS16; IND_DELTA = 1; IND = COUNTR + IND_DELTA; DLY; // IND = 0x2a (&LDT)
766 SIGMA = 0xffff; RD_W; // Read from TR:0x2a
767 TMPD = SIGMA; DLY; IND_DELTA = -2; IND += IND_DELTA; // IND = 0x28 (&DS) TMPD = 0xffff
768 LDT = OPR_R; UNL; RD_W; // LDT = W[TR:0x2a] Read from TR:0x28
769 DLY; IND += IND_DELTA; // IND = 0x26 (&SS) IND_DELTA set to -2 at 767
76A DS = OPR_R; UNL; // DS = W[TR:0x28]
76B FS = 0; RD_W; // Read from TR:0x26
76C GS = 0; DLY; IND += IND_DELTA; // IND = 0x24 (&CS) IND_DELTA set to -2 at 767
76D LOAD_TASK_COMM: SS = OPR_R; COUNTR = 7; UNL; RD_W; // SS = W[TR:0x26] Read from TR:0x24 SS = W[TR:0x50] Read from TR:0x4c
76E SIGMA = -1 - TMPD; DLY; IND += IND_DELTA; // SIGMA = 0xffff0000 IND = 0x22 IND = 0x48 SIGMA = 0 (&ES)
76F CS = OPR_R; UNL; RD_W; // CS = W[TR:0x24] Read from TR:0x22 CS = W[TR:0x4c] Read from TR:0x48
770 IND_DELTA = NEGWSZ; IND += IND_DELTA; TMPC = SIGMA; DLY; // IND = 0x20 TMPC = 0xffff0000 IND = 0x44 TMPC = 0 (&DI/&EDI)
771 ES = OPR_R; UNL; RD; // ES = W[TR:0x22] Read from TR:0x20 ES = W[TR:0x48] Read from TR:0x44
772 TMPE = 0; DLY; IND += IND_DELTA; // IND = 0x1e IND = 0x40 (&SI/&ESI)
773 LOAD_TASK_LOOP; SIGMA = OPR_R | TMPC; UNL; RD; // SIGMA = OPR_R | 0xffff0000 Read from TR:0x1e..TR:0x10 Read from TR:0x40..TR:0x24 SIGMA = OPR_R
774 IRF[COUNTR] = SIGMA; if (COUNTR != 0) goto LOAD_TASK_LOOP; DLY; IND += IND_DELTA; // Store to registers 7..0
775 --COUNTR;
776 PTF READ_RPL; PROTUN = CS;
777 SIGMA = OPR_R & TMPD; UNL; RD; // SIGMA = W[TR:0x10] & 0xffff Read from TR:0x0e Read from TR:0x20 SIGMA = [TR:0x24]
778 EFLAGS = SIGMA; COUNTR = 0; DLY; IND += IND_DELTA; // EFLAGS = W[TR:0x10] & 0xffff IND = 0x0c IND = 0x1c EFLAGS = [TR:0x24] (&SS2/&CR3) COUNTR = 0 here so we don't set CR3 in the 16-bit case
779 eIP = OPR_R; if (BITS == 16) goto LOAD_TASK_NOPG; UNL; // eIP = W[TR:0x0e] Skip paging stuff in 16-bit mode EIP = [TR:0x20]
77A SIGMA = SIGN CR0; // if paging enabled then SIGMA = 0xffffffff else SIGMA = 0 ?
77B TMPB = SIGMA; RD_D; // TMPB = PG ? 0xffffffff : 0 Read from TR:0x1c
77C DLY;
77D IRF2 = PDBR.PCR;
77E TMPD = IRF2; DLY; // TMPD = PDBR.PCR = oldCR3
77F TMPC = OPR_R; SIGMA = OPR_R - TMPD; UNL; // SIGMA = newCR3 - oldCR3 TMPC = newCR3
780 DES_TR; IND_DELTA = 0x65; IND = -1 + IND_DELTA; DLY; // IND = 0x64
781 SIGMA &= TMPB; RD_W; // SIGMA = (newCR3 - oldCR3) & (PG ? 0xffffffff : 0) Read from W[TR:0x64] = debug trap bit and IO MAP BASE in 32-bit TSS
782 COUNTR = SIGMA; DLY; // COUNTR = (newCR3 - oldCR3) & (PG ? 0xffffffff : 0)
783 SIGMA = OPR_R & 1; UNL; // SIGMA = W[TR:0x64] & 1 == debug trap bit
784 TMPE = SIGMA; // TMPE = debug trap bit
785 LOAD_TASK_NOPG: TMPeSP = ESP; // Back to both 16-bit and 32-bit
786 TMPeIP = EIP; FLAGS_BACKED_UP = true;
787 if (!MISC1 && !INTERRUPT_HW) goto NOT_NESTED_TSK; SLCTR2 = TR;
788 FLAGSB = EFLAGS; SIGMA = EFLAGS | 0x4000; // Set Nested Task flag
789 FLAGSB = SIGMA;
78A EFLAGS = SIGMA; goto SET_TSKSWTCHED;
78B TR = TMPG; TASK_SAVED = false;
------------------------------------------|----------------------------------------------------------------------------------------------
78C NOT_NESTED_TSK: SLCTR2; DLY; // TODO: What are we doing with SLCTR2 here?
78D DESSDT; IND_DELTA = 4; IND = SLCTR + IND_DELTA;
78E TR = TMPG; rd_W; // Read W[DT:SLCTR+4]
78F DLY;
790 SIGMA = OPR_R & ~0x200; UNL; // SIGMA = W[DT:SLCTR+4] & 0xfffffdff Clear bit 9 => mark TSS as available
791 OPR_W = SIGMA; TASK_SAVED = false; WR_W; // Write back modified descriptor
792 SET_TSKSWTCHED: DESABS; if (COUNTR == 0) goto WRITE_BACK_CR0; DLY; IND = TMPC; // COUNTR (set at 782) is 0 if paging is disabled or if the new CR3 is the same as the old CR3. In these cases we can skip flushing the TLB
793 SIGMA = CR0 | 8; // Set "Task Switched" bit
794 PDBR.PCR = IND; // Load new CR3 value, flushing the TLB
795 WRITE_BACK_CR0: CR0 = SIGMA; COUNTR = 0x65;
796 TMPC = CS; goto TASK_FINAL_PM;
797 if (VM) goto TASK_FINAL_V86; // !VM case: execution continues at 7ab == TASK_FINAL_PM from jump at 796. VM case: one line at 7ab == TASK_FINAL_PM executed and then continues at 798 == TASK_FINAL_V86
------------------------------------------|----------------------------------------------------------------------------------------------
798 TASK_FINAL_V86: PROTUN = -1; PTF COPY_STACK_DPL; // (KN)
799 DES_FS.BASE = FS << 4;
79A DES_DS.BASE = DS << 4;
79B DES_SS.BASE = SS << 4;
79C DES_CS.BASE = CS << 4;
79D DES_GS.BASE = GS << 4; SIGMA = 0xffff;
79E TMPG = SIGMA; SHLCNT = 0x0d; DLY; // TMPG = 0xffff
79F SIGMA = (0:3) << SHLCNT; // SIGMA = 3 << 13 = 0x6000
7A0 SIGMA |= 0x8200; // SIGMA = 0xe200
7A1 TASK_FV86_LOOP: DES_ES.BASE = ES << 4;
7A2 IRF[COUNTR].AR = SIGMA; if ((COUNTR & 15) != 1) goto TASK_FV86_LOOP; // COUNTR = 0x65 => DES_GS Set all AR bytes to 0xe2 == present, ring 3, LDT
7A3 IRF[COUNTR].LIMIT = TMPG; --COUNTR; // Set all limits to 0xffff
7A4 DES_ES.AR = SIGMA;
7A5 DES_ES.LIMIT = TMPG;
7A6 PTR = &DESLDT; DLY; PTSAV1 TST_DES_LDT // TST_DES_LDT can go to #NP(I0,E0), PROT_TESTS_PASSED (RETURNs) or continue.
7A7 LD_DESCRIPTOR(); // Load new LDT descriptor
7A8 SLCTR = LDTR; PTSELA TST_SEL_TR_TSF; DLY; // TST_SEL_TR_TSF can go to NULL_SELECTOR2 (RETURNs), #GP/#TS(I0,E0), or continue.
7A9 goto HANDLE_TS_BP;
7AA COUNTR = TMPE; PTR->DEL = TMPC; // descriptor selected previously?
------------------------------------------|----------------------------------------------------------------------------------------------
7AB TASK_FINAL_PM: SHLCNT = 0x0d; DLY;
7AC DESLDT.AR = 0; SIGMA = (0:TMPC) << SHLCNT; // SIGMA = TMPC << 13
7AD PROTUN = SIGMA; PTF COPY_STACK_DPL; // (KN)
7AE DES_GS.AR = 0;
7AF DES_FS.AR = 0;
7B0 DES_DS.AR = 0;
7B1 DES_SS.AR = 0;
7B2 DES_ES.AR = 0;
7B3 PTR = &DESLDT; PTSAV1 TST_DES_LDTTSK; DLY; // TST_DES_LDTTSK can go to #GP/#TS(I0,E0), PROT_TESTS_PASSED (RETURN) or continue.
7B4 LD_DESCRIPTOR(); // Load new LDT descriptor
7B5 SLCTR = LDT; PTSELA TST_SEL_TR_TSF; DLY; // TST_SEL_TR_TSF can go to NULL_SELECTOR2 (RETURNs), #GP/#TS(I0,E0), or continue.
7B6 PTR->DEL = TMPC; // descriptor selected previously?
7B7 PTR = &DES_SS; DLY; PTSAV7 TST_DES_SS; // TST_DES_SS can jump to #SS(I0,E0) or PROT_TESTS_PASSED (KN) (RETURNs) or continue.
7B8 LD_DESCRIPTOR(); // Load new SS descriptor
7B9 SLCTR = SS; DLY; PTSELA TST_SEL_MOREPR; // TST_SEL_MOREPR can go to #GP/#TS(I0,E0) or continue.
7BA PTR->DEL = TMPC; // descriptor selected previously?
7BB PTR = &DES_CS; DLY; PTSAV7 TST_DES_JGDEST; // TST_DES_JGDEST can go to #NP(I0,E0), PROT_TESTS_PASSED2 (N) (RETURN) or continue
7BC LD_DESCRIPTOR(); // Load new CS descriptor
7BD SLCTR = CS; DLY; PTSELE TST_SEL_CS; // TST_SEL_CS can go to #GP/#TS(I0,E0) or continue (L)
7BE PTR->DEL = TMPC; // descriptor selected previously?
7BF PAGER5.PCR;
7C0 PTR = &DES_DS; DLY; PTSAV1 TST_DES_SIMPLE; // TST_DES_SIMPLE can go to #NP(I0,E0), PROT_TESTS_PASSED (N) (RETURNs) or continue
7C1 LD_DESCRIPTOR(); // Load new DS descriptor
7C2 SLCTR = DS; DLY; PTSELA TST_SEL_TASKFI; // TST_SEL_TASKFI can go to NULL_SELECTOR2 (RETURNs) or continue (L)
7C3 PTR->DEL = TMPC; // descriptor selected previously?
7C4 PTR = &DES_ES; DLY; PTSAV1 TST_DES_SIMPLE; // TST_DES_SIMPLE can go to #NP(I0,E0), PROT_TESTS_PASSED (N) (RETURNs) or continue
7C5 LD_DESCRIPTOR(); // Load new ES descriptor
7C6 SLCTR = ES; DLY; PTSELA TST_SEL_TASKFI; // TST_SEL_TASKFI can go to NULL_SELECTOR2 (RETURNs) or continue (L)
7C7 PTR->DEL = TMPC; // descriptor selected previously?
7C8 PTR = &DES_FS; DLY; PTSAV1 TST_DES_SIMPLE; // TST_DES_SIMPLE can go to #NP(I0,E0), PROT_TESTS_PASSED (N) (RETURNs) or continue
7C9 LD_DESCRIPTOR(); // Load new FS descriptor
7CA SLCTR = FS; DLY; PTSELA TST_SEL_TASKFI; // TST_SEL_TASKFI can go to NULL_SELECTOR2 (RETURNs) or continue (L)
7CB PTR->DEL = TMPC; // descriptor selected previously?
7CC PTR = &DES_GS; DLY; PTSAV1 TST_DES_SIMPLE; // TST_DES_SIMPLE can go to #NP(I0,E0), PROT_TESTS_PASSED (N) (RETURNs) or continue
7CD LD_DESCRIPTOR(); // Load new GS descriptor
7CE SLCTR = GS; DLY; PTSELA TST_SEL_TASKFI; // TST_SEL_TASKFI can go to NULL_SELECTOR2 (RETURNs) or continue (L)
7CF PTR->DEL = TMPC; COUNTR = TMPE; BITS32; // TMPE set to debug trap bit on line 784
7D0 HANDLE_TS_BP: if (!ERROR_CODE_FLAG) goto TSKF_NO_ERRCOD; DESCOD; DLY; IND = EIP; // Last phase of task switching - handle breakpoints
7D1 TMPB = TMPF; PREF;
7D2 if (BITS == 16) goto ADJ_STACK_16;
7D3 DESSTK; SIGMA = ESP - 4; DLY; IND_DELTA = -4; IND = ESP + IND_DELTA;
7D4 ADJ_STACK_DONE: SHRCNT = 0x10; eSP = SIGMA;
7D5 SIGMA = (0:TMPB) >> SHRCNT; // SIGMA = TMPB >> 16;
7D6 OPR_W = SIGMA; WR_W; // Push error code?
7D7 TSKF_NO_ERRCOD: TMPB = DR7; SIGMA = 0x65; DLY;
7D8 SIGMA -= 0x10; // SIGMA = 0x55;
7D9 SIGMA ^= -1; // SIGMA = 0xffffffaa;
7DA TMPC = SIGMA; SHLCNT = 2;
7DB SIGMA = (0:TMPC) << SHLCNT; // SIGMA = 0xffffffaa << 2 = 0xfffffea8;
7DC SIGMA |= 2; // SIGMA = 0xfffffeaa;
7DD SIGMA &= TMPB; // SIGMA = 0xfffffeaa & DR7; Bit pattern 1111 1111 1111 1111 1111 1110 1010 1010
7DE DR7 = SIGMA; // Disable all local breakpoints and Local Exact Breakpoint Enable
7DF if ((COUNTR & 15) != 1) goto NO_DEBUG_BP; TMPeIP = EIP; // if debug trap bit is 0 then we're done
7E0 SIGMA = DR6 | 0x8200; RNi; // RNi means RNI only if it's executed in the delay slot, and 7eb is a convenient empty uop
7E1 goto BREAKPOINT;
7E2 DR6 = SIGMA; // Set DR6 bits 15 BT "Task Switch Breakpoint" and 9 (reserved)
------------------------------------------|----------------------------------------------------------------------------------------------
7E3 ADJ_STACK_16: goto ADJ_STACK_DONE;
7E4 DESSTK; SIGMA = ESP - 2; IND_DELTA = -2; IND = ESP + IND_DELTA;
------------------------------------------|----------------------------------------------------------------------------------------------
7E5 NULL_SELECTOR2: IND_DELTA = 4; IND += IND_DELTA; DLY; // Occurs after 5cb in LD_DESCRIPTOR. IND = SLCTR + 4 i.e. IND set to high dword of descriptor (containing access byte)
7E6 UNL; wr_W; RETURN; // Write back access byte (but what has changed?)
7E7 PTR->DEH = 0; DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
7E8 AVAIL_TSS_NP: PROTUN = SLCTR2; PTSELA TST_SEL_TASKGT // TST_SEL_TASKGT can go to #GP/#TS(I0,E0) or continue (L)
7E9
7EA goto #NP(I0,E0);
7EB NO_DEBUG_BP:
------------------------------------------|----------------------------------------------------------------------------------------------
7EC CLI_STI: DESCOD; IND = EIP;
7ED PREF;
7EE DLY;
7EF FLGOPS; // 0 CLC/STC/CLD/STD/CMC
7F0 RNI;
7F1
------------------------------------------|----------------------------------------------------------------------------------------------
7F2 eSP = SIGMA; // 2 p PUSHFd
7F3 SIGMA = EFLAGS & 0xffff; // PUSHFD in protected mode stores the RF and VM flags as 0?
7F4 SIGMA &= 0x37fd7; // SIGMA = EFLAGS & 0x7fd7;
7F5 OPR_W = SIGMA; WR; RNI;
7F6 DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
7F7 if (CPL <= IOPL) goto CLI_STI; // 0 CLI/STI
7F8 BITS32;
------------------------------------------|----------------------------------------------------------------------------------------------
7F9 if (CPL <= IOPL) goto "p PUSHFd"; // 2 r PUSHFd
7FA
------------------------------------------|----------------------------------------------------------------------------------------------
7FB if (CPL <= IOPL) goto "p POPFd"; // 3 r POPFd
7FC
------------------------------------------|----------------------------------------------------------------------------------------------
7FD if (CPL <= IOPL) goto "p INT ib"; // 0 r INT ib
7FE
------------------------------------------|----------------------------------------------------------------------------------------------
7FF if (CPL <= IOPL) goto IRET_REAL_MODE; // 3 r IRETd
800 // PLAJMP destinations for v86 mode, IRET_REAL_MODE for actual real mode? "CPL is always three in V86 mode; therefore, if IOPL < 3, these instructions will trigger a general-protection exceptions."
------------------------------------------|----------------------------------------------------------------------------------------------
801 OVERLONG_INST: goto #GP/#TS(I0,E0);
802 SLCTR2 = 0; PTGEN SET_FAULT;
------------------------------------------|----------------------------------------------------------------------------------------------
803 eSP = SIGMA; RD; // 3 p POPFd SIGMA initially set to eSP+WORDSZ
804 BITS16; DLY; // Setting BITS16 (after the RD) because POPFD does not modify the resume and V86 flags? (https://www.felixcloutier.com/x86/popf:popfd:popfq suggests RF is cleared)
805 SIGMA = OPR_R; UNL; // TODO: What is UNL?
806 FLAGS = SIGMA; RNI; // Don't really need to BITS16 since we're writing to FLAGS instead of EFLAGS?
807
------------------------------------------|----------------------------------------------------------------------------------------------
808 goto INTERRUPT; // 0 p INT ib
809 SIGMA = IMM;
------------------------------------------|----------------------------------------------------------------------------------------------
80A IRET_REAL_MODE: SIGMA += WORDSZ; RD; // Non-v86 real mode First read is offset? segment?
80B FLAGSB = EFLAGS; FLAGS_BACKED_UP = true; DLY; IND_DELTA = WORDSZ; IND += IND_DELTA;
80C SIGMA += WORDSZ; RD; // Second read is segment? offset?
80D TMPG = OPR_R; CLRNMI; UNL; // TMPG = value from first read
80E eSP = SIGMA; IND_DELTA = WORDSZ; IND += IND_DELTA; DLY;
80F COUNTR = OPR_R; SIGMA = 0xffff; UNL; RD; // COUNTR = value from second read Third read is flags
810 SIGMA += 0xffff; // SIGMA = 0x1fffe
811 SIGMA |= 0xffff; DLY; // SIGMA = 0x1ffff
812 TMPB = SIGMA; // TMPB = 0x1ffff
813 SIGMA = OPR_R & TMPB; UNL; // SIGMA = OPR_R & 0x1ffff Clear VM flag (don't allow real mode IRET to enable V86 mode)
814 DLY; goto JMP_FAR_RM;
815 FLAGS = SIGMA; // FLAGS = OPR_R & 0x1ffff
------------------------------------------|----------------------------------------------------------------------------------------------
816 goto INTERRUPT; // 0 INT 3
817 SIGMA = 3; // "Interrupt 3 Breakpoint"
------------------------------------------|----------------------------------------------------------------------------------------------
818 SIGMA = 7; RD; // 1 BOUND rv,m2v read lower bound
819 TMPB = SIGMA; IND_DELTA = WORDSZ; IND += IND_DELTA; DLY; // TMPB = 7
81A SIGMA = OPR_R - SRCREG; UNL; RD; // read upper bound
81B DLY;
81C TMPC = OPR_R; UNL; if (JG) goto #BR; // if (OPR_R > SRCREG) goto BOUD_RANGE_EX;
81D SIGMA = SRCREG - TMPC;
81E // Why is this blank? Need a cycle to update flags between SUB and JL?
81F if (JG) goto #BR;
820 RNI;
821
------------------------------------------|----------------------------------------------------------------------------------------------
822 #BR: goto FAULT;
823 SIGMA = TMPB + -2; // SIGMA = 5 "Interrupt 5 Bounds Check"
------------------------------------------|----------------------------------------------------------------------------------------------
824 DIVIDE_ERROR: CONTRIBUTORY_FAULT = true;
825 goto FAULT;
826 SIGMA = 0; // "Interrupt 0 Divide Error"
------------------------------------------|----------------------------------------------------------------------------------------------
827 if (OVERFLOW_FLAG == 0) goto NO_OVERFLOW; // 0 INTO
828 SIGMA = 4; RNi; // RNi means "RNI but only if it's executed in the delay slot"
829 goto INTERRUPT;
82A NO_OVERFLOW: // If O then no jump so RNi does nothing and we go to INTERRUPT and this is the delay slot. If NO then jump here but RNi executed in the delay slot and this is the empty delay slot for the RNi.
------------------------------------------|----------------------------------------------------------------------------------------------
82B #UD: goto FAULT;
82C SIGMA = 6;
------------------------------------------|----------------------------------------------------------------------------------------------
82D HARDWARE_IRQ: TMPeSP = ESP; ICESIG; // TODO: Saved ESP?
82E DESABS; BITS32; DLY; IND = 4; // HRM 3.1.7 "The address driven during the first cycle is 4;"
82F TMPeIP = EIP; SHRCNT = 8; IACK; // "BE3#, BE2#, and BE1# are high, BE0# is low"
830 DESABS; CINTLA; DLY; IND = 0; // HRM 3.1.7 "during the second cycle, the address is 0."
831 SIGMA = (0:0xffff) >> SHRCNT; UNL; // SIGMA = 0xffff >> 8 = 0xff
832 RPT; // not sure what this is for - no slow operation to wait for
833 TMPB = SIGMA; IACK; // TMPB = 0xff
834 DLY; goto INTERRUPT_X;
835 SIGMA = OPR_R & TMPB; UNL; // Mask off low 8 bits of PIC response as interrupt vector number
------------------------------------------|----------------------------------------------------------------------------------------------
836 NMI: TMPeSP = ESP; SETNMI; // SETNMI sets "NMI processing" flag to avoid further NMI interrupts until we're done with this one? Gets reset by something in IRET
837 goto INTERRUPT_X;
838 TMPeIP = EIP; SIGMA = 2; // "Interrupt 2 NMI"
------------------------------------------|----------------------------------------------------------------------------------------------
839 TRIPLE_FAULT: ICESIG;
83A TRIPLE_FT_WAIT: if (JICEWT) goto TRIPLE_FT_WAIT;
83B
83C CONTRIBUTORY_FAULT = true; OPR_R;
83D goto HLT_SHUTDOWN;
83E DESABS; DLY; IND = 0; // "For a shutdown condition, BE0# is active" (HRM 3.1.8)
------------------------------------------|----------------------------------------------------------------------------------------------
83F #DF: SIGMA = TMPF & 0xffff; DLY; // TODO: Why DLY?
840 TMPF = SIGMA; ERROR_CODE_FLAG = true;
841 SIGMA = 8;
842 goto FAULT;
843 CONTRIBUTORY_FAULT = true; // "Interrupt 8 Double Fault"
------------------------------------------|----------------------------------------------------------------------------------------------
844 NO_PRIVILEGE: CONTRIBUTORY_FAULT = true;
845 ERROR_CODE_FLAG = true;
846 SIGMA = TMPF & 0xffff;
847 goto FAULT;
848 TMPF = SIGMA; SIGMA = 0x0d; // "Interrupt 0x0d General Protection Exception"
------------------------------------------|----------------------------------------------------------------------------------------------
849 unused?: PTGEN SET_FAULT; // Is there actually any way to get here or is it an instruction removed from the decoder?
84A SIGMA = TMPF & 0xffff; // Assuming this was a removed instruction, it unconditionally causes a page fault exception with the error code set to the last error code from the paging unit and CR2 set to some mysterious value from the paging unit instead of the fault linear address. What could this mysterious value be?
84B BITS32; // TODO: What is BITS32?
84C // TODO: Why is this line blank?
84D SHLCNT = 0x10; TMPB = SIGMA; // TMPB = TMPF & 0xffff
84E SIGMA = (0:7) << SHLCNT; // SIGMA = 7 << 16 = 0x70000
84F TMPC = SIGMA; DLY; // TMPC = 0x70000
850 IRF2 = PFERRC.PCR; ERROR_CODE_FLAG = true;
851 SIGMA = IRF2 & TMPC; DLY; // SIGMA = IND & 0x70000
852 IRF2 = PGUNUS.PCR; SIGMA |= TMPB; // SIGMA = (IND & 0x70000) | (TMPF & 0xffff) - another LATTTF?
853 CR2 = IRF2; CONTRIBUTORY_FAULT = true; DLY; // "CR2 is used for handling page faults when PG is set. The processor stores in CR2 the linear address that triggers the fault."
854 TMPF = SIGMA; SIGMA = 0x0d; // TMPF = (IND & 0x70000) | (TMPF & 0xffff)
855 goto FAULT;
856 SIGMA += 1; // SIGMA = 0xe means "Interrupt 0x0e Page Fault"
------------------------------------------|----------------------------------------------------------------------------------------------
857 ACCESS_VIOLATI: IRF2 = DESERR.AR; // We get here from the small PLA, so probably in response to some non-microcode signal. Limit, RO, EO, null selector, privilege?
858 IRF2 = PROTUN.AR; PTGEN TST_ACCESS_VIO; // TST_ACCESS_VIO can go to #GP(0), #GP/#TS(SIGMA), #SS(0), #SS(SIGMA), #GP(SIGMA | 2) or continue The value we're testing seems to be a descriptor index. The incantation to test it is strange, though - I have no idea how it works
859 SIGMA = SLCTR2 & -4; RPT; // exhaust (one of) the PTGEN's delay slots? EXT = 0, I = 0
85A CONTRIBUTORY_FAULT = true;
85B #GP(0): goto FAULT_ERR_CODE;
85C TMPE = 0; SIGMA = 4; // SIGMA = 4 means "Interrupt 0x0d General Protection Exception"
------------------------------------------|----------------------------------------------------------------------------------------------
85D #GP/#TS(I0,E0): SIGMA = SLCTR2 & -4; // EXT = 0, I = 0
85E #GP/#TS(SIGMA): if (TSS_ACCESS_FLAG) goto #TS(SIGMA);
85F
860 #GP(SIGMA): goto FAULT_ERR_CODE;
861 TMPE = SIGMA; SIGMA = 4; // SIGMA = 4 means "Interrupt 0x0d General Protection Exception"
------------------------------------------|----------------------------------------------------------------------------------------------
862 #SS(0): SIGMA = 0;
863 #SS(SIGMA): goto FAULT_ERR_CODE;
864 TMPE = SIGMA; SIGMA = 3; // SIGMA = 3 means "Interrupt 0x0c Stack Exception"
------------------------------------------|----------------------------------------------------------------------------------------------
865 #GP(I1,E0): SIGMA = SLCTR2 & -4; // See 871 EXT = 0 #GP(I1,E0) == #GP((SLCTR2 & -4) | 2)
866 #GP(SIGMA | 2): goto #GP(SIGMA);
867 SIGMA |= 2; // I = 1 => the index portion of the error code refers to a gate descriptor in the IDT
------------------------------------------|----------------------------------------------------------------------------------------------
868 #TS(SIGMA): goto FAULT_ERR_CODE;
869 TMPE = SIGMA; SIGMA = 1; // SIGMA = 1 means "Interrupt 0x0a Invalid TSS"
------------------------------------------|----------------------------------------------------------------------------------------------
86A #SS(I0,E0): SIGMA = SLCTR2 & -4; // See 871 mask off RPL bits EXT = 0, I = 0 #SS(I0,E0) == #SS(SLCTR2 & -4)
86B DLY; goto FAULT_ERR_CODE;
86C TMPE = SIGMA; SIGMA = 3; // TMPE = SLCTR2 & -4; SIGMA = 3 means "Interrupt 0x0c Stack Exception"
------------------------------------------|----------------------------------------------------------------------------------------------
86D FAULT_SUPPRESS: if (JICEWT) goto FAULT_SUPPRESS; // RNI is in the delay slot - does that break the loop? (No, RNI is suppressed if it's in the delay slot)
86E LAR_LSL_VERRW_NULL_SELECTOR: CLZF; RNI;
86F OPR_R; // Ack bus
------------------------------------------|----------------------------------------------------------------------------------------------
870 #NP(I0,E0): goto NP_COMMON; // #NP(I0,E0) == #NP(SLCTR2 & -4) EXT = 0, I = 0
871 #NP(I1,E0): SIGMA = SLCTR2 & -4; // #NP(I1,E0) == #NP((SLCTR2 & -4)|2) EXT = 0, I = 1
872 SIGMA |= 2; // SIGMA = (SLCTR2 & -4) | 2
873 NP_COMMON: TMPE = SIGMA; SIGMA = 2; // SIGMA = 2 means "Interrupt 0x0b Segment Not Present"
874 FAULT_ERR_CODE: if (NO_FAULT) goto FAULT_SUPPRESS; // TMPE on entry here is fault error code
875 SIGMA += 9;
876 CONTRIBUTORY_FAULT = true;
877 TMPC = SIGMA; BITS32; // TODO: What is BITS32? Store interrupt number to TMPC
878 if (EVENT_EXTERNAL_TO_PROGRAM) goto EXT_BIT_DONE; // "The processor sets the EXT bit if an event external to the program caused the exception." - where does this information come from? happens when we come through smallpla?
879 SIGMA = TMPE | 1;
87A SIGMA = TMPE & 0xfffffffe; // EXT bit cleared - event was internal to the program
87B EXT_BIT_DONE: TMPB = SIGMA; SHLCNT = 0x10; // TMPB = (TMPE & 0xfffffffe) | EXT
87C SIGMA = (0:TMPB) << SHLCNT; // SIGMA = TMPB << 16
87D TMPB = SIGMA; ERROR_CODE_FLAG = true; // TMPB = TMPB << 16 = ((TMPE & 0xfffffffe) | EXT) << 16
87E SIGMA = TMPF & 0xffff; // SIGMA = TMPF & 0xffff
87F SIGMA |= TMPB; // SIGMA = (TMPF & 0xffff) | (((TMPE & 0xfffffffe) | EXT) << 16)
880 TMPF = SIGMA; goto FAULT; // TMPF = (TMPF & 0xffff) | (((TMPE & 0xfffffffe) | EXT) << 16)
881 SIGMA = TMPC; // Restore interrupt number from TMPC
------------------------------------------|----------------------------------------------------------------------------------------------
882 STRING_CORRECT: SIGMA = COUNTR + 1; // Seems like this corrects ECX/EDI/ESI for interrupted string operations (but not IRQ/NMI/debug?) so they can be resumed
883 TMPB = SIGMA; SIGMA = WORDSZ; // TMPB = COUNTR + 1
884 COUNTR = SIGMA; SIGMA = SIGMA - INCREM; // COUNTR = WORDSZ; SIGMA = WORDSZ - INCREM This SIGMA isn't used directly - setting flags for JG to test?
885 TMPC = eCX; CREPF;
886 if (JG) goto STRCORR_DOWN; eCX = TMPB; // eCX = COUNTR + 1
887 SIGMA = TMPB - TMPC; // SIGMA = (COUNTR + 1) - old_eCX < 0
888 SIGMA = TMPC - TMPB; // SIGMA = old_eCX - (COUNTR + 1) > 0
889 STRCORR_DOWN: TMPC = SIGMA; SIGMA += ESI;
88A STRCORR_LOOP: eSI = SIGMA; --COUNTR;
88B SIGMA = TMPC + EDI;
88C eDI = SIGMA; if (COUNTR != 0) goto STRCORR_LOOP; // loop executes WORDSZ times (1, 2, or 4)
88D SIGMA = TMPC + ESI;
88E goto INTERRUPT_X;
88F SIGMA = TMPD;
------------------------------------------|----------------------------------------------------------------------------------------------
890 FAULT: IRF2 = DES_SS.AR; DLY; if (!FLAGS_BACKED_UP) goto FLAGS_OK;
891 PTGEN COPY_STACK_DPL; PROTUN = IRF2; // (KN) PROTUN = DES_SS.AR
892 EFLAGS = FLAGSB; // Restore flags from backup
893 FLAGS_OK: TMPD = SIGMA; if (TSS_ACCESS_FLAG) goto RESUME_FLAG_OK;
894 EIP = TMPeIP; ICESIG;
895 SIGMA = 0xffff;
896 SIGMA += 1; // SIGMA = 0x10000
897 TMPB = SIGMA; // TMPB = 0x10000
898 SIGMA = EFLAGS | TMPB; // SIGMA = EFLAGS | 0x10000
899 EFLAGS = SIGMA; SIGMA = TMPD; // EFLAGS |= 0x10000 - set Resume Flag
89A RESUME_FLAG_OK: ESP = TMPeSP; if (JICEWT) goto RESUME_FLAG_OK;
89B OPR_R; TSS_ACCESS_FLAG = false; // Does OPR_R on its own just ack any pending read in the bus logic?
89C if (REPF) goto STRING_CORRECT; // Is REPF only set for REP MOVS and not for the other REP string instructions? Former if it's only set by SREPF
89D TMPD = SIGMA; BITSDE; // SIGMA saved in TMPD so that it is restored by STRING_CORRECT
89E INTERRUPT_X: INTERRUPT_HW = true;
89F INTERRUPT: ICESIG // TODO: What is ICESIG? Software interrupts arrive here, skipping the INTERRUPT_HW set
8A0 if (PM) goto INTERRUPT_PM;
8A1 BITS32;
8A2 if (VM) goto INTERRUPT_PM; // Doesn't VM imply PM (except in instruction decoding)?
8A3 SHLCNT = 2; TMPB = SIGMA;
8A4 SIGMA = (0:TMPB) << SHLCNT; // SIGMA = TMPB << 2? We must be in real mode here
8A5 DESIDT; DLY; IND = SIGMA;
8A6 FLAGSB = EFLAGS; FLAGS_BACKED_UP = true; RD_D; // Fetch of the offset? Or segment:offset since this is real mode?
8A7 IRF2 = DES_CS.LIMIT; CLI; DLY;
8A8 TMPC = IRF2;
8A9 SHRCNT = 0x10 & BITS_V; TMPB = OPR_R; UNL;
8AA SIGMA = (0:TMPB) >> SHRCNT; // SIGMA = TMPB >> 16?
8AB PROTUN = SIGMA;
8AC DES_CS.BASE = PROTUN << 4;
8AD DES_CS.LIMIT = TMPC; BITS16;
8AE PAGER5.PCR; goto PUSH_INT_FRAME;
8AF TMPG = TMPB;
------------------------------------------|----------------------------------------------------------------------------------------------
8B0 INTERRUPT_PM: SHLCNT = 3; TMPB = SIGMA; // IDT contains task/interrupt/trap gate descriptors. Offset in bytes 0-1 and 6-7, selector in bytes 2-3, P/DPL in byte 5
8B1 SIGMA = (0:TMPB) << SHLCNT; // SIGMA = TMPB << 3?
8B2 DESIDT; MISC1 = true; DLY; IND_DELTA = 4; IND = SIGMA + IND_DELTA;
8B3 SHRCNT = 0x10; SLCTR2 = SIGMA; rd_D; // Fetching bytes 4-7 of the gate
8B4 FLAGSB = EFLAGS; FLAGS_BACKED_UP = true; IND_DELTA = -4; IND += IND_DELTA; DLY; // Clear NT
8B5 PROTUN = OPR_R; SIGMA = OPR_R & 0xffff0000; UNL; rd_D; // Fetching bytes 0-3 of the gate
8B6 TMPB = SIGMA; DLY; if (!INTERRUPT_HW) goto INTERRUPT_SW; // TMPB = OPR_R & 0xffff0000 INTERRUPT_HW is only used here - determines whether we do TST_DES_INT_SW (which has an extra priv check) or TST_DES_INT_HW
8B7 TMPD = OPR_R; SIGMA = OPR_R & 0xffff; UNL;
8B8 SIGMA |= TMPB; // SIGMA = recombined offset from gate
8B9 TMPG = SIGMA; PTF TST_DES_INT_HW; // TST_DES_INT_HW can go to TASKGATE, #NP(I1,E0), TRAPGATE286, INTGATE286, TRAPGATE386, INTGATE386 or continue
8BA INTERRUPT_COMM: SIGMA = (0:TMPD) >> SHRCNT; // SIGMA = TMPD >> 16?
8BB TMPH = SIGMA;
8BC PTR = &DES_CS; DLY; PTSAV7 TST_DES_CGDEST; // TST_DES_CGDEST can go to PROT_TESTS_PASSED2 (N) (RETURNs), MORE_PRIVILEGE (KLN), #NP(I0,E0), continue.
8BD goto #GP(I1,E0); // we end up here if TST_INTERRUPT* continues
8BE PTGEN JMP_GFAULT_INT; // JMP_GFAULT_INT is unconditional jump to #GP(I1,E0) with FAULT flag set. But we're already going there, so I don't know why this isn't just a SET_FAULT. Also not sure if this causes 3 microops at #GP(I1,E0) to run twice
------------------------------------------|----------------------------------------------------------------------------------------------
8BF INTERRUPT_SW: SIGMA |= TMPB; // SIGMA = recombined offset from gate
8C0 goto INTERRUPT_COMM;
8C1 TMPG = SIGMA; PTF TST_DES_INT_SW; // TST_DES_INT_SW can go to TASKGATE, #NP(I1,E0), TRAPGATE286, INTGATE286, TRAPGATE386, INTGATE386 or continue
------------------------------------------|----------------------------------------------------------------------------------------------
8C2 INTGATE286: CLI; // Trap gates don't clear interrupt and trap flags, interrupt gates do.
8C3 TRAPGATE286: SIGMA = (-1)^0x4000; // SIGMA = 0xffffbfff 0x4000 corresponds to NT (Nested Task) flag
8C4 TMPB = SIGMA; MISC2 = true;
8C5 SIGMA = EFLAGS & TMPB;
8C6 EFLAGS = SIGMA; // Clear NT
8C7 LD_DESCRIPTOR(); // Load new CS descriptor
8C8 SLCTR = TMPH; PTSELE TST_SEL_CS; DLY; // TST_SEL_CS can go to #GP/#TS(I0,E0) or continue (L)
8C9 goto TRAP_INT_GATE;
8CA PROTUN = TMPH; BITS16; DLY; PTR->DEL = TMPC; // descriptor selected previously?
------------------------------------------|----------------------------------------------------------------------------------------------
8CB INTGATE386: CLI; // Trap gates don't clear interrupt and trap flags, interrupt gates do.
8CC TRAPGATE386: SIGMA = (-1)^0x4000; // SIGMA = 0xffffbfff 0x4000 corresponds to NT (Nested Task) flag
8CD TMPB = SIGMA; MISC2 = false;
8CE SIGMA = EFLAGS & TMPB;
8CF EFLAGS = SIGMA; // Clear NT
8D0 LD_DESCRIPTOR(); // Load new CS descriptor
8D1 SLCTR = TMPH; PTSELE TST_SEL_CS; DLY; // TST_SEL_CS can go to #GP/#TS(I0,E0) or continue (L)
8D2 PROTUN = TMPH; BITS32; DLY; PTR->DEL = TMPC; // descriptor selected previously? INTERRUPT-TO-SAME-PRIVILEGE-LEVEL case (RETURN from LD_DESCRIPTOR)
8D3 TRAP_INT_GATE: PAGER5.PCR; PTGEN SET_RPL_TO_CPL; // (KM)
8D4 if (VM) goto GENERAL_FAULTP; // GENERAL_FAULTP goes to a jump to #GP/#TS(I0,E0).
8D5 PUSH_INT_FRAME: SIGMA = EFLAGS & 0xffff;
8D6 EFLAGS = SIGMA; // clear Resume Flag and Virtual 8086 Mode Flag?
8D7 DESCOD; IND = TMPG;
8D8 SIGMA = FLAGSB & 0x37fd7; PREF;
8D9 DESSTK; DLY; IND_DELTA = NEGWSZ; IND = ESP + IND_DELTA;
8DA OPR_W = SIGMA; WR; // write flags to bus?
8DB DLY; IND += IND_DELTA; // IND_DELTA set to NEGWSZ at 8d9
8DC OPR_W = CS; WR_W; // write return segment/selector to bus?
8DD TMPB = TMPF; CLT; DLY; IND += IND_DELTA; // IND_DELTA set to NEGWSZ at 8d9
8DE OPR_W = EIP; WR; // write return offset to bus?
8DF eIP = TMPG; DLY; if (!ERROR_CODE_FLAG) goto TRAP_INT_DONE;
8E0 eSP = IRF2; BITS32; IND += IND_DELTA; // IND_DELTA set to NEGWSZ at 8d9 Does IRF2 here mean IND?
8E1 if (PM) goto PUSH_ERRORCODE;
8E2 SHRCNT = 0x10;
8E3 TRAP_INT_DONE: CS = PROTUN; RNI;
8E4
------------------------------------------|----------------------------------------------------------------------------------------------
8E5 PUSH_ERRORCODE: eSP = IRF2; IND_DELTA = 0; IND += IND_DELTA; // Why IND_DELTA = 0? Does IRF2 here mean IND?
8E6 SIGMA = (0:TMPB) >> SHRCNT; // SIGMA = TMPB >> 16? SHRCNT = 0x10 at 8e2
8E7 OPR_W = SIGMA; WR_W; goto TRAP_INT_DONE;
8E8 DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
8E9 #PF: ICESIG;
8EA PAGE_FAULTLOOP: if (JICEWT) goto PAGE_FAULTLOOP;
8EB SIGMA = TMPF & 0xffff; // TODO: Where does TMPF come from?
8EC BITS32; // TODO: What is BITS32?
8ED TMPC = SIGMA; {-7E-}; DLY; // TODO: What is {-7E-}? TMPC = TMPF & 0xffff
8EE IRF2 = PFERRC.PCR; CONTRIBUTORY_FAULT = true; OPR_R;
8EF TMPB = IRF2; SHLCNT = 0x10; DLY; // Read TMPB from special register {-7A-}?
8F0 IRF2 = LATTTF.PCR; SIGMA = (0:TMPB) << SHLCNT; // LATTTF = Linear Address That Triggered The Fault. SIGMA = TMPB << 16;
8F1 CR2 = IRF2; ERROR_CODE_FLAG = true; // "CR2 is used for handling page faults when PG is set. The processor stores in CR2 the linear address that triggers the fault."
8F2 SIGMA |= TMPC; // SIGMA = (IND << 16) | (TMPF & 0xffff)
8F3 TMPF = SIGMA; SIGMA = 0x0d; // TMPF = (IND << 16) | (TMPF & 0xffff) Is this the error code (bit 0 = P, bit 1 = W/R, bit 2 = U/S)? (initial TMPF) with upper 16 bits coming from PFERRC
8F4 goto FAULT;
8F5 SIGMA += 1; // SIGMA = 0xe means "Interrupt 0x0e Page Fault"
------------------------------------------|----------------------------------------------------------------------------------------------
8F6 if (PM && CPL > 0) goto NO_PRIVILEGE; // 0 LOADALL386
8F7 ICESIG;
8F8 SIGMA = 0x800000fc;
8F9 SIGMA &= 0x7ff; // SIGMA = 0xfc
8FA DES_ES; IND_DELTA = EDI; IND = SIGMA + IND_DELTA; BITS32; DLY; // ES:EDI is the location to read from (uses actual ES, not the ES descriptor)
8FB DLY; IND_DELTA = 4; IND += IND_DELTA; // First read is is at EDI + 0x100
8FC SIGMA = 0x0f; RD_D;
8FD SIGMA += 4; // SIGMA = 0x13
8FE COUNTR = SIGMA; SIGMA = 0x0d; DLY; // COUNTR = 0x13 Why DLY?
8FF PROTUN = OPR_R; UNL; // PROTUN is first mystery read.
900 SIGMA -= 2; // SIGMA = 0x0b
901 EAX = SIGMA; DLY; IND += IND_DELTA; // IND_DELTA set to 4 at 8fb
902 LOADALL_LOOP1: SIGMA = COUNTR - EAX; RD_D;
903 DLY; IND += IND_DELTA; // IND_DELTA set to 4 at 8fb
904 IRF[COUNTR] = OPR_R; UNL; if (JG) goto LOADALL_LOOP1;
905 --COUNTR; // Loop to load registers 0x13 down to 0x0b? - 9 of the 10 mystery reads described at https://www.rcollins.org/articles/loadall/tspec_a3_doc.html ? SLCTR2 TMPG TMPH FLAGSB TMPF TMPE TMPD TMPC TMPB
906 DES_ES; DLY; IND_DELTA = -4; IND = EDI + IND_DELTA; // Next reads back down to EDI (below the mystery reads).
907 DLY; IND_DELTA = 4; IND += IND_DELTA;
908 RD_D;
909 COUNTR = 9; DLY; IND += IND_DELTA; // IND_DELTA set to 4 at 907
90A MDTMP4 = OPR_R; UNL; RD_D; // 11th read (should be CR0) is to MDTMP4?
90B LOADALL_LOOP2: DLY; IND += IND_DELTA; // IND_DELTA set to 4 at 907
90C IRF[COUNTR] = OPR_R; if (COUNTR != 1) goto LOADALL_LOOP2; UNL; RD_D; // Read EFLAGS? EIP EDI ESI EBP ESP EBX EDX ECX EAX (12th - 21st reads)
90D --COUNTR;
90E DLY; IND += IND_DELTA; // IND_DELTA set to 4 at 907
90F EAX = OPR_R; SIGMA = 0x29; UNL; RD_D;
910 SIGMA -= 3; // SIGMA = 0x26
911 COUNTR = SIGMA; DLY; IND += IND_DELTA; // COUNTR = 0x26; IND_DELTA set to 4 at 907
912 DR6 = OPR_R; UNL; RD_D; // 22nd read is to DR6
913 SIGMA = 0x5d; DLY; IND += IND_DELTA; // IND_DELTA set to 4 at 907
914 DR7 = OPR_R; UNL; RD_W; // 23rd read is to DR7
915 TMPB = SIGMA; DLY; IND += IND_DELTA; // TMPB = 0x26 IND_DELTA set to 4 at 907
916 TR = OPR_R; UNL; RD_W; // 24th read is to TR
917 LOADALL_LOOP3: SIGMA = TMPB + 0x0d; DLY; IND += IND_DELTA; // SIGMA = 0x33 IND_DELTA set to 4 at 907
918 IRF[COUNTR] = OPR_R; if ((COUNTR & 15) != 1) goto LOADALL_LOOP3; UNL; RD_W; // Loop to load the segment/selector registers? LDT GS FS DS SS CS ES
919 --COUNTR;
91A COUNTR = SIGMA; DLY; IND += IND_DELTA; // COUNTR = 0x33 IND_DELTA set to 4 at 907
91B ES = OPR_R; UNL;
91C LOADALL_LOOP4: PROTUN = COUNTR; SIGMA = COUNTR - 1; RD_D;
91D COUNTR = SIGMA; DLY; IND += IND_DELTA; // IND_DELTA set to 4 at 907
91E TMPB = OPR_R; UNL; RD_D;
91F DLY;
920 SIGMA = IRF2 + 4; IND += IND_DELTA; // IND_DELTA set to 4 at 907
921 TMPC = OPR_R; UNL; RD_D;
922 IRF[COUNTR].AR = TMPB; DLY; // Select AR field of descriptor cache
923 IRF[COUNTR].BAS = TMPC; DLY; // Select BASE field of descriptor cache
924 IRF[COUNTR].LIM = OPR_R; UNL; // Select LIMIT field of descriptor cache
925 DES_ES; IND_DELTA = 4; IND = SIGMA + IND_DELTA;
926 COUNTR = PROTUN;
927 // Why do we have a blank line here?
928 if ((COUNTR & 15) != 1) goto LOADALL_LOOP4; // Loop to load descriptor cache entries
929 --COUNTR;
92A IRF2 = DES_SS.AR; SIGMA = CR0 & 0xffff0000; DLY; // Paging bit is top bit of CR0
92B PTGEN COPY_STACK_DPL; PROTUN = IRF2; // (KN)
92C SIGMA &= 0x800000fc; // Isolate paging bit?
92D COUNTR = SIGMA;
92E CR0 = MDTMP; // What is MDTMP? Value from MDTMP4 on line 90a?
92F if (COUNTR != 0) goto LOADALL_PAGING; TMPeIP = EIP;
930 IRF2 = DES_CS.LIMIT; ICEEXT; // ICEEXT only used here - presumably it exits ICE mode (sending a signal to the ICE that LOADALL has completed successfully?)
931 SIGMA = IRF2;
932 LOADALL_FINAL: DES_CS; CLRNMI; DLY; IND = SIGMA;
933 PAGER5.PCR; SIGMA = DR6;
934 DESCOD; ICEBRK; IND = EIP;
935 DR6 = SIGMA; PREF;
936 TMPeSP = ESP; DLY;
937 RNI;
938
------------------------------------------|----------------------------------------------------------------------------------------------
939 LOADALL_PAGING: SIGMA = IRF2; IRF2 = PDBR.PCR; // IRF2 = CR3
93A DESABS; IND = IRF2; goto LOADALL_FINAL; // IND = CR3
93B PDBR.PCR = IND; // CR3 = CR3 - don't change CR3, just flush the TLB
------------------------------------------|----------------------------------------------------------------------------------------------
93C BITS32; // 0 ICEBP
93D goto BREAKPOINT_CMN;
93E ICEBRK;
------------------------------------------|----------------------------------------------------------------------------------------------
93F SINGLE_STEP: SIGMA = DR6 | 0x4000; // Presumably we enter here (via the small PLA) if we're doing a single step (trap flag) breakpoint. "The BS bit is associated with the TF (trap flag) bit of the EFLAGS register. The BS bit is set if the debug handler is entered due to the occurrence of a single-step exception. The single-step trap is the highest-priority debug exception; therefore, when BS is set, any of the other debug status bits may also be set."
940 DR6 = SIGMA;
941 BREAKPOINT: TMPeIP = EIP; ICEBRK; // Presumably we enter here (via the small PLA) if one of the debug register breakpoints is hit
942 TMPeSP = ESP; BITS32;
943 BREAKPOINT_CMN: SHRCNT = 2; // ICEBRK always happens before we get to BREAKPOINT_CMN (whether from BREAKPOINT, ICEBP or GDHIT). BREAKPOINT_CMN can either do INT 1 or ICE_SINGLESTEP (which does STOREALL)
944 SIGMA = (0:0x4000) >> SHRCNT; // SIGMA = 0x4000 >> 2 = 0x1000
945 TMPB = SIGMA; ICESIG; // TMPB = 0x1000
946 SIGMA = DR7 & TMPB; // Undocumented bit of DR7 "0 MEANS INTEL RESERVED. DO NOT DEFINE." in manual https://en.wikipedia.org/wiki/X86_debug_register says "Action on breakpoint match: 0 = INT 1 (#DB exception, default) 1 = Break to ICE/SMM"
947 COUNTR = SIGMA; SHLCNT = 13;
948 SIGMA = (0:1) << SHLCNT; // SIGMA = 1 << 13 = 0x2000
949 TMPB = TMPeIP; if (COUNTR != 0) goto ICE_SINGLESTEP;
94A SIGMA ^= -1; // SIGMA = 0xdfff
94B TMPB = SIGMA; // TMPB = 0xdfff
94C SIGMA = DR7 & TMPB; // SIGMA = DR7 & 0xdfff - clear "General Detect Enable" (If set, will cause a debug exception on any attempt at accessing the DR0-DR7 registers.) https://en.wikipedia.org/wiki/X86_debug_register
94D goto INTERRUPT_X;
94E DR7 = SIGMA; SIGMA = 1; // DR7 &= 0xdfff "Interrupt 1 Debug Exceptions"
------------------------------------------|----------------------------------------------------------------------------------------------
94F ICE_SINGLESTEP: if (JICEWT) goto ICE_SINGLESTEP;
950
951 goto STOREALL;
952 ICEENT;
------------------------------------------|----------------------------------------------------------------------------------------------
953 ICE_PIN: ICEBRK; // this acts like BREAKPOINT_CMN but always does the ICE break instead of INT 1
954 TMPB = DR7; BITS32;
955 SHRCNT = 2;
956 SIGMA = (0:0x4000) >> SHRCNT; // SIGMA = 0x4000 >> 2 = 0x1000
957 TMPC = SIGMA; SIGMA = TMPC | TMPB; // TMPC = 0x1000 SIGMA = 0x1000 | DR7; Set "Action on breakpoint match:" to "1 = Break to ICE/SMM" (This will cause a system hang if an ICE is not connected.)
958 DR7 = SIGMA; DLY; // Why DLY?
959 TMPB = TMPeIP; ICESIG;
95A ICE_PIN_LOOP: if (JICEWT) goto ICE_PIN_LOOP;
95B SIGMA = DR6 | TMPC; // Waiting for something? Set BK/SMMS "SMM or ICE mode entered" bit in DR6
95C goto STOREALL;
95D DR6 = SIGMA; ICEENT;
------------------------------------------|----------------------------------------------------------------------------------------------
95E STOREALL16: TMPeIP = IRF2; COUNTR = 0x8200;
95F MDTMP4 = COUNTR; goto STOREALL_COMM; // MDTMP4 = 0x8200;
960 IRF2 = DES_TR.LIMIT;
------------------------------------------|----------------------------------------------------------------------------------------------
961 STOREALL: SHLCNT = 0x10; IRF2 = DES_TR.AR; DLY; // do we actually do anything with IRF2?
962 MDTMP4 = -1; if (BITS == 16) goto STOREALL16;
963 IRF2 = DES_TR.BASE; SIGMA = (0:6) << SHLCNT; // SIGMA = 6 << 16 = 0x60000
964 TMPeIP = IRF2;
965 IRF2 = DES_TR.LIMIT;
966 STOREALL_COMM: TMPeSP = IRF2;
967 COUNTR = SIGMA; SIGMA = 0x8200; // COUNTR = 0x60000
968 DES_TR.AR = SIGMA; SIGMA = 0x800000fc;
969 SIGMA &= 0x7ff; // SIGMA = 0xfc
96A DES_TR.BASE = COUNTR // DES_TR.BASE = 0x60000 = 384kB mark? Why there?
96B DES_TR.LIMIT = 0xffffffff; DLY;
96C DES_TR; IND_DELTA = 4; IND = SIGMA + IND_DELTA;
96D OPR_W = PROTUN; SIGMA = 0x0f; WR_D; // WR_D is special write operation for ICE memory space (see https://web.archive.org/web/19970613081422/http://www.x86.org/ddj/Jan97/Jan97.html ).
96E SIGMA += 4; // SIGMA = 0x13
96F COUNTR = SIGMA; // COUNTR = 0x13
970 STOREALL_LOOP1: SIGMA = COUNTR - 0x0d; DLY; IND += IND_DELTA; // IND_DELTA set to 4 at 96c
971 OPR_W = IRF[COUNTR]; WR_D;
972 IRF[COUNTR] = 0; if (JG) goto STOREALL_LOOP1; // if (COUNTR > 0x0d) goto STOREALL_LOOP1; Loop to write SLCTR2, TMPG, TMPH, FLAGSB, TMPF, TMPE, TMPD
973 --COUNTR;
974 DLY; IND += IND_DELTA; // IND_DELTA set to 4 at 96c COUNTR = 0x0c now?
975 OPR_W = TMPC; WR_D; // Write TMPC
976 DLY; IND += IND_DELTA; // IND_DELTA set to 4 at 96c
977 OPR_W = TMPB; SIGMA = -4; WR_D; // Write TMPB
978 DLY;
979 IRF2 = PDBR.PCR; // IRF2 = CR3
97A DESABS; IND = IRF2; // IND = CR3
97B PDBR.PCR = IND; // CR3 = CR3 - don't change CR3 but flush TLB
97C DES_TR; IND_DELTA = 4; IND = SIGMA + IND_DELTA; DLY; SIGMA = 4;
97D SIGMA += 6; // SIGMA = 10
97E COUNTR = SIGMA; goto STOREALL_LOOPS;
97F PROTUN = 0; PTGEN COPY_STACK_DPL; // (KN)
------------------------------------------|----------------------------------------------------------------------------------------------
980 STOREALL_LOOP2: TMPB = 0; DLY; IND += IND_DELTA; // IND_DELTA set to 4 at 97c
981 STOREALL_LOOPS: OPR_W = IRF[COUNTR]; WR_D; if (COUNTR != 0) goto STOREALL_LOOP2; // Write 10-0 CR0 EFLAGS EIP EDI ESI EBP ESP EBX EDX ECX EAX
982 IRF[COUNTR] = 0; --COUNTR;
983 COUNTR = 0x29; DLY; IND += IND_DELTA; // IND_DELTA set to 4 at 97c
984 OPR_W = DR6; WR_D; // Write DR6?
985 SIGMA = COUNTR - 3; DLY; IND += IND_DELTA; // SIGMA = 0x26 IND_DELTA set to 4 at 97c
986 OPR_W = DR7; WR_D; // Write DR7?
987 COUNTR = SIGMA; DLY; IND += IND_DELTA; // COUNTR = 0x26 IND_DELTA set to 4 at 97c
988 OPR_W = TR; WR_W; // Write TR selector
989 STOREALL_LOOP3: TR = 0; DLY; IND += IND_DELTA; // IND_DELTA set to 4 at 97c
98A OPR_W = IRF[COUNTR]; WR_W; if ((COUNTR & 15) != 1) goto STOREALL_LOOP3; // Write other selectors (LDT GS FS DS SS CS)
98B IRF[COUNTR] = 0; --COUNTR;
98C DLY;
98D SIGMA = IRF2 + 4; IND += IND_DELTA; // IND_DELTA set to 4 at 97c
98E OPR_W = ES; WR_W; // Write ES
98F TMPE = SIGMA; SIGMA = 0x70;
990 SIGMA -= 7; // SIGMA = 0x69;
991 COUNTR = SIGMA; goto STOREALL_L4_ST; // COUNTR = 0x69;
992 ES = 0; SIGMA = 0 - (-1); DLY;
------------------------------------------|----------------------------------------------------------------------------------------------
993 STOREALL_LOOP4: IRF2 = IRF[COUNTR].BASE; SIGMA = COUNTR & 0x1f;
994 TMPeIP = IRF2; // Load value 2 from descriptor cache = base?
995 IRF2 = IRF[COUNTER].LIMIT; SIGMA -= 0; // TODO: Why are we subtracting 0?
996 TMPeSP = IRF2; // Load value 3 from descriptor cache = limit?
997 IRF[COUNTER].BASE = 0; SIGMA = 0xffff;
998 IRF[COUNTER].LIMIT = SIGMA; SIGMA = 0x8200; // IRF[COUNTER].LIMIT = 0xffff
999 IRF[COUNTER].AR = SIGMA; // IRF[COUNTER].AR = 0x8200
99A STOREALL_L4_ST: DES_TR; IND_DELTA = 4; IND = TMPE + IND_DELTA;
99B OPR_W = MDTMP; WR_D; // OPR_W = access rights ?
99C DR7 = 0; DLY; IND += IND_DELTA; // IND_DELTA set to 4 at 99a
99D OPR_W = TMPeIP; --COUNTR; WR_D; // Write value 2 = base?
99E DLY;
99F SIGMA = IRF2 + 4; IND += IND_DELTA; // IND_DELTA set to 4 at 99a
9A0 TMPE = SIGMA;
9A1 OPR_W = TMPeSP; WR_D; // Write value 3 = limit?
9A2 IRF2 = IRF[COUNTER].AR; DLY; if (JG) goto STOREALL_LOOP4; // if (IRF2 > -4) goto STOREALL_LOOP4; (Flags set from ALU op done at 99f?)
9A3 MDTMP4 = IRF2; // Is MDTMP4 same as MDTMP?
9A4 goto BOOTUP_JUMP;
9A5 DES_TR.BASE = 0; CLT;
------------------------------------------|----------------------------------------------------------------------------------------------
9A6 BOOTUP: SIGMA = 0x29 | 0x40; // SIGMA = 0x69
9A7 BOOTUP_LOOP1: TMPC = SIGMA; if (COUNTR != 0) goto BOOTUP_LOOP1; // TMPC = 0x69
9A8 IRF[COUNTR] = 0; --COUNTR; // zero registers from 0x29 to 0 (TR, IDTR, GDTR, LDTR, GS, FS, DS, SS, CS, ES, ?, ?, MDTMP, OPROFF, FSVeIP, CSOPCD), DR7, DR6, TMPeSP, TMPeIP, PROTUN, MDTMP4, SLCTR2, TMPG, TMPH, FLAGSB, TMPF, TMPE, TMPD, TMPC, TMPB, CR0, EFLAGS, EIP, EDI-EAX)
9A9 COUNTR = 0x73; DESABS.BASE = 0; DLY; // SBAS selects base field of descriptor cache. However, I'm not sure that SBAS actually does anything here. Referencing DESABS should just put a phantom address (IND) on the address bus
9AA PDBR.PCR = IND; // Clear page cache? IND here is set to LDTR (nonsense value reused from jump uop). Maybe the value doesn't matter, we're just initializing/flushing the TLB but it needed to be something with a deterministic value.
9AB BOOTUP_LOOP2: DR7 = 0; if ((COUNTR & 15) != 1) goto BOOTUP_LOOP2;
9AC IRF[COUNTR].BAS = 0; --COUNTR; // zeroing all base fields in the descriptor cache?
9AD SIGMA = 0xffff; CR2 = 0;
9AE COUNTR = TMPC; TMPB = SIGMA; // TMPC here is 0x69 assuming it hasn't been zeroed. TMPB = 0xffff
9AF BOOTUP_LOOP3: SIGMA = 0x8200; DR6 = 0;
9B0 IRF[COUNTR].AR = SIGMA; if ((COUNTR & 15) != 1) goto BOOTUP_LOOP3; // IRF[COUNTR].AR = 0x8200. SAR = Select AR field of descriptor cache. 8200 = (G=0 DB=0 AVL=0 P=1 DPL=0 S=0 TYPE=2) = LDT?
9B1 IRF[COUNTR].LIMIT = TMPB; --COUNTR; // IRF[COUNTR].LIMIT = 0xffff. Initialises the descriptor cache with limit 0xffff and attributes 0x8200 SLIM selects LIMIT field of descriptor cache
9B2 DES_ES.AR = SIGMA; CONTRIBUTORY_FAULT = true; // DES_ES.AR = 0x8200
9B3 DES_ES.LIMIT = TMPB; BITS32; // DES_ES.LIMIT = 0xffff
9B4 DR6 = 0;
9B5 SIGMA = 0x0303; TMPD = BIST1; // 0x0303 is initial EDX value (CPU type/stepping).
9B6 EDX = SIGMA; // set initial EDX value
9B7 TMPE = BIST2; SIGMA = TMPE ^ TMPD; // Compute the total BIST checksum
9B8 SIGMA ^= 0x3ddc0c2c; // XOR against expected value - result should be 0 if self-test passed
9B9 EAX = SIGMA; if (!BUSY# && !ERROR#) goto BOOTUP_JUMP;
9BA SIGMA = 0x10; CR0 = 0; // The 80387 holds its ERROR# output low after reset, whereas the 80287 holds its ERROR# output high. Not sure why we're checking BUSY# rather than ERROR# here.
9BB CR0 = SIGMA; // CR0 = 0x10 - set bit to indicate 80387 is present. CR0 bit 4 zero means "the configuration either contains an 80287 or does not contain a coprocessor"
9BC BOOTUP_JUMP: SHRCNT = 4; PROTUN = 0; // Initialize barrel shifter to shift right by 4? Presumably this routine sets up initial CS descriptor and IP
9BD SIGMA = (0:0xf0000) >> SHRCNT; // SIGMA = 0xf000 This is the initial CS value
9BE TMPB = SIGMA; SIGMA = 0xffff0000;
9BF DESCOD.BAS = SIGMA; SIGMA = 0xffff; // DESCOD = 0xffff0000 - this is the initial CS base (in order that the linear address of the first instruction is fffffff0)
9C0 DESCOD.LIM = SIGMA;
9C1 PAGER5.PCR; SIGMA -= 0x0f; // SIGMA = 0xfff0
9C2 goto JMP_FAR_COMMON;
9C3 TMPG = SIGMA; SIGMA = TMPB; // TMPG = 0xfff0 - this is the initial EIP value
9C4 =====================================|
9C5 =====================================|
9C6 =====================================|
9C7 =====================================|
9C8 =====================================|
9C9 =====================================|
9CA =====================================|
9CB =====================================|
9CC =====================================|
9CD =====================================|
9CE =====================================|
9CF =====================================|
9D0 =====================================|
9D1 =====================================|
9D2 =====================================|
9D3 =====================================|
9D4 =====================================|
9D5 =====================================|
9D6 =====================================|
9D7 =====================================|
9D8 =====================================|
9D9 =====================================|
9DA =====================================|
9DB =====================================|
9DC =====================================|
9DD =====================================|
9DE =====================================|
9DF =====================================|
9E0 =====================================|
9E1 =====================================|
9E2 =====================================|
9E3 =====================================|
9E4 =====================================|
9E5 =====================================|
9E6 =====================================|
9E7 =====================================|
9E8 =====================================|
9E9 =====================================|
9EA =====================================|
9EB =====================================|
9EC =====================================|
9ED =====================================|
9EE =====================================|
9EF =====================================|
9F0 =====================================|
9F1 =====================================|
9F2 =====================================|
9F3 =====================================|
9F4 =====================================|
9F5 =====================================|
9F6 =====================================|
9F7 =====================================|
9F8 =====================================|
9F9 =====================================|
9FA =====================================|
9FB =====================================|
9FC =====================================|
9FD =====================================|
9FE =====================================|
9FF =====================================|