//D1SimCon.bcpl
//	Last edited: 30 April 1980

get "d1.d"
manifest [ get "d1pe.d" ]
get "d1sim.d"
manifest [ get "d1dmux.d" ]

external [
// D1I0
	@DMuxTab; @OldDMuxTab

// Defined here
	SimControl
]


//SimControl is called by DSimulate to check consistency of signals in the
//control section and of other signals elsewhere in the machine that are
//closely related to the control section (primarily signals that depend
//upon task numbers).

let SimControl(Tn,Correct,T1DTab,T2DTab,Tneven,
	block,ff,jcn,FFfunc,oldblock,oldjcn,oldFFfunc,
	lvT2RepeatCur,lvT2DoCBr,lvHoldReq) = valof
[	let ctd = DMuxTab!dCTD
	let ctask = DMuxTab!dCTASK
	let Next = DMuxTab!dNEXT
	let cia = DMuxTab!dCIA
//Following value correct at even clocks only
	let NextCL = (ctd lshift 4)+ctask	//LastNext = ctd, CurrLast = ctask
//T2RepeatCur is only valid for Tn ge 2, but need it for TNIA prediction
//in one case, so done here.
	let oldSwitchUpx = OldDMuxTab>>C.bSwitchUpx
	let T2RepeatCur = (T2DTab>>C.bHoldA & oldSwitchUpx) ne 0
	rv lvT2RepeatCur = T2RepeatCur

	let FFEQ = DMuxTab!dFFEQ

//**Simulation of t1 signals dependent upon t0 and t1 signals**
	if Tn ge 1 do
	[ let T1FFeq = T1DTab!dFFEQ

//**Simulation of stuff derived from values at Tn-2**
	  test Tn ge 2
	  ifso
	  [
	    let oldctask = OldDMuxTab!dCTASK
	    let oldcia = OldDMuxTab!dCIA
	    let oldNext = OldDMuxTab!dNEXT
	    let oldStopTasks = OldDMuxTab>>C.StopTasks
//StopTasks = TaskingOff & TOffIsOK ? 1,(TaskingOn ? 0,oldStopTasks)
	    Correct>>C.StopTasks = (FFEQ & #40020) eq #40020 ? 1,
		(FFEQ < 0 ? 0,oldStopTasks)
	    let oldRWIMTPCx = OldDMuxTab>>C.RWIMTPCx

	    let oldSwitchx = OldDMuxTab>>C.bSwitchxa
	    let oldBigBorBDisp = OldDMuxTab>>C.BigBorBDisp
	    let oldMulStep = OldDMuxTab>>C.MulStep
	    let oldDoCBr = OldDMuxTab>>C.bDoCBr

	    Correct>>C.RIMorRTPCdly = not ((oldRWIMTPCx & 5B) eq 5B)
//Back2x is the task 2 cycles back = oldLastx
	    let cBack2x = nil
	    test Tn eq 3
	    ifso	//Tn eq 3
	    [ cBack2x = OldDMuxTab>>P1.CurrLastx
	      NextCL = (Next lshift 4)+oldctask
	    ]
	    ifnot	//Tn eq 2
	    [ cBack2x = OldDMuxTab>>P0.RepeatCurrC ne 0 ?
		not oldctask,OldDMuxTab>>P1.LastNextx
	    ]
//Because DblClock' ne (clk0' & clk1'), double-clocked flipflops on the
//processor boards are unsimuable after multiphase instructions.
	    let oldMultiPhase = (oldjcn & 347B) eq 147B
	    if not oldMultiPhase do
	    [ Correct>>P1.Back2x = cBack2x
	      Correct>>P1.Back3x = OldDMuxTab>>P1.Back2x
	    ]

	    Correct>>P0.LasteqCurrx = oldctask ne oldNext
	    let T2TrueNext = nil
	    test T2RepeatCur
	    ifso
	    [ T2TrueNext = oldctask
	      Correct>>C.MulStep = oldMulStep
	      Correct>>C.BigBorBDisp = oldBigBorBDisp
	    ]
	    ifnot
	    [ T2TrueNext = oldNext
	      if oldSwitchx ne 0 do
	      [	Correct>>C.MulStep = (T1FFeq & 4B) ne 0
		Correct>>C.BigBorBDisp =
		  (((T1FFeq & 3) ne 0) & 1) % (T1FFeq lshift 1)
	      ]
	    ]
	    Correct!dCTASK = T2TrueNext
	    let oldbnt = OldDMuxTab!dBNT
//Predict Ready from OldReady, IsNext, and switch stuff
	    let newReady = OldDMuxTab!dREADY & not
		((100000B rshift oldbnt) & (oldSwitchx eq 0))
//Test FF=Notify'
	    if (OldDMuxTab!dFFEQ & 10B) eq 0 then
		newReady = newReady % (100000B rshift (oldFFfunc & 17B))
	    if OldDMuxTab>>C.PreEmptingx eq 0 then
		newReady = newReady % (100000B rshift oldctask)
	    Correct!dREADY = (T2RepeatCur ? OldDMuxTab!dREADY,newReady) &
		77777B

//**When NoWakeups in MCR changes at t1, the task 17 wakeup request may
//**change after T1; this is a hardware bug for which a fix is pending.
//**In the meantime disable simulation of signals dependent upon oldPEnc
//**when NoWakeups is changing.
	    if (DMuxTab!dMCR xor OldDMuxTab!dMCR) & 1 eq 0 do
	    [ let oldPEnc = OldDMuxTab!dPENC
	      let olddSwitchUp =
		(not oldStopTasks) & (oldPEnc > T2TrueNext)
	      Correct!dBNT = (T2RepeatCur & (oldbnt > oldPEnc)) ?
		oldbnt,oldPEnc
	      Correct>>C.TPCBypass = (oldctask eq oldPEnc) & oldblock 

	      Correct>>C.bSwitchUpx = not olddSwitchUp
//We have block = T2dBlock because SimTest loads MIR with a random
//instruction in which Block = the value previously there.
	      Correct>>C.bSwitchxa = oldStopTasks ne 0 ? oldSwitchx,
		not (olddSwitchUp % ((oldPEnc < T2TrueNext) &
		  (T2TrueNext ne 0) & (T2RepeatCur ? oldblock,block)
		))
	    ]

//CIA is predicted from BNPC on Switch, from TNIA or CIA+1 on Switch',
//or from old CIA on RepeatCurrent.  Effects of pending dispatches and
//branch conditions are included in BNPC, but only dispatch bits are
//included in TNIA, so DoCBr has to be ORed in.
	    let ccia,bctrue = nil,0
	    test T2RepeatCur
	    ifso ccia = oldcia
	    ifnot test oldSwitchx eq 0
	      //Can't predict CIA[0:1] because BNPC[0:1] unmuffled
	      ifso ccia = (OldDMuxTab!dBNPC & 37777B)+(cia & 140000B)
//Have to worry about the illegal use of Link←B, BigBDispatch←B,
//BDispatch←B, or MulStep concurrent with IM/TPC read/write.
	      ifnot
	      [	test oldMultiPhase	//Return function?
		ifso
		[ ccia = T2DTab>>C.LinkgBMuxa ne 0 ?
		    T2DTab!dBMUX,(oldcia & 177700B)+((oldcia+1) & 77B)
		  if OldDMuxTab>>C.MulStep ne 0 then
			ccia = ccia % (cia & 2)
		]
		ifnot
		[ let cia01 = (oldjcn & 347B) eq 107B ? cia,oldcia
		  ccia = (OldDMuxTab!dTNIA & 37777B)+(cia01 & 140000B)
		]
//DoCBr can be taken from OldDMuxTab at t3; at t2, the branch condition
//result would be predicted from OldDMuxTab jcn and ff and from the
//DMuxTab condition values (mufflered by ProcH) for Rodd, R<0, ALU
//branch conditions and IOatta (?), or from OldDMuxTab condition values for
//Cnt=0&-1.
		test Tneven
		ifso
		[ if (oldjcn < 200B) & ((oldjcn & 7B) ne 7B) &
			(oldjcn > 17B) do
			bctrue = BCResult(oldjcn & 7B)
		  if (oldFFfunc rshift 3) eq 6B do
			bctrue = bctrue %
			  BCResult(oldFFfunc & 7B)
		]
		ifnot bctrue = oldDoCBr
	      ]
	    Correct!dCIA = ccia % bctrue
	    rv lvT2DoCBr = bctrue	//For T2IfuNextMacro for SimIFU

//Propagate CIMrhPE and CIMlhPE to IMrhPE and IMlhPE
	    Correct!dESTAT = (Correct!dESTAT & not(IMlhPE+IMrhPE)) +
		((OldDMuxTab!dESTAT & (CIMrhPE+CIMlhPE))lshift 8)
	  ]
	  ifnot	//Tn eq 1 (LastNext = Next, CurrLast unknown)
	  [ NextCL = (Next lshift 4)+(DMuxTab!dNEXTCL & 17B)
	  ]

	  let T1cia = T1DTab!dCIA
	  Correct!dCIAINC = (T1cia & 177700B)+((T1cia+1) & 77B)
//B←Link if FF=ReadLink or Link←CPReg
	  Correct>>C.BgLinkx = (T1FFeq & 3000B) eq 0
//Link←BMuxa if FF= WriteLink, Link←CPReg, BigBDispatch, or BDispatch
	  Correct>>C.LinkgBMuxa = (T1FFeq & 6003B) ne 0
//CTD is always loaded from CTASK at t1 and t2.  It may be something
//else on intermediate clocks of polyphase instructions but never check
//at these times.
	  Correct!dCTD = T1DTab!dCTASK
	]
	Correct!dNEXTCL = not ((NextCL lshift 8)+NextCL)

//**Simulate signals derived from other signals without intervening flops**
	let PEnc = DMuxTab!dPENC
	let Bnt = DMuxTab!dBNT
	let ToPE = DMuxTab!dTOPE
	let Ready = DMuxTab>>C.Ready
	let Hold = DMuxTab>>C.bHoldA
	let Phase0 = DMuxTab>>C.Phase0
	let Phase4 = DMuxTab>>C.Phase4
	let RWTPCorRWIMx = not DMuxTab>>C.RWTPCorRWIM

	let Switchx = DMuxTab>>C.bSwitchxa
	let SwitchUpx = DMuxTab>>C.bSwitchUpx
	let BigBorBDisp = DMuxTab>>C.BigBorBDisp
	let MulStep = DMuxTab>>C.MulStep
	let DoCBr = DMuxTab>>C.bDoCBr

//Predict PEnc from ToPE checking priority encoder
	let cPEnc = 15
	let ToPEbits = (DMuxTab!dTOPE)+100000B
	while (ToPEbits & 1) eq 0 do
	[ ToPEbits = ToPEbits rshift 1
	  cPEnc = cPEnc-1
	]
	Correct!dPENC = cPEnc

//1's in ToPE can be predicted from Ready and Bnt.
	let IsNext = (100000B rshift Bnt) & (Switchx eq 0)
	let cToPE = Ready & not IsNext
	Correct!dTOPE = cToPE % DMuxTab!dTOPE

//Determine TNIA from CIA and jcn decoding, and then modify if a
//dispatch is pending.
//Note that the mufflered TNIA includes dispatch stuff but not
//the branch condition result.
	let cDecCntx,cNextMacro = true,0
	let ctnia,tniamask,cbrtypex = 0,37777B,37B
	let cRWIMTPCx,cRWTPCorRWIM = 17B,0
	let jcnr3 = (jcn rshift 3) & 3
	test jcn ge 200B
	ifso test jcn ge 300B
	  ifso ctnia = (jcn lshift 6) & 7700B		//global
	  ifnot
	  [ ctnia = (cia & 7700B)+(jcn & 77B)		//local
	    cbrtypex = 17B
	  ]
	ifnot test jcn < 20B
	  ifso
	  [ ctnia = (ff lshift 4)+(jcn & 17B)		//long
	    cbrtypex = 33B
	  ]
	  ifnot test (jcn & 7B) eq 7B
	    ifso test jcn < 40B
	      ifso ctnia = 0				//undefined
	      ifnot test jcn ge 100B
		ifso					//return
		[ tniamask,cbrtypex = 0,35B
		  if jcn ge 140B do
		  [ cRWTPCorRWIM = true
		    cRWIMTPCx = table [ 16B; 15B; 13B; 7B ] ! jcnr3
		  ]
		]
		ifnot					//ifujump
		[ tniamask,ctnia = 30003B,jcnr3
		  cbrtypex = 27B
		  cNextMacro = 1
		]
	    ifnot					//cond br
	    [ ctnia = (cia & 7700B)+((jcn rshift 1) & 60B)+
		((jcn rshift 2) & 6B)
	      cbrtypex = 36B
	      if (jcn & 7B) eq 3B then cDecCntx = false
	    ]
	if (tniamask & 17B) eq 17B do Correct>>C.Call = (ctnia & 17B) eq 0
//If a multiply-step is occurring, tnia.14 is unknown unless already 1.
	if MulStep ne 0 then tniamask = tniamask & 177775B
//If a BigBDispatch or BDispatch occurred in the last microinstruction
//for this task, then tnia[8:15] or tnia[13:15] might be unknown unless
//already 1.  However, if (CTD eq CTASK) and (Tn ne 1), then the bits
//affecting the B/BigB dispatch are on the BMux unless RepeatCur is true.
	let tniamask2x = BigBorBDisp ge 2 ? 377B,(BigBorBDisp ne 0) & 7B
	test (Tn < 2) % (ctd ne ctask) % T2RepeatCur
	ifso tniamask = tniamask & not tniamask2x
	ifnot ctnia = ctnia % (T2DTab!dBMUX & tniamask2x)
	Correct!dTNIA = (ctnia + (cia & 30000B & tniamask)) %
		((not tniamask) & DMuxTab!dTNIA)

	Correct!dNEXT = Switchx eq 0 ? Bnt,ctask

	let dStartCycle = Phase4 % (RWTPCorRWIMx & Phase0)
//Stop is false for SimTest (cleared by LoadMIR) but true for SimGo (?)
//	Correct>>C.Stop = false
	Correct>>C.preStartCyclea = dStartCycle & (not Tneven)
	Correct>>C.dStartCycle = dStartCycle
	Correct>>C.Phase0 = Tneven
	Correct>>C.Phase4 = 0	//**Bug here???
	Correct>>C.RWTPCorRWIM = cRWTPCorRWIM
	Correct>>C.RWIMTPCx = cRWIMTPCx

	Correct>>C.bSWdx = Switchx
//??	Correct>>C.GND = 0
	Correct>>C.brtypex = cbrtypex

//This is the correct logic function for RepeatCurrent, but the actions
//that depend upon RepeatCurrent need to use the value of Hold that
//develops at t1.
	let RepeatCur = (Hold & SwitchUpx) ne 0
	let nexttask = RepeatCur ? ctask,Next
	Correct>>C.Nexteq0 = Next eq 0
	Correct>>C.CTaskeq0 = ctask eq 0
	Correct>>C.PEncGtTrueNextx = PEnc le nexttask
	Correct>>C.PEncLtTrueNextx = PEnc ge nexttask
	Correct>>C.PEnceqCTx = ctask ne PEnc
	Correct>>C.PreEmptingx = SwitchUpx % (block & not Hold)
	Correct>>C.RepeatCurz = RepeatCur

	Correct>>P0.RepeatCurrC = RepeatCur
	Correct>>P0.EMUx = ctask ne 0
	Correct>>P1.NextMacro = cNextMacro

//FF's decoded directly on ContA
	Correct!dFFEQ = FFfunc ge 360B ? 20B,	//Notify
	    selecton FFfunc into
	    [
case 70B:	31B			//BigBDispatch
case 71B:	32B			//BDispatch
case 72B:	34B			//Multiply
case 140B:	70B			//UseDMD
case 141B:	20030B			//MidasOn
case 142B:	(Switchx ne 0 ? 40030B,40010B)	//TaskingOff
case 143B:	100030B			//TaskingOn
case 147B:	4030B			//Link←B
case 176B:	2030B			//B←RWCPReg
case 177B:	1030B			//B←Link
default:	30B
	    ]

	if FFfunc eq 63B then cDecCntx = false
	Correct>>P0.DecCntx = cDecCntx

	if (FFEQ & 20B) eq 0 then rv lvHoldReq = 1

//Handle LastNext and CurrLast stuff on ProcH/L
	Correct>>P0.CurreqNextx = ctask ne Next

//Control store address is TNIA or BNPC based upon SWITCH
	let CSaddr = Switchx eq 0 ? DMuxTab!dBNPC,
		(DMuxTab!dTNIA % DoCBr)
	Correct>>C.RA = CSaddr rshift 1
	Correct>>C.CSBDbx = selecton CSaddr & 4001B into
	[
	case 0:		 7B
	case 1:		13B
	case 4000B:	15B
	case 4001B:	16B
	]
	resultis RepeatCur
]


and BCResult(bc) = valof
[	bc = table [
		10000B	//ResEqZero'
		 4000B	//ResLtZero'
		 2000B	//AluCarry
		40000B	//CnteqZero' (T2)
		  400B	//RmLtZero'
		    1B	//RmOdd'
		20000B	//IOatta (T2)
		 1000B	//Overflow'
		] ! bc
	let Tab = bc ge 20000B ? OldDMuxTab,DMuxTab
	resultis ((Tab!dSTKRB & bc) eq 0) & 1
]