*----------------------------------------------------------- Title[S-Group.mc...January 27, 1984 1:13 PM...Taft]; *----------------------------------------------------------- KnowRBase[AEmRegs]; TopLevel; *----------------------------------------------------------- NPTrap: * NOPAR trap -- ID=2, which is trap offset * N = trap location offset, relative to base defined by trap starting location *----------------------------------------------------------- Trap00: T← ID+(130C), Branch[Trapx]; * 530+N Trap17: T← ID+(147C), Branch[Trapx]; * 547+N Trap36: T← ID+(166C), Branch[Trapx]; * 566+N Trapx: T← (R400)+T, MemBase← MDS; Fetch← T, Call[GetPC]; * Fetch new PC; get current ETemp← T+1; T← (R400)+(127C); * VM 527 ← old PC +1 Store← T, DBuf← ETemp, T← MD, Branch[Start]; * Start at new PC *----------------------------------------------------------- * CYCLE (60000) *----------------------------------------------------------- CYCLE: T← ID AND (17C); * Cycle count from operand byte StkP← spAC1, Branch[.+2, ALU#0]; T← (Stack) AND (17C); * Cycle count from AC1 T← LSH[T, 10], StkP-1; * Load cycle count into ShC T← MD, ShC← T; Stack← ShiftNoMask[Stack], IFUJump[0]; * Cycle AC0 *----------------------------------------------------------- * JSRII (64400) * MemBase = MDS, Sign = 1. *----------------------------------------------------------- JSRII: T← 2(ID), Q← PCX', Call[EffAdrPCRel1]; JSRIIx: Fetch← T; T← MD, Branch[JSRixf]; *----------------------------------------------------------- * JSRIS (65000) * MemBase = MDS, Sign = 1. *----------------------------------------------------------- JSRIS: StkP← spAC2; T← ID+(Stack), Branch[JSRIIx]; *----------------------------------------------------------- * CONVERT (67000) * MemBase = MDS, Sign = 1. *----------------------------------------------------------- RME[PtrXW, ETemp1]; RME[NWords, ETemp2]; RME[DWA, ETemp3]; RME[ShCTemp, ETemp4]; CONVERT: StkP← spAC3; PtrXW← Fetch← Stack&-1; * Fetch FontBase+Char T← ID+(Stack&-2); * T← AC2 + SE(disp) PtrXW← (PtrXW)+MD+1; * PtrXW← address of word XW +1 T← (Fetch← T)+1; * NWords← @(AC2 + SE(disp)) NWords← MD, Fetch← T; * DBA← @(AC2 + SE(disp) +1) DWA← Stack&+1; * DWA← AC0 Stack&+2← T← (17S) AND MD; * AC1← DBA MOD 20B ShCTemp← (17S)-T; * LMask← 17B - DBA T← T+1, Branch[CvOneW, ALU=0]; * Branch if DBA = 17 (one dest word) ETemp← LSH[T, 14]; * RMask← Count← DBA+1 T← LCY[ETemp, T, 10]; ShCTemp← (ShCTemp) OR T; CvOneW: Fetch← PtrXW, T← A0; * Fetch @(PtrXW+1) = HD,,XH ETemp← DPF[T, 10, 10, MD], T← MD; * ETemp← XH; T← RSH[T, 10]; * T← HD T← NWords← (NWords)-1, Cnt← T; * Really NWords-1 hereafter * Skip over HD scan lines in the destination bit map. * Note that we really execute the following loop HD+1 times, but the extra * time compensates for the fact that DWA-NWords was originally passed in AC0. DWA← (DWA)+T+1, Branch[., Cnt#0&-1]; T← 5C; * Set ALUFM[17] to "NOT A OR B" Stack← ALUFMRW← T, ALUF[17]; * Save previous value in AC3 T← Cnt← ETemp; * Cnt← XH PtrXW← (PtrXW)-T-1, Branch[CvEnd, Cnt=0&-1]; * PtrXW← -> char bit map * Main loop of CONVERT CvLp: PtrXW← (Fetch← PtrXW)+1; * Fetch next word of character ETemp← MD, Fetch← DWA; * Fetch word of destination bit map PD← ShC← ShCTemp; * Load ShC and prepare 1-word test T← XShMDLMask[ETemp], B← MD, FreezeBC; * Shift and OR character bits DWA← T← (Store← DWA)+1, DBuf← T, * Store destination word Branch[CvLpx, ALU=0]; * Branch if only one dest word Fetch← DWA; * Fetch second word of destination T← XShMDRMask[ETemp], B← MD; * Shift and OR character bits T← Store← DWA, DBuf← T; * Store destination word CvLpx: DWA← T+(NWords), Branch[CvLp, Cnt#0&-1]; * Advance dest ptr and repeat * End of CONVERT * PtrXW now again points to word XW, and StkP addresses AC3. * Return AC3← word XW right-shifted 1, and skip if it was odd (no extension). CvEnd: Fetch← PtrXW; Stack← MD, ALUFMRW← Stack, ALUF[17]; * Restore ALUFM[17] Stack← (Stack) RSH 1, DblBranch[DoSkip, NoSkip, R odd]; *----------------------------------------------------------- * Parameterless opcodes (61000) * Dispatch on operand byte if in [0..45], trap otherwise. * Leave StkP pointing at AC0 before dispatch. *----------------------------------------------------------- NOPAR: T← ID-(46C), ETemp← MD; * Wait for previous ref to complete T← T+(46C), Branch[NPTrap, ALU>=0]; BigBDispatch← T; StkP← spAC0, Branch[DIR]; *----------------------------------------------------------- * DIR (61000) *----------------------------------------------------------- DIR: NWW← (NWW) OR (100000C), IFUJump[0], At[SD400, 0]; *----------------------------------------------------------- * DIRS (61013) *----------------------------------------------------------- DIRS: PD← NOT (NWW), At[SD400, 13]; NWW← (NWW) OR (100000C), DblBranch[DoSkip, NoSkip, ALU<0]; *----------------------------------------------------------- * EIR (61001) *----------------------------------------------------------- EIR: T← (R400)+(52C), At[SD400, 1]; * WW (=452B) Fetch← T; NWW← (NWW) OR MD, RescheduleNow; * Will be noticed after 2 cycles NWW← (NWW) AND (77777C), Branch[NoSkip]; *----------------------------------------------------------- * BRI (61002) *----------------------------------------------------------- BRI: T← (R400)+(52C), At[SD400, 2]; * WW (=452B) T← (Fetch← T)+(26C); * PCLOC (=500B) T← MD, Fetch← T; NWW← (NWW) OR T, RescheduleNow; NWW← (NWW) AND (77777C), T← MD, Branch[Start]; *----------------------------------------------------------- * RCLK (61003) *----------------------------------------------------------- RCLK: RBase← RBase[RTClock], At[SD400, 3]; T← RTC430, TaskingOff; * Read the 2 words atomically!! Stack&+1← T; * AC0← high word T← RTClock, TaskingOn, Branch[StackGetsT]; * AC1← low word KnowRBase[AEmRegs]; *----------------------------------------------------------- * SIO (61004) *----------------------------------------------------------- SIO: Branch[DiskSIO], At[SD400, 4]; * Takes arg in Stack = AC0 *----------------------------------------------------------- * MUL (61020) * [high: AC0, low: AC1] ← AC0 + AC1*AC2 *----------------------------------------------------------- MULx: StkP+1, At[SD400, 20]; Q← Stack&+1; * Q← AC1 T← Stack&-2, Call[MulSub]; * T← AC2, [T,,Q] ← Q*T Stack+1← (Stack&+1)+Q; * AC1← AC0 + low result T← A← T, XorSavedCarry, StkP-1, * AC0← high result + carry Branch[StackGetsT]; *----------------------------------------------------------- * DIV (61021) * [quotient: AC1, remainder: AC0] ← [high: AC0, low: AC1] / AC2 * Skips unless overflow would occur. *----------------------------------------------------------- DIVx: T← Stack&+1, At[SD400, 21]; * T← AC0 Q← Stack&+1; * Q← AC1 Temp17← Stack&-1, SCall[DivSub]; * Temp17← AC2 * DivSub computes [quotient: Q, remainder: T] ← [T,,Q]/Temp17. * DivSub returns to caller+2 if an overflow occurred. Stack&-1← Q, Branch[.+2]; * AC1← quotient IFUJump[0]; Stack← T, Branch[DoSkip]; * AC0← remainder *----------------------------------------------------------- * BLT (61005) * Accepts AC0: first source -1, AC1: last destination, AC3: -count. * If interrupted, returns with ACs prepared for remainder of transfer. * Normally, returns AC0: last source +1, AC1: unchanged, AC3: 0. *----------------------------------------------------------- BLT: Stack&+3← (Stack&+3)+1, At[SD400, 5]; * AC0+1 = first source adr ETemp3← T← Stack&-2; * AC3 = -count ETemp← (Stack&-1)+T+1; * AC1-count+1 = first dest adr * StkP points to AC0 during the body of this code. Stack← (Fetch← Stack)+1; * Fetch first source word T← (0S)-T; * T← count T← T AND (17C); * T← count MOD 20B ETemp3← (ETemp3)+(Cnt← T); * Adjust remainder, load Cnt * PreFetch words 2 munches ahead of where we are now BLTmor: T← (Stack)+(40C), Branch[BLTnpf, ALU=0]; * Don't if last munch PreFetch← T; T← (ETemp)+(40C); PreFetch← T, DblBranch[BLTlp, BLTlpx, Cnt#0&-1]; * Test for going around loop zero times (count MOD 17B = 0) BLTnpf: DblBranch[BLTlp, BLTlpx, Cnt#0&-1]; * Main loop. One word has been fetched ahead. * This code depends on MD not being clobbered by Store← or PreFetch←. BLTlp: Stack← (Fetch← Stack)+1, T← MD; ETemp← (Store← ETemp)+1, DBuf← T, Branch[BLTlp, Cnt#0&-1]; * Fell out of main loop. Check for more munches to do. BLTlpx: T← ETemp3, Cnt← 20S, Branch[BLTint, Reschedule]; ETemp3← (ETemp3)+(20C), Branch[BLTmor, ALU#0]; * All done, update state in ACs. Stack&+3← (Stack&+3)-1, Branch[BLKxit]; * AC0← last source +1, AC3← 0 * Interrupt pending, save state and process interrupt. BLTint: Stack&+3← (Stack&+3)-(2C), Branch[BLKint]; * AC0← last source *----------------------------------------------------------- * BLKS (61006) * Accepts AC0: value, AC1: last destination, AC3: -count. * If interrupted, returns with ACs prepared for remainder of transfer. * Normally, returns AC0: unchanged, AC1: unchanged, AC3: 0. *----------------------------------------------------------- BLKS: T← Stack&+3, At[SD400, 6]; * AC0 = value T← Stack&-2, Q← T; * AC3 = -count ETemp← (Stack&+2)+T+1; * AC1-count+1 = first dest adr * StkP points to AC3 during the remainder of this instruction T← (0S)-T; * T← count T← T AND (17C); * T← count MOD 20B Stack← (Stack)+(Cnt← T); * Adjust remainder, load Cnt * PreFetch words 2 munches ahead of where we are now BLKmor: T← (ETemp)+(40C), Branch[BLKnpf, ALU=0]; * Don't if last munch PreFetch← T, DblBranch[BLKlp, BLKlpx, Cnt#0&-1]; * Test for going around loop zero times (count MOD 17B = 0) BLKnpf: DblBranch[BLKlp, BLKlpx, Cnt#0&-1]; * Main loop. BLKlp: ETemp← (Store← ETemp)+1, DBuf← Q, Branch[BLKlp, Cnt#0&-1]; * Fell out of main loop. Check for more munches to do. BLKlpx: T← Stack, Cnt← 20S, Branch[BLKint, Reschedule]; Stack← (Stack)+(20C), Branch[BLKmor, ALU#0]; * All done BLKxit: Stack← A0, IFUJump[0]; * AC3 = 0 * Interrupt pending, save state and process interrupt. BLKint: Stack← T, Branch[AEmuReschedule]; * AC3← -count remaining *----------------------------------------------------------- * BITBLT (61024) *----------------------------------------------------------- BitBltA: At[SD400, 24], StkP+2; T← Stack&-2; * AC0← AC2 Stack&+1← T, SCall[BitBltSub]; * TOS-1=BBTable, TOS=scan line count Branch[AEmuReschedule]; * +1 return: interrupt pending IFUJump[0]; * +2 return: done *----------------------------------------------------------- * XMLDA (61025) AC0 ← @AC1 in alternate bank *----------------------------------------------------------- XMLDA: MemBase← ScratchBR, At[SD400, 25]; T← A0, BRHi← EmuXMBRHiReg; StkP+1, BRLo← T; Fetch← Stack&-1, Branch[StackGetsMD]; *----------------------------------------------------------- * XMSTA (61026) @AC1 ← AC0 in alternate bank *----------------------------------------------------------- XMSTA: MemBase← ScratchBR, At[SD400, 26]; T← A0, BRHi← EmuXMBRHiReg; T← Stack&+1, BRLo← T; Store← Stack, DBuf← T, IFUJump[0]; *----------------------------------------------------------- * Special D-machine-only parameterless opcodes. *----------------------------------------------------------- *----------------------------------------------------------- * SetDisplayFieldRate (61027) [Dorado/Dolphin] * Sets vertical sync pulse width from AC0, top border from AC1, and total visible * line count (including borders) from AC2. All counts are number of scan lines * in the even field. * Note: Dolphin has the same instruction, but it works differently. *----------------------------------------------------------- SetDisplayFieldRateA: At[SD400, 27], StkP+2, Branch[SetDisplayFieldRate]; *----------------------------------------------------------- * GetMemConf (61033) [Dorado/Dolphin] * Returns number of pages of real memory in AC0 and number of 64K banks * of virtual memory in AC1. *----------------------------------------------------------- GetMemConfA: At[SD400, 33], RBase← RBase[RealPages]; T← RealPages; Stack&+1← T; T← VirtualBanks, Branch[StackGetsT]; KnowRBase[AEmRegs]; *----------------------------------------------------------- * PowerOff (61034) [Dorado/Dolphin] * Turns off power and does not return. *----------------------------------------------------------- PowerOffA: At[SD400, 34], Nop; * Simply tell the baseboard to turn me off. * This is done by setting the baseboard communication register to 2, * which in turn is done by executing manifold function 2262. T← 2000C; T← T OR (262C), Call[SetDMuxAddress]; * 2262 UseDMD; Branch[.]; * Baseboard will stop me eventually % ********* Not implemented at present ********* *----------------------------------------------------------- * Checksum (61035) [Dorado/Dolphin] * AC0 = sum (initially 0), AC1 = pointer, AC3 = word count. * Returns result in AC0. Interruptible. *----------------------------------------------------------- ChecksumA: At[SD400, 35], StkP+3; Cnt← Stack&-2; Stack&-1← (Fetch← Stack&-1)+1, Branch[ChecksumDn, Cnt=0&-1]; ChecksumLp: T← (Stack&+1)+MD, Branch[ChecksumInt, Reschedule]; Stack&-1← (Fetch← Stack&-1)+1, Branch[.+2, Carry]; Stack← T LCY 1, DblBranch[ChecksumLp, ChecksumDn, Cnt#0&-1]; Stack← (T+1) LCY 1, DblBranch[ChecksumLp, ChecksumDn, Cnt#0&-1]; ChecksumDn: PD← (Stack)+1; * Turn -0 (=177777b) into +0 Stack← A← Stack, XorSavedCarry, IFUJump[0]; ChecksumInt: Stack&+2← (Stack&+2)-1; * Fix pointer and count for interrupt Stack← Cnt; Stack← (Stack)+1, Branch[AEmuReschedule]; % ********* End of unimplemented code ********* *----------------------------------------------------------- * LoadRam (61036) [Dorado/Dolphin] * AC0 = pointer, AC1 = flag * load the array of Items at [MDS,,pointer]; * if flag is odd then jump to the start address in the new Ram image * else resume normal emulation at the next opcode. * In the latter case, the address of the next Item is returned in AC0. *----------------------------------------------------------- LoadRamA: At[SD400, 36], T← Stack&+1, MemBase← ScratchBR; BRLo← T, T← NOT (Stack&-1); * LoadRam reverses the sense of flag LRFlag← T; BRHi← EmuBRHiReg, Call[LoadRam]; T← LRItem; * If it returns, pass back ending address Stack← (Stack)+T, Branch[AEmuNext]; * Restart IFU *----------------------------------------------------------- * SetDefaultDisk (61037) [Dorado/Dolphin] * If AC0 = 0, returns AC0 = current default partition. * If AC0 # 0 and legal, sets default partition and returns -1. * If AC0 is illegal, returns 0. *----------------------------------------------------------- SetDefaultDiskA: At[SD400, 37], T← Stack, RBase← RBase[DefaultPartition]; PD← T-(MaxPartition)-1, Branch[.+2, ALU#0]; T← DefaultPartition, Branch[StackGetsT]; * Return current default T← T-(Q← T)-1, Branch[.+2, Carry']; Stack← A0, IFUJump[0]; * Illegal DefaultPartition← Q; * Set new partition and return -1 StackGetsT: Stack← T, IFUJump[0]; KnowRBase[AEmRegs]; *----------------------------------------------------------- * DoradoIn (61040) [Dorado only] *----------------------------------------------------------- DoradoIn: At[SD400, 40], StkP+1; T← A0, TIOA← Stack&-1; Stack← Input, Branch[ResIOA]; *----------------------------------------------------------- * DoradoOut (61041) [Dorado only] *----------------------------------------------------------- DoradoOut: At[SD400, 41], StkP+1; T← A0, TIOA← Stack&-1; Output← Stack; ResIOA: TIOA← T, IFUJump[0]; *----------------------------------------------------------- * DoradoHalt (61042) [Dorado only] *----------------------------------------------------------- DoradoHalt: At[SD400, 42], IFUJump[0], Breakpoint; *----------------------------------------------------------- * SetPCHist (61043) [Dorado only] * If AC0#0, enables emulator PC sampling and uses the 8192-word table * pointed to by AC0 to maintain a histogram (double-precision counters). * If AC0=0, disables PC sampling. *----------------------------------------------------------- SetPCHistA: At[SD400, 43], T← Stack; T← A0, Q← T, Branch[.+2, ALU=0]; * Long pointer in T,,Q, branch if nil T← EmuBRHiReg; * Non-nil, lengthen pointer RBase← RBase[Events], Call[SetPCHistAddr]; IFUJump[0]; *----------------------------------------------------------- * GenIn (61044) [Dorado only] * Reads GenIn register into AC0. *----------------------------------------------------------- GenInA: At[SD400, 44], Stack← NOT (EventCntA'), IFUJump[0]; *----------------------------------------------------------- * GenOut (61045) [Dorado only] * Writes GenOut register from AC0. *----------------------------------------------------------- GenOutA: At[SD400, 45], EventCntB← Stack, IFUJump[0]; *----------------------------------------------------------- * IFU declarations * Note that all the S-group opcodes that trap are defined in xTraps.mc. *----------------------------------------------------------- EmIFUReg[140, CYCLE, 0, 17]; * 60000-60377 CYCLE EmIFUReg[142, NOPAR, 0, 17]; * 61000-61377 Parameterless opcodes EmIFUPause[151, JSRII, MDS, 1]; * 64400-64777 JSRII EmIFUPause[152, JSRIS, MDS, 1]; * 65000-65377 JSRIS EmIFUReg[156, CONVERT, 1, 17]; * 67000-67377 CONVERT