//D1mem.bcpl memory read/write procedures 28 June 1983 get "mcommon.d" get "d1.d" manifest [ get "d1instrs.d" ] manifest [ get "d1regmem.d" ] //manifest [ get "d1dmux.d" ] "TOO MANY NAMES, SO.." manifest [ dCIAINC=#1; dCIA=#2; dTNIA=#5; dBNPC=#6; dOLDCIA=#165 dIMOUT=#172 ] external [ // OS Zero; DoubleAdd; Dvec // MINIT0 @MBlock; MStatus // MASM DoubleNeg; @OddParity // MMPRGN UpdateMPDValues // MCMD ErrorAbort // MGO @CantContinue // MLOAD DoingLoad // D1I0 @DMuxTab; @OldDMuxTab; DWrong; DChecked; DMuxSelect @DHistTab; @SaveMIR; HWStatus; SaveBR36 // D1TABLES @MEMCON // D1ASM ReadDMux; LoadDMD; LoadMIR; @DoStrobe; @SelectTask; @SetALUF; @SetRSTK @Xct; @XctR16; @XctR16C; @XctR16Link; @XctL16; @XctL16C; @XctLFF @XctL16T; @XctL16Q; ConvertAV; IMtoMIR; MIRtoIM @MCXctR; @MCXct; ReadIMX; LoadDWatch; SelFltSrn @MADDRL; @MADDRH; stUndAdr; stReadOnly // D1REG MGetChecks; MPutChecks // D1RES BR36Saved; BreakTask // D1VM LookUpVA; LookUpAA; @VirtualP // D1LOAD AddToVM // D1CONFIG CacheAMask0; CacheAMask1; log2rows; IMXmask //Defined here for use by machine-independent code GetMemData; MGetMemData; PutMemData; MPutMemData; MDATAmemx // Defined here for D1 code RdCACHEA; GetMic2; FixClock; TurnOffRefresh; ClearIMBDAddr @SaveTask; @SaveTPC; @OldTask; OldTPC; SaveALUFM0 SaveALUFM16; SaveSTKP; SaveTIOA; @SaveLINK; @SaveQ; @SaveSRN @SaveMCR; @SaveT; @SaveRBase; @SaveMBase; SaveR0 ] static [ MDATAmemx = MDATAx @SaveTask; @SaveTPC; @OldTask; OldTPC; SaveALUFM0; SaveALUFM16 @SaveLINK; @SaveQ; @SaveSRN; @SaveMCR; @SaveT; @SaveRBase @SaveMBase; @SaveBRHI; @SaveBRLO; SaveSTKP; SaveTIOA; SaveR0 ] let FixIMVA(DVec) be [ if VirtualP then DVec!0 = LookUpVA(DVec!0) ] and GetMic2(DVec) be [ DVec>>lh = MCXctR(BInt+BHoldInt+BCFetchInc) DVec>>rh = MCXctR(BInt+BHoldInt+BCFetchInc) ] and HistShift(I) = valof [ let T = nil for J = MADDRH+I to MADDRH+I+(15*3) by 3 do [ T = (T lshift 1)+((DHistTab!I rshift MADDRL) & 1) ] resultis T ] and RestoreBR36() be [ XctL16T(DisHold+DisCF+NoWake); Xct(MCRFT) XctL16T(SaveBR36!0); Xct(BRHIFT) XctL16T(SaveBR36!1); Xct(BRLOFT) ] and RestoreMemStuff() be [ XctLFF(LMB0,SaveMBase) XctL16T(SaveSRN); Xct(SRNFT) XctL16T(SaveMCR); Xct(MCRFT) XctL16T(SaveT); SelectTask(OldTask) ] and ClearIMBDAddr() be [ LoadDMD(IMAddr0); LoadDMD(IMAddr1) LoadDMD(IMAddr2+HWStatus>>HWStatus.MIRdebugging) LoadDMD(IMControl) ] and RestoreIMBD() be [ if BreakTask ne 0 then CantContinue = CantContinue % didIMBD XctL16C(LLINK,OldTPC); XctL16C(LTPC,17B); Xct(NOOP) XctL16C(LLINK,SaveLINK); SelectTask(OldTask) DoStrobe(Clock+UseCPReg+ClrReady); DoStrobe(Clock+UseCPReg) ] //Used from ConvertAV for CACHED setup and for CACHEA read and RdCACHEA(DVec) = valof [ XctL16T(dVAfVic+UseMcrV+NoWake+FDMiss+DisBR+DisHold+MADDRL) Xct(MCRFT); XctL16T(MADDRH); Xct(NOOP) //For some strange reason, it is essential to do ←PIPE5 right after //DUMMYREF← and before ←PIPE0 or ←PIPE1. let CE = TurnOffRefresh() Xct(DUMMYFT); Xct(NOOP) let T = XctR16C(RPIPE5,DVec) LoadDMD(CE) DVec!0 = XctR16C(RVAHI,DVec) & 7777B; XctR16C(RVALO,DVec+1) resultis T ] and FixIFUMParity(D0,D1) = (D1 & 107777B)+ (OddParity(D0 & 1400B,D1 & 40317B) & 40000B)+ (OddParity(D0 & 377B,D1 & 20000B) & 20000B)+ (OddParity(D0 & 2000B,D1 & 117460B) & 10000B) //Procedure to turn off RunRefresh. This has to be done carefully, //first turning off EnRefreshPeriod', then RunRefresh. Needed when //reading or writing cache flags. and TurnOffRefresh() = valof [ let CE = RunEnable+HWStatus>>HWStatus.RunControl LoadDMD(CE % EnRefreshPeriodx) LoadDMD(RunEnable+ECLup+IOResetx+EnRefreshPeriodx) resultis CE ] and FixClock() be [ if MStatus>>MStatus.MachRunning eq 0 then DoStrobe(Clock+UseCPReg) ] //Do manifold load of IM half-word and LoadIMData(d0,d1,dpar,lhalf) be [ LoadDMD(IMDataA+((d0 rshift 9) & 77B)) LoadDMD(IMDataB+((d0 rshift 3) & 77B)) LoadDMD(IMDataC+((d0 lshift 3) & 77B)+((d1 rshift 13) & 4)+ ((dpar rshift 6) & 2B)) let dcon = IMControl+IMAddressen+ResetCBMIR+ ((d0 rshift 14) & 2B)+lhalf LoadDMD(dcon); LoadDMD(dcon+IMWriteen); LoadDMD(dcon) ] //GetMemData is called directly by MLOAD, MTEST, and some Dorado-specific //actions. Other places in machine-dependent code call MGetMemData. //GetMemData freely smashes "volatile" stuff, but shouldn't clobber //anything that may be loaded from a .MB file. MGetMemData restores //whatever GetMemData clobbers. and GetMemData(MemX,DVec,AVec) = valof [ let T,U,DVX,DVH = nil,vec 4,nil,nil switchon ConvertAV(AVec,MemX) into [ case ABSOLx: DVec!0 = MCXctR(BInt+BHoldInt+BCFetchInc) lshift 8 MCXct(BInt+BCNoop); FixClock(); endcase case MSTATx: GetMic2(DVec); DVec = DVec+1 case ABSx: GetMic2(DVec); MCXct(BInt+BCNoop); FixClock(); endcase case TPCx: test MADDRL eq SaveTask ifso DVec!0 = SaveTPC ifnot [ XctL16C(RTPC,MADDRL); XctR16Link(RLINK,DVec) ] FixIMVA(DVec); endcase case TLINKx: SaveLINK = not XctR16Link(RLINK,DVec) DVec!0 = SaveLINK; FixIMVA(DVec); endcase case OLINKx: T = not XctR16Link(RLINK,DVec) DVec!0 = (T & 177700B)+((T-1) & 77B) FixIMVA(DVec); endcase //Use Dvec here to reduce the max. stack depth. The bad case seems to be //aborting from SimGo, when many stack words are consumed by an overlay. //During the abort, stack becomes ...MStopped, ReadAllRegs, UpdateMPDValues, //MGetMemData, GetMemData, FixIMVA, LookUpVA, RetrieveBlock, GetBlock, //ActOnDiskPages, .... Reduce GetMemData frame size by using Dvec rather //than vec. case IMBDx: DVX,DVH = DMUXlen,DHISTlen Dvec(GetMemData,lv DVX,lv DVH) T,U = DMuxTab,DHistTab; DMuxTab,DHistTab = DVX,DVH LoadDMD(IMControl+IMAddressen+ResetCBMIR) ReadDMux(); MIRtoIM(DVec,DMuxTab+dIMOUT) DMuxTab,DHistTab = T,U ClearIMBDAddr(); endcase case IMx: MADDRL = LookUpAA(MADDRL,DVec) if MADDRL < 0 do //Outside VM [ Zero(DVec,3); resultis false ] case IMXx: ReadIMX(DVec,U); endcase //U is temp storage vec case ALUFMx: test MADDRL eq 16B ifso DVec!0 = SaveALUFM16 ifnot test MADDRL eq 0 ifso DVec!0 = SaveALUFM0 ifnot [ Xct(SetALUF(TFAF0,MADDRL)); XctR16(RT,DVec) ] DVec!0 = DVec!0 lshift 8; endcase //Have Task←17, ProcSRN←1, MemBase[17]←36, virtual address from CACHEA //with word bits in BR 36, T←0, Mcr←NoWake+DisHold or NoWake+DisHold+DisCF //according to Vacant+WP in CacheA entry. case CACHEDx: //MapFaults and data errors ignored for VM. case VMx: Xct(FETCHM) case MDx: Xct(TFMD) case Tx: XctR16(RT,DVec); endcase case RBASEx: Xct(TFPTRS); DVec!0 = (XctR16(RT,DVec))<<Pointers.RBase lshift 12 endcase case TIOAx: Xct(TFTIOA); DVec!0 = XctR16(RT,DVec) & 177400B; endcase case MEMBASEx: Xct(TFPTRS); DVec!0 = (XctR16(RT,DVec))<<Pointers.MemBase lshift 11 endcase case RMx: XctR16(SetRSTK(RRM0,MADDRL),DVec); endcase case STKXx: case STKx: XctR16(RSTACK,DVec); endcase case BRXx: case BRx: XctL16T(0); Xct(DUMMYFT); Xct(NOOP) XctR16C(RVAHI,DVec); XctR16C(RVALO,DVec+1) if MADDRL eq 36B do [ MBlock(SaveBR36,DVec,2); BR36Saved = true ] endcase //MADDRL has two low bits of address = column positioned in McrV field //MADDRH has n row address bits positioned with 4 zeroes to the right //Task 17 is selected and ProcSRN contains 1. //VA[4:31] wind up in DVec[4:31], flags in DVec[0:3]. case CACHEAx: DVec>>nib0 = (RdCACHEA(DVec))<<nib2 DVec!0 = DVec!0 & CacheAMask0 DVec!1 = DVec!1 & CacheAMask1 endcase //BR 36 is selected by MemBase and has VA in position; MCR contains //DisHold+NoWake; task 17 is selected; SRN 1 is selected. //MAP shows (MapDirtyb, MapParity, MapPE), (Ref, WP, Dirty), and (RP[0:15]) //as 3 fields case MAPx: XctLFF(LRB0,0); XctL16(LRM0,0); Xct(RDMAP) XctR16(RMAP,DVec+1) T = XctR16(RERRS,DVec) rshift 12 T = (T & 3B)+((T & 10B) rshift 1)+ ((DVec!0 & 44000B) eq 0 ? 10B,0) DVec!0 = ((XctR16(RCONFG,DVec) & 3) lshift 4)+T endcase case IFUMx: XctR16(RIFL,DVec+1); DVec!0 = XctR16(RIFH,DVec) & 3777B DVec!1 = FixIFUMParity(DVec!0,DVec!1) endcase case LDRx: MIRtoIM(DVec,MADDRL); endcase case MDATAx: MBlock(DVec,MADDRL,3); endcase case MADDRx: MBlock(DVec,MADDRL,2); endcase case DMUXx: DVec!0 = DMuxSelect!MADDRL switchon MADDRL into [ case dCIA: case dBNPC: case dCIAINC: case dTNIA: case dOLDCIA: if (DMuxSelect eq DMuxTab) % (DMuxSelect eq OldDMuxTab) then FixIMVA(DVec) ] endcase //History of a particular signal over 32 ReadDMux()'s case DHISTx: MBlock(DVec,MADDRL,3); endcase //Value of all 32 history signals at a particular clock time case VHx: DVec!0 = HistShift(0); DVec!1 = HistShift(16*3); endcase //Legitimately get here only when ConvertAV fails; presently this can //only happen for the STKX memory, which has addresses that may be //OK'ed by CertifyAV but which might subsequently become undefined. default: resultis false ] resultis true ] and MGetMemData(MemX,DVec,AVec,Ext) = valof [ unless MGetChecks(MEMCON!MemX) do resultis false let AVec1 = vec 1; MBlock(AVec1,AVec,2) //Translate ROW memory into 4 instances of CACHEA followed by the //victim and next-victim test MemX eq ROWx ifso [ test Ext eq 4 ifso //victim, next-victim [ SelFltSrn(); XctL16T(DisBR+DisHold+DisCF); Xct(MCRFT) XctL16T(AVec!1 lshift 4); Xct(DUMMYFT); Xct(NOOP) DVec!0 = XctR16C(RPIPE5,DVec) lshift 12 RestoreBR36(); RestoreMemStuff(); Xct(NOOP); LoadMIR(SaveMIR) resultis true ] ifnot //one of the CACHEA's [ MemX = CACHEAx; AVec1!1 = AVec!1 + (Ext lshift log2rows) ] ] //Show Pipe0 to Pipe5 all high-true on three display lines ifnot if MemX eq PIPEx do [ unless ConvertAV(AVec,MemX) eq PIPEx do resultis false switchon Ext into [ case 0: DVec!0 = XctR16C(RVAHI,DVec) & 7777B XctR16C(RVALO,DVec+1); endcase case 1: XctR16(RPIPE2,DVec); XctR16(RMAP,DVec+1); endcase case 2: DVec!0 = XctR16(RERRS,DVec) xor 47416B DVec!1 = XctR16C(RPIPE5,DVec+1) xor 4000B; endcase ] XctL16T(SaveSRN); Xct(SRNFT); XctL16T(SaveT); Xct(NOOP) LoadMIR(SaveMIR); resultis true ] if GetMemData(MemX,DVec,AVec1) do [ switchon MemX into [ case TPCx: if MADDRL eq SaveTask then resultis true XctL16C(LLINK,SaveLINK); endcase case IMBDx: RestoreIMBD(); endcase case IMx: //if undef., GetMemData returns false here case IMXx: XctL16C(LLINK,SaveLINK); endcase case RMx: XctLFF(LRB0,SaveRBase); endcase case ALUFMx: if (MADDRL eq 16B) % (MADDRL eq 0) then resultis true XctL16T(SaveT); endcase case MAPx: XctL16(LRM0,SaveR0); XctLFF(LRB0,SaveRBase) case VMx: case CACHEDx: case CACHEAx: RestoreBR36() case BRXx: case BRx: RestoreMemStuff(); endcase case MEMBASEx: case TIOAx: case MDx: case RBASEx: XctL16T(SaveT) case TLINKx: case OLINKx: case Tx: SelectTask(OldTask); endcase default: resultis true case STKXx: case STKx: SelectTask(OldTask); XctL16Q(SaveSTKP); Xct(STKPFQ) case IFUMx: XctL16Q(SaveQ); endcase ] Xct(NOOP); LoadMIR(SaveMIR); resultis true ] resultis false ] //PutMemData is called directly by MLOAD and MTEST (where speed is //important) and by some Dorado-specific actions. Other places in //machine-independent code call MPutMemData. PutMemData freely smashes //"volatile" stuff, but must be sure to leave both the hardware and //any Midas statics in good shape for the Get and MGet procedures to //deliver accurate values. MPutMemData calls PutMemData and then //restores any smashed volatile registers. and PutMemData(MemX,DVec,AVec) = valof [ let D0,D1,D2 = DVec!0,DVec!1,DVec!2 let TVec,TVec1,DVX = vec 1,vec 1,vec 10 switchon ConvertAV(AVec,MemX) into [ case ABSx: MCXct(BInt+BCStoreInc+(D0<<lh)) MCXct(BInt+BCStoreInc+(D0<<rh)) FixClock(); resultis true case ABSOLx: MCXct(BInt+BCStoreInc+(D0<<lh)); FixClock(); resultis true //Illegal virtual addresses as data for TPC or TLINK will be given a false //exit here, then ErrorAbort from MPutMemData. case TPCx: if VirtualP do [ D0 = LookUpAA(D0) if D0 < 0 then resultis false ] test MADDRL eq SaveTask ifso SaveTPC = D0 ifnot [ XctL16C(LLINK,D0); XctL16C(LTPC,MADDRL) ] endcase case TLINKx: if VirtualP do [ D0 = LookUpAA(D0) if D0 < 0 then resultis false ] SaveLINK = D0 XctL16C(LLINK,SaveLINK); endcase case IMBDx: IMtoMIR(DVX,DVec) //Convert good/bad to parity bit LoadIMData(D0,D1,DVX!1,IMlh) LoadIMData((D1 lshift 1)+(D2 rshift 15), D2 lshift 1,DVX!3,0) ClearIMBDAddr() LoadDMD(IMDataA); LoadDMD(IMDataB); LoadDMD(IMDataC) resultis true //VM can only be built during a Ld, LdSyms, etc. and the VM mapping //cannot subsequently be changed. case IMx: test DoingLoad //AddToVM will ErrorAbort(..) on AA too large ifso MADDRL = AddToVM(MADDRL,DVec) ifnot [ MADDRL = LookUpAA(MADDRL,DVec) if MADDRL < 0 then resultis false //not in VM ] case IMXx: XctL16C(LLINK,MADDRL) XctL16C((D0 < 0 ? LIMLK,LIMLFK)+((D2 & 20000B) rshift 11), (D0 lshift 1)+(D1 rshift 15)) XctL16C(LLINK,MADDRL) XctL16C(((D1 & 40000B) ne 0 ? LIMRK,LIMRFK)+ ((D2 & 10000B) rshift 10), (D1 lshift 2)+(D2 rshift 14)) endcase case ALUFMx: D0 = D0<<lh test MADDRL eq 16B ifso SaveALUFM16 = D0 ifnot test MADDRL eq 0 ifso SaveALUFM0 = D0 ifnot [ XctL16Q(D0); Xct(SetALUF(LAF0,MADDRL)) ] endcase case Tx: SaveT = D0; XctL16T(SaveT); endcase case RBASEx: SaveRBase = D0 rshift 12 XctLFF(LRB0,SaveRBase); endcase case TIOAx: SaveTIOA = D0; XctL16Q(D0); Xct(TIOAFQ); endcase case MEMBASEx: SaveMBase = D0 rshift 11 XctLFF(LMB0,SaveMBase); endcase case RMx: XctL16(SetRSTK(LRM0,MADDRL),D0); endcase case STKXx: case STKx: XctL16(WSTACK,D0); endcase case BRXx: BR36Saved = false case BRx: XctL16T(D0); Xct(BRHIFT); XctL16T(D1); Xct(BRLOFT) if MADDRL eq 36B then BR36Saved = false endcase //MADDRL has 2 low bits of address = column positioned in McrV field //MADDRH has n row address bits positioned with 4 zeroes to the right //Relevant bits of VA[4:31] are in DVec[4:31], flags in DVec[0:3]. //(With 256-word pages and 1k ic's in cache data section, VA[7:21] are //relevant). Use BR 36 from task 17 to reference CACHEA. //Because NoRef is true, CACHED will not be updated from memory case CACHEAx: XctL16T(FDMiss+DisCF+UseMcrV+DisHold+NoRef+NoWake+MADDRL) Xct(MCRFT) //BR36←VA[4:31] - value for flags, T←value for flags, then reference //T+BR. This cleverly accomplishes Mar←value for flags while //BR+Mar has desired VA[4:31]. TVec!0 = D0 & CacheAMask0 & #7777 //VA[7:15] for BRHI TVec!1 = MADDRH+(D1 & CacheAMask1) //VA[16:21] for BRLO D1 = ((not D0) rshift 8) & 360B //Flags for CFLAGS←T TVec1!0 = 0; TVec1!1 = D1; DoubleNeg(TVec1) DoubleAdd(TVec,TVec1) XctL16T(TVec!0); Xct(BRHIFT) XctL16T(TVec!1); Xct(BRLOFT) //FETCH is done twice to prevent tag-bit screw up XctL16T(D1); Xct(NOOP); Xct(FETCHM); Xct(NOOP) Xct(FETCHM); Xct(NOOP) XctL16T(FDMiss+UseMcrV+DisHold+NoRef+NoWake+MADDRL) Xct(MCRFT); XctL16T(D1); Xct(NOOP) //Flags written in a separate reference because of problem with Dirty bit. //The sequence only works with RunRefresh off. D0 = TurnOffRefresh() Xct(DUMMYFT); Xct(CFLAGSFT) LoadDMD(D0); endcase //BR has VA in position. Task 17, ProcSRN 1 selected, Mcr has NoWake, T=0. //Everything except the Ref bit is handled by Map←. WP is loaded from //TIOA.0 and Dirty from TIOA.1. case MAPx: XctL16Q(D0 lshift 14); Xct(TIOAFQ); XctL16Q(D1); Xct(MAPTQ) endcase case CACHEDx: case VMx: XctL16Q(D0); Xct(STORETQ); endcase case IFUMx: XctL16Q(D0); Xct(IFHFQ); Xct(RQ) XctL16Q(FixIFUMParity(D0,D1)); Xct(IFLFQ); Xct(RQ); endcase case LDRx: IMtoMIR(MADDRL,DVec); resultis true case MDATAx: MADDRL!2 = D2 & 170000B case MADDRx: MBlock(MADDRL,DVec,2) LoadDWatch(); resultis true case DMUXx: DMuxSelect!MADDRL = D0; resultis true case DHISTx: MBlock(MADDRL,DVec,3); resultis true default: resultis false ] Xct(NOOP); resultis true ] and MPutMemData(MemX,DVec,AVec,Extension) be [ let AVec1 = vec 1; MBlock(AVec1,AVec,2) test MemX eq ROWx ifso [ if Extension eq 4 then ErrorAbort(stReadOnly) MemX = CACHEAx; AVec1!1 = AVec!1 + (Extension lshift log2rows) ] ifnot if MemX eq DMUXx do [ if DMuxSelect ne DChecked then ErrorAbort(stReadOnly) ] MPutChecks(MEMCON!MemX) //Will ErrorAbort(..) if illegal if PutMemData(MemX,DVec,AVec1) do [ switchon MemX into [ case TPCx: if MADDRL eq SaveTask then [ UpdateMPDValues(); return ] case IMx: case IMXx: XctL16C(LLINK,SaveLINK); Xct(NOOP); endcase case RMx: XctLFF(LRB0,SaveRBase); endcase case STKXx: case STKx: XctL16Q(SaveSTKP); Xct(STKPFQ) case TIOAx: XctL16Q(SaveQ); Xct(NOOP) case MEMBASEx: case TLINKx: case Tx: case RBASEx: SelectTask(OldTask); endcase case IFUMx: XctL16Q(SaveQ); Xct(NOOP); endcase case ALUFMx: if (MADDRL ne 16B) & (MADDRL ne 0) do [ XctL16Q(SaveQ); Xct(NOOP); endcase ] default: UpdateMPDValues(); return case IMBDx: RestoreIMBD(); endcase case MAPx: XctL16Q(SaveTIOA); Xct(TIOAFQ) case CACHEDx: case VMx: XctL16Q(SaveQ); Xct(NOOP) case CACHEAx: RestoreBR36() case BRXx: case BRx: RestoreMemStuff(); endcase ] LoadMIR(SaveMIR); ReadDMux() UpdateMPDValues(); return ] ErrorAbort(stUndAdr) ]