// DCPProms.bcpl -- Dicentra Central Processor Proms
// Last modified November 28, 1982 5:35 AM by Boggs
external [ Ws; OpenFile; Puts; Closes; TruncateDiskStream; CallSwat; Multibus ]
static [ memory; mbFile ]
structure String [ length byte; char↑1,1 byte ]
manifest [ high = 1; low = 0 ]
//-----------------------------------------------------------------------------------------
let DCPProms() be
//-----------------------------------------------------------------------------------------
[
mbFile = OpenFile("DCPProms.mb")
DoMemory("Stack", 512, 8, Stack)
DoMemory("IB", 512, 8, IB)
DoMemory("ALUHigh", 512, 8, ALUHigh)
DoMemory("FX", 512, 8, FX)
DoMemory("FYZ", 512, 8, FYZ)
DoMemory("FY1", 512, 8, FY1)
DoMemory("FY2", 512, 8, FY2)
DoMemory("FZ1", 512, 8, FZ1)
DoMemory("FZ2", 512, 8, FZ2)
DoMemory("Trap", 512, 8, Trap)
DoMemory("Multibus", 512, 24, Multibus)
Puts(mbFile, 0) //0 = end of file
TruncateDiskStream(mbFile)
Closes(mbFile)
]
//-----------------------------------------------------------------------------------------
and DoMemory(name, nAddr, nData, Proc) be
//-----------------------------------------------------------------------------------------
// nAddr is number of addresses; nData is number of output bits
[
Ws("*N"); Ws(name)
Puts(mbFile, 4) //4 = define memory
memory = memory +1
Puts(mbFile, memory)
Puts(mbFile, nData)
// Write Asciz string to word stream. What a pain!
if name>>String.length gr 1 then
for i = 1 to name>>String.length-1 by 2 do
Puts(mbFile, name>>String.char↑i lshift 8 + name>>String.char↑(i+1))
Puts(mbFile, (name>>String.length & 1) eq 0? 0,
name>>String.char↑(name>>String.length) lshift 8)
Puts(mbFile, 2) //2 = set current memory
Puts(mbFile, memory)
Puts(mbFile, 0) //location counter
let data = vec 1; if nData gr 32 then CallSwat("increase data vector size")
for addr = 0 to nAddr-1 do
[
Puts(mbFile, 1) //1 = memory contents
Puts(mbFile, 0) //0 = source line number (not used)
Proc(addr, data)
for i = 0 to (nData+15)/16 -1 do Puts(mbFile, data!i)
]
]
//-----------------------------------------------------------------------------------------
and Stack(addr, data) be
//-----------------------------------------------------------------------------------------
[
structure Addr:
[
blank bit 7
StackP bit 4
PopX bit
PopZ bit
PushX bit
PushY bit
PushZ bit
]
structure Data:
[
StackTrap bit
blank bit 3
StackP bit 4
blank bit 8
]
let PopX = addr<<Addr.PopX eq high
let PopZ = addr<<Addr.PopZ eq high
let PushX = addr<<Addr.PushX eq high
let PushY = addr<<Addr.PushY eq high
let PushZ = addr<<Addr.PushZ eq high
let StackP = addr<<Addr.StackP
let Pop = PopX % PopZ
let Push = PushX % PushY % PushZ
let StackTrap = Pop & StackP eq 0 %
Push & StackP eq 15 %
PopX & Push & StackP eq 0 %
Push & PopZ & StackP eq 15 %
PopX & PopZ & (StackP eq 0 % StackP eq 1) %
PopX & PopZ & Push & (StackP eq 0 % StackP eq 1)
if Pop then StackP = StackP -1
if Push then StackP = StackP +1
data>>Data.StackP = StackP
data>>Data.StackTrap = StackTrap? high, low
]
//-----------------------------------------------------------------------------------------
and IB(addr, data) be
//-----------------------------------------------------------------------------------------
[
manifest
[
// instruction buffer states
ibEmpty = 0
ibByte = 1
ibFull = 2
ibWord = 3
]
structure Addr:
[
blank bit 7
IBDisp bit
ReadIB bit
WriteIB bit
IBPtrGetsWord bit
IBPtrGetsByte bit
EnC2Funs bit
Interrupt bit
InIBPtr bit 2
unused bit
]
structure Data:
[
GoodIBDisp bit
IBEmpty bit //low true
IBRefillTrap bit
ReadIB0 bit //low true
ReadIB1 bit //low true
WriteIBFront bit
OutIBPtr bit 2
blank bit 8
]
let IBDisp = addr<<Addr.IBDisp eq high
let ReadIB = addr<<Addr.ReadIB eq high
let WriteIB = addr<<Addr.WriteIB eq high
let IBPtrGetsWord = addr<<Addr.IBPtrGetsWord eq high
let IBPtrGetsByte = addr<<Addr.IBPtrGetsByte eq high
let EnC2Funs = addr<<Addr.EnC2Funs eq high
let Interrupt = addr<<Addr.Interrupt eq high
let InIBPtr = addr<<Addr.InIBPtr
let IBEmpty = false
let IBRefillTrap = false
let GoodIBDisp = false
let ReadIB0 = false
let ReadIB1 = false
let WriteIBFront = false
let OutIBPtr = InIBPtr
let advance = false
// IBRefillTrap causes a trap to one of four locations executed in Cycle 1:
// 3400b or 3000b Interrupt
// 2400b IB refill; IB not empty
// 2000b IB refill; IB is empty
if IBDisp & EnC2Funs & not ReadIB & not WriteIB & not IBPtrGetsWord then
test (Interrupt % InIBPtr ne ibFull) & not IBPtrGetsByte
ifso IBRefillTrap = true
ifnot [ GoodIBDisp = true; advance = true ]
// ReadIB puts IBFront onto the X bus and advances IBPtr.
// Since there are always at least 2 bytes in the buffer when we begin
// executing a Mesa instruction, ReadIB can't trap.
// Note that "ReadIB, IBDisp" is not legal (its a Noop).
if ReadIB & not IBDisp & not WriteIB & not IBPtrGetsWord & not IBPtrGetsByte then
advance = true
if advance then
[
WriteIBFront = true
ReadIB0 = (InIBPtr & 1) eq 0 //ReadIB0 is the inverse of IBPtr.1
ReadIB1 = not ReadIB0
OutIBPtr = selecton InIBPtr into
[
case ibFull: ibWord
case ibWord: ibByte
case ibByte: ibEmpty
case ibEmpty: ibEmpty
]
]
// Unless we are refilling due to a jump instruction, IBPtr will be ibByte or ibEmpty.
// If it's ibEmpty then we need to write IBFront from IB0.
// If it's ibByte then we shouldn't write IBFront.
// If we are refilling due to a jump instruction, IBPtr value is unknown.
// It will be specified by a IBPtr← in this cycle or the next.
// Note that "WriteIB, ReadIB" is not legal (it's a Noop).
if WriteIB & not IBDisp & not ReadIB test InIBPtr eq ibEmpty
ifso
[
WriteIBFront = true
test IBPtrGetsByte
ifso [ ReadIB1 = true; OutIBPtr = ibByte ]
ifnot [ ReadIB0 = true; OutIBPtr = ibWord ]
]
ifnot OutIBPtr = ibFull
// IBPtr←byte or IBPtr←word always come in cycle 1 immediately after a WriteIB.
// They load IBFront with the even or odd dest byte and set up IBPtr.
if IBPtrGetsWord & not IBDisp & not ReadIB & not WriteIB & not IBPtrGetsByte then
[
WriteIBFront = true
ReadIB0 = true
OutIBPtr = ibWord
]
if IBPtrGetsByte & not IBDisp & not ReadIB & not WriteIB & not IBPtrGetsWord then
[
WriteIBFront = true
ReadIB1 = true
OutIBPtr = ibByte
]
data>>Data.IBEmpty = OutIBPtr eq ibEmpty? low, high
data>>Data.IBRefillTrap = IBRefillTrap? high, low
data>>Data.GoodIBDisp = GoodIBDisp? high, low
data>>Data.ReadIB0 = ReadIB0? low, high
data>>Data.ReadIB1 = ReadIB1? low, high
data>>Data.WriteIBFront = WriteIBFront? high, low
data>>Data.OutIBPtr = OutIBPtr
]
//-----------------------------------------------------------------------------------------
and ALUHigh(addr, data) be
//-----------------------------------------------------------------------------------------
[
structure Addr:
[
blank bit 7
paS0 bit
paS1 bit
paS2 bit
paF1 bit
paF2 bit
pMem bit
Cycle3 bit
Cycle2 bit
blank bit
]
structure Data:
[
aSh0 bit
aSh1 bit
aSh2 bit
aFh1 bit
aFh2 bit
ReadMD bit //low true
blank bit 2
blank bit 8
]
let paS0 = addr<<Addr.paS0 eq high
let paS1 = addr<<Addr.paS1 eq high
let paS2 = addr<<Addr.paS2 eq high
let paF1 = addr<<Addr.paF1 eq high
let paF2 = addr<<Addr.paF2 eq high
let pMem = addr<<Addr.pMem eq high
let Cycle3 = addr<<Addr.Cycle3 eq high
let Cycle2 = addr<<Addr.Cycle2 eq high
data>>Data.aSh0 = (pMem & Cycle3? false, paS0)? high, low
data>>Data.aSh1 = (pMem & Cycle3? true, paS1)? high, low
data>>Data.aSh2 = (pMem & Cycle3? true, paS2)? high, low
data>>Data.aFh1 =(pMem & Cycle3? true, paF1)? high, low
data>>Data.aFh2 =(pMem & Cycle3? true, paF2)? high, low
data>>Data.ReadMD = pMem & Cycle2? low, high
]
//-----------------------------------------------------------------------------------------
and FX(addr, data) be
//-----------------------------------------------------------------------------------------
[
structure Addr:
[
blank bit 7
pfX bit 4
blank bit 5
]
structure Data:
[
blank bit
WriteRH bit
Shift bit //low true
CycleX bit //low true
CInGetsPC16X bit //low true
MapRefX bit //low true
PopX bit
PushX bit
blank bit 8
]
let FX = addr<<Addr.pfX
data>>Data.WriteRH = FX eq 9? high, low
data>>Data.Shift = FX eq 10? low, high
data>>Data.CycleX = FX eq 11? low, high
data>>Data.CInGetsPC16X = FX eq 12? low, high
data>>Data.MapRefX = FX eq 13? low, high
data>>Data.PopX = FX eq 14? high, low
data>>Data.PushX = FX eq 15? high, low
]
//-----------------------------------------------------------------------------------------
and FYZ(addr, data) be
//-----------------------------------------------------------------------------------------
[
structure Addr:
[
blank bit 7
pfS01 bit 2
pfS23 bit 2
pfZ01 bit 2 =
[
pfZ0 bit
pfZ1 bit
]
pfY0 bit
pfY1 bit
blank bit
]
structure Data:
[
Zero bit //low true
IB bit //low true
Rot bit //low true
Byte bit //low true
Const bit //low true
FourBitBr bit //low true
TwoBitBr bit //low true
OneBitBr bit //low true
blank bit 8
]
let pfS01 = addr<<Addr.pfS01
let pfS23 = addr<<Addr.pfS23
let pfZ01 = addr<<Addr.pfZ01
let pfZ0 = addr<<Addr.pfZ0 eq high
let pfY0 = addr<<Addr.pfY0 eq high
let pfY1 = addr<<Addr.pfY1 eq high
data>>Data.Zero = (pfS23 eq 1 % (pfS23 eq 3 & pfZ0))? low, high
data>>Data.IB = (pfS23 eq 3 & pfZ01 eq 3)? low, high
data>>Data.Rot = (pfS23 eq 0 & pfZ01 eq 3)? low, high
data>>Data.Byte = pfS01 eq 3? low, high
data>>Data.Const = pfS23 eq 1? low, high
data>>Data.FourBitBr = (pfS01 eq 0 & pfY0 & not pfY1)? low, high
data>>Data.TwoBitBr = (pfS01 eq 0 & pfY0)? low, high
data>>Data.OneBitBr = (pfS01 eq 0 & not pfY0)? low, high
]
//-----------------------------------------------------------------------------------------
and FY1(addr, data) be
//-----------------------------------------------------------------------------------------
[
structure Addr:
[
blank bit 7
pfY bit 4
pfS01 bit 2
blank bit 3
]
structure Data:
[
WriteDebA bit //low true
WriteExtCtrl bit
ClrIntTrap bit //low true
IBDisp bit
SetInterrupt bit
WriteStkP bit
WriteIB bit
CycleY bit //low true
blank bit 8
]
let pfY = addr<<Addr.pfY
let pfS01 = addr<<Addr.pfS01
data>>Data.WriteDebA = (pfS01 eq 2 & pfY eq 0)? low, high
data>>Data.WriteExtCtrl = (pfS01 eq 2 & pfY eq 1)? high, low
data>>Data.ClrIntTrap = (pfS01 eq 1 & pfY eq 2)? low, high
data>>Data.IBDisp = (pfS01 eq 1 & pfY eq 3)? high, low
data>>Data.SetInterrupt = (pfS01 eq 1 & pfY eq 4)? high, low
data>>Data.WriteStkP = (pfS01 eq 1 & pfY eq 5)? high, low
data>>Data.WriteIB = (pfS01 eq 1 & pfY eq 6)? high, low
data>>Data.CycleY = (pfS01 eq 1 & pfY eq 7)? low, high
]
//-----------------------------------------------------------------------------------------
and FY2(addr, data) be
//-----------------------------------------------------------------------------------------
[
structure Addr:
[
blank bit 7
pfY bit 4
pfS01 bit 2
blank bit 3
]
structure Data:
[
blank bit
MapRefY bit //low true
blank bit
PushY bit
IORefY bit //low true
WriteBank bit
BHEN bit
RawRef bit
blank bit 8
]
let pfY = addr<<Addr.pfY
let pfS01 = addr<<Addr.pfS01
data>>Data.MapRefY = (pfS01 eq 1 & pfY eq 9)? low, high
data>>Data.PushY = (pfS01 eq 1 & pfY eq 11)? high, low
data>>Data.IORefY = ((pfS01 eq 1 % pfS01 eq 2) & pfY eq 12)? low, high
data>>Data.WriteBank = (pfS01 eq 1 & pfY eq 13)? high, low
data>>Data.BHEN = (pfS01 eq 2 & (pfY eq 12 % pfY eq 14 % pfY eq 15))? low, high
data>>Data.RawRef = ((pfS01 eq 1 % pfS01 eq 2) & pfY eq 14)? high, low
]
//-----------------------------------------------------------------------------------------
and FZ1(addr, data) be
//-----------------------------------------------------------------------------------------
[
structure Addr:
[
blank bit 7
pfZ bit 4
pfS23 bit 2
blank bit 3
]
structure Data:
[
ADR0 bit
IBPtrGetsByte bit
IBPtrGetsWord bit
CInGetsPC16Z bit //low true
IORefZ bit //low true
PopZ bit
PushZ bit
AltUAddr bit
blank bit 8
]
let pfZ = addr<<Addr.pfZ
let pfS23 = addr<<Addr.pfS23
data>>Data.ADR0 = (pfS23 eq 3 & pfZ eq 0)? high, low
data>>Data.IBPtrGetsByte = (pfS23 eq 0 & pfZ eq 1)? high, low
data>>Data.IBPtrGetsWord = (pfS23 eq 0 & pfZ eq 2)? high, low
data>>Data.CInGetsPC16Z = (pfS23 eq 0 & pfZ eq 3)? low, high
data>>Data.IORefZ = (pfS23 eq 3 & pfZ eq 7)? low, high
data>>Data.PopZ = (pfS23 eq 0 & pfZ eq 5)? high, low
data>>Data.PushZ = (pfS23 eq 0 & pfZ eq 6)? high, low
data>>Data.AltUAddr = (pfS23 eq 0 & pfZ eq 7)? high, low
]
//-----------------------------------------------------------------------------------------
and FZ2(addr, data) be
//-----------------------------------------------------------------------------------------
[
structure Addr:
[
blank bit 7
pfZ bit 4
pfS23 bit 2
blank bit 3
]
structure Data:
[
ReadDebB bit //low true
ReadExtStat bit //low true
ReadMisc bit //low true
ReadRH bit //low true
blank bit
ReadIB bit
blank bit
IBHigh bit //low true
blank bit 8
]
let pfZ = addr<<Addr.pfZ
let pfS23 = addr<<Addr.pfS23
data>>Data.ReadDebB = (pfS23 eq 3 & pfZ eq 8)? low, high
data>>Data.ReadExtStat = (pfS23 eq 3 & pfZ eq 6)? low, high
data>>Data.ReadMisc = (pfS23 eq 3 & pfZ eq 10)? low, high
data>>Data.ReadRH = (pfS23 eq 3 & pfZ eq 11)? low, high
data>>Data.ReadIB = (pfS23 eq 3 & pfZ eq 13)? high, low
data>>Data.IBHigh = (pfS23 eq 3 & pfZ eq 15)? low, high
]
//-----------------------------------------------------------------------------------------
and Trap(addr, data) be
//-----------------------------------------------------------------------------------------
[
manifest
[
// These bits appear inverted on X[8-9] when fZ = XLow←Misc.
// If X[8-9] = zero then a control store parity error occured.
stateIBEmpty = 0
stateStack = 1
stateInit = 2
stateNoTrap = 3
stateParity = 3
]
structure Addr:
[
blank bit 7
CurrentState bit 2
TrapIn bit
IBEmptyTrap bit //low true
StackTrap bit
InitTrap bit //low true
ParityTrap bit
ClrIntTrap bit //low true
Cycle1 bit
]
structure Data:
[
NextState bit 2
Trap bit
ParityLED bit //low true
ForceBank0 bit
blank bit 3
blank bit 8
]
let CurrentState = addr<<Addr.CurrentState
let IBEmptyTrap = addr<<Addr.IBEmptyTrap eq low
let StackTrap = addr<<Addr.StackTrap eq high
let InitTrap = addr<<Addr.InitTrap eq low
let ParityTrap = addr<<Addr.ParityTrap eq high
let ClrIntTrap = addr<<Addr.ClrIntTrap eq low
let Cycle1 = addr<<Addr.Cycle1 eq high
let TrapIn = addr<<Addr.TrapIn eq high
let NextState = CurrentState
let Trap = false
// The Trap machine only remembers one trap. If multiple traps occur,
// only one of them is reported. The priority of reporting is:
// InitTrap - highest priority
// ParityTrap
// StackTrap
// IBEmptyTrap - lowest priority
// If a trap occurs in an instruction which clears traps, the new trap still takes.
// The instruction at location 0 must read the trap type (XBus←Misc) and
// clear the trap (ClrIntTrap), or else another trap will occur.
// InitTrap causes a continuous Trap regardless of the cycle.
// The CP repeatedly executes the instruction at location 0.
// The Multibus FSM loops in Cycle 1.
// The control store bank is forced to 0.
// When InitTrap goes away, the processor takes off from location 0 in cycle 1.
// The instruction at location 0, which the CP repeatedly executes while
// Init is asserted, contains fY = ClrIntTrap. Unless inhibited, this will
// cause the trap machine to forget its mission 3 cycles before the processor
// is finally released from its chains. TrapIn detects this peculiar
// combination and remembers it long enough to inhibit ClrIntTrap until the last
// time that that magic instruction at location 0 is executed.
if ClrIntTrap & CurrentState eq stateInit & (TrapIn % not Cycle1) then ClrIntTrap = false
if ClrIntTrap then NextState = stateNoTrap
if IBEmptyTrap & CurrentState eq stateNoTrap then NextState = stateIBEmpty
if StackTrap & (CurrentState eq stateNoTrap % CurrentState eq stateIBEmpty) then
NextState = stateStack
if ParityTrap & CurrentState ne stateInit then NextState = stateParity
if InitTrap then NextState = stateInit
// Trap must be asserted during Cycle 2, so we must decide to assert it during Cycle 1.
// A Trap causes the address loaded into NIA at the end of cycle 2 to be zero.
// The instruction at location 0 is fetched in cycle 3 and executed in cycle 1.
if Cycle1 & (NextState ne stateNoTrap % ParityTrap) then Trap = true
// ParityTrap is a level (JK-FF) rather than a 1-cycle pulse like the rest of the traps.
// This is fortunate since the trap mechanism has only 2 state bits but has 5 states:
// NoTrap, IBEmpty, Stack, Parity, Init.
// InitTraps and ParityTraps go to location 0 in bank 0.
// All other traps go to location 0 in the current bank.
// This trap handler might just pass control to the trap handler in bank 0.
data>>Data.NextState = NextState
data>>Data.ParityLED = ParityTrap? low, high
data>>Data.ForceBank0 = (Trap & ParityTrap) % InitTrap? high, low
data>>Data.Trap = Trap? high, low
]