// Sun-Proms.bcpl -- Sun 3 MB Ethernet board Proms
// Last modified February 10, 1984 4:00 PM by Boggs
// Sun-Rev-B & CadLink-Rev-0 boards require a hardware change: (TX Multibus/Fifo interlock)
// isolate U308 pin 4; connect it to U308 pin 25 (P.Read/)
// Other known hardware fixes:
// isolate U511 pin 4; connect it to U111 pin 12 (T.AbortAck/)
// isolate U513 pin 2; connect it to U317 pin 9 (TX.Jam)
external [ Ws; OpenFile; Puts; Closes; Allocate; Free; sysZone ]
static [ memory; mbFile ]
structure String [ length byte; char↑1,1 byte ]
manifest [ high = 1; low = 0 ]
//-----------------------------------------------------------------------------------------
let SunProms() be
//-----------------------------------------------------------------------------------------
[
mbFile = OpenFile("Sun-Proms.mb")
DoMemory("TX", 256, 8, TX)
DoMemory("NewTX", 256, 8, NewTX)
DoMemory("Ctrl", 32, 40, Ctrl)
Puts(mbFile, 0) //0 = end of file
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)
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 = Allocate(sysZone, (nData+15)/16)
for addr = 0 to nAddr-1 do
[
Puts(mbFile, 1) //1 = memory contents
Puts(mbFile, 0) //source line number
Proc(addr, data)
for i = 0 to (nData+15)/16 -1 do Puts(mbFile, data!i)
]
Free(sysZone, data)
]
//-----------------------------------------------------------------------------------------
and TX(addr, data) be
//-----------------------------------------------------------------------------------------
[
structure Addr:
[
blank bit 8
state bit 2
timeout bit
inhibit bit
ready bit
wrd bit
jam bit
carrier bit
]
structure Data:
[
nextState bit 2
notIdle bit
idle bit
blank bit
load bit
notGo bit
go bit
blank bit 8
]
manifest
[
stateIdle = 0
stateData = 1
stateCRC = 2
]
let state = addr<<Addr.state
let timeout = addr<<Addr.timeout eq high
let inhibit = addr<<Addr.inhibit eq high
let ready = addr<<Addr.ready eq high
let wrd = addr<<Addr.wrd eq high
let jam = addr<<Addr.jam eq high
let carrier = addr<<Addr.carrier eq high
let nextState = state
let idle, load, go = false, false, false
switchon state into
[
case stateIdle:
[
if not ready % carrier then idle = true
if ready & not carrier then nextState = stateData //aquire Ether
endcase
]
case stateData:
[
go = not jam
if not jam & wrd & ready then load = true
if wrd & inhibit then nextState = stateCRC //end of data
if wrd & not ready then nextState = stateIdle //data late
if jam % timeout then nextState = stateIdle //catastrophe
endcase
]
case stateCRC:
[
go = not jam
if wrd then nextState = stateIdle //end of CRC
if jam % timeout then nextState = stateIdle //catastrophe
endcase
]
default: nextState = stateIdle
]
data>>Data.nextState = nextState
data>>Data.notIdle = idle? low, high
data>>Data.idle = idle? high, low
data>>Data.load = load? high, low
data>>Data.notGo = go? low, high
data>>Data.go = go? high, low
]
//-----------------------------------------------------------------------------------------
and NewTX(addr, data) be
//-----------------------------------------------------------------------------------------
[
structure Addr:
[
blank bit 8
state bit 2
timeout bit
inhibit bit
ready bit
wrd bit
jam bit
carrier bit
]
structure Data:
[
nextState bit 2
notIdle bit
idle bit
done bit //low true
load bit
abrt bit //low true
go bit
blank bit 8
]
manifest
[
stateIdle = 0
stateData = 1
stateCRC = 2
]
let state = addr<<Addr.state
let timeout = addr<<Addr.timeout eq high
let inhibit = addr<<Addr.inhibit eq high
let ready = addr<<Addr.ready eq high
let wrd = addr<<Addr.wrd eq high
let jam = addr<<Addr.jam eq high
let carrier = addr<<Addr.carrier eq high
let nextState = state
let idle, load, go = false, false, false
switchon state into
[
case stateIdle:
[
if ready & not carrier & not inhibit then nextState = stateData //aquire Ether
endcase
]
case stateData:
[
go = not jam
if not jam & not inhibit & wrd & ready then load = true
if wrd & inhibit then nextState = stateCRC //end of data
if wrd & not ready then nextState = stateIdle //data late
if jam % timeout then nextState = stateIdle //catastrophe
endcase
]
case stateCRC:
[
go = not jam
if wrd then nextState = stateIdle //end of CRC
if jam % timeout then nextState = stateIdle //catastrophe
endcase
]
default: nextState = stateIdle
]
data>>Data.nextState = nextState
data>>Data.notIdle = nextState ne stateIdle? low, high
data>>Data.idle = nextState eq stateIdle? high, low
data>>Data.done = (nextState eq stateIdle & not jam)? low, high
data>>Data.load = load? high, low
data>>Data.abrt = jam? low, high
data>>Data.go = go? high, low
]
//-----------------------------------------------------------------------------------------
and Ctrl(addr, data) be
//-----------------------------------------------------------------------------------------
[
structure Addr:
[
blank bit 11
Instr bit 5
]
structure Data:
[
BufWE bit
RBufCE bit //low true
TBufCE bit //low true
CRead bit //low true
PWrite bit //low true
PRead bit //low true
TWrite bit //low true
RRead bit //low true
RxOverflow bit
TxTimeout bit
RxInterrupt bit
QEmpty bit
Ack bit //low true
Resume bit
CarryIn bit
DestHigh bit
DestLow bit 2
Function bit 3
Source bit 3
BReg bit 4
AReg bit 4
Branch bit 3
Next bit 5 //msb is low true
blank bit 8
]
manifest
[
// instruction addresses
Init1 = 0
Init2 = 1
Init3 = 2
RxEnd1 = 3
RxEnd2 = 4
RxEnd3 = 5
RxEnd4 = 6
RxReady1 = 7
RxReady2 = 10b
PortReadReq1 = 11b
PortReadReq2 = 12b
PortWriteReq1 = 13b
PortStart = 20b
PortStart1 = 14b
PortStart2 = 15b
PortStart3 = 21b
PortStart4 = 16b
TxStart = 17b
TxAbort1 = 22b
TxTimer = 23b
TxTimer1 = 24b
TxTimer2 = 25b
TxTimer3 = 26b
TxTimer4 = 27b
// Startup addresses
RxReady = 30b
RxEnd = 31b
TxReady = 32b
TxAbort = 33b
PortWriteReq = 34b
PortReadReq = 35b
Init = 36b
Idle = 37b
// Register names
spare = 0
rBase = 1
rGet = 2
rPut = 3
count = 4
tBase = 5
tGet = 6
tPut = 7
retry = 8
timer = 9
random = 10
// Branch Condition Codes (CC)
Never = 0
NonZero = 1
Zero = 2
NoCarry8 = 3
Positive = 4
Negative = 5
Equal = 6
Always = 7
// 2901 Functions
RplusS = 0
SminusR = 1
RminusS = 2
RorS = 3
RandS = 4
NotRandS = 5
RxorS = 6
RxnorS = 7
// 2901 Sources
AQ = 0
AB = 1
ZQ = 2
ZB = 3
ZA = 4
DA = 5
DQ = 6
DZ = 7
// 2901 Destinations
QReg = 0
Nop = 1
RamA = 2
RamF = 3
RamQD = 4
RamD = 5
RamQU = 6
RamU = 7
]
let Next, Branch = 0, Never
let CarryIn, Function, Source = nil, nil, nil
let AReg, BReg, Destination = nil, nil, nil
let Resume, Ack, QEmpty = false, false, false
let RxInterrupt, TxTimeout, RxOverflow = false, false, false
let RRead, TWrite, PRead, PWrite, CRead = false, false, false, false, false
let TBufCE, RBufCE, BufWE = false, false, false
switchon addr<<Addr.Instr into
[
case Init: //tGet ← -1
[
CarryIn = low; Function = RxnorS; Source = AB
AReg = tGet; BReg = tGet; Destination = RamF
Next = Init1
endcase
]
case Init1: //tPut ← 0
[
CarryIn = low; Function = RandS; Source = ZB
AReg = spare; BReg = tPut; Destination = RamF
Next = Init2
endcase
]
case Init2: //rGet ← 0
[
CarryIn = low; Function = RandS; Source = ZB
AReg = spare; BReg = rGet; Destination = RamF
Next = Init3
endcase
]
case Init3: //rPut ← 0; Goto(RxEnd1)
[
CarryIn = low; Function = RandS; Source = ZB
AReg = spare; BReg = rPut; Destination = RamF
Next = RxEnd1
endcase
]
case RxEnd: //Test(rPut-rGet) mod 2↑11; SetRxOverflow(EQ); Return(EQ); Ack
[
CarryIn = low; Function = RminusS; Source = AB
AReg = rPut; BReg = rGet; Destination = Nop
RxOverflow, Ack = true, true
Branch = Equal
Next = RxEnd1
endcase
]
case RxEnd1: //Latch ← Count; Count ← 0
[
CarryIn = low; Function = RandS; Source = ZB
AReg = count; BReg = count; Destination = RamA
Next = RxEnd2
endcase
]
case RxEnd2: //RxBuf[rBase] ← Latch
[
CarryIn = low; Function = RorS; Source = ZB
AReg = spare; BReg = rBase; Destination = Nop
RBufCE, BufWE, CRead = true, true, true
Next = RxEnd3
endcase
]
case RxEnd3: //rBase ← rPut; RxBuf[rPut] ← Latch; QEmpty
[
CarryIn = low; Function = RorS; Source = ZA
AReg = rPut; BReg = rBase; Destination = RamF
RBufCE, BufWE, CRead = true, true, true
QEmpty = true
Next = RxEnd4
endcase
]
case RxEnd4: //rPut ← rPut+1; Return
[
CarryIn = high; Function = RplusS; Source = ZB
AReg = spare; BReg = rPut; Destination = RamF
Branch = Always
endcase
]
case RxReady: //Test(rPut-rGet) mod 2↑11; SetRxOverflow(EQ); Return(EQ); Ack
[
CarryIn = low; Function = RminusS; Source = AB
AReg = rPut; BReg = rGet; Destination = Nop
RxOverflow, Ack = true, true
Branch = Equal
Next = RxReady1
endcase
]
case RxReady1: //count ← count+1
[
CarryIn = high; Function = RplusS; Source = ZB
AReg = spare; BReg = count; Destination = RamF
Next = RxReady2
endcase
]
case RxReady2: //RxBuf[rPut] ← Rx; rPut ← rPut+1; Return
[
CarryIn = high; Function = RplusS; Source = ZA
AReg = rPut; BReg = rPut; Destination = RamA
RBufCE, BufWE, RRead = true, true, true
Branch = Always
endcase
]
case PortReadReq: //Port ← RxBuf[rGet]
[
CarryIn = low; Function = RorS; Source = ZB
AReg = spare; BReg = rGet; Destination = Nop
RBufCE, PWrite = true, true
Next = PortReadReq1
endcase
]
case PortReadReq1: //Test(rGet-Rbase) mod 2↑11; ClearRxInterrupt(EQ); Return(EQ)
[
CarryIn = low; Function = RminusS; Source = AB
AReg = rGet; BReg = rBase; Destination = Nop
RxInterrupt = true
Branch = Equal
Next = PortReadReq2
endcase
]
case PortReadReq2: //rGet ← rGet+1; Goto(Idle)
[
CarryIn = high; Function = RplusS; Source = ZB
AReg = spare; BReg = rGet; Destination = RamF
Next = Idle
endcase
]
case PortWriteReq: //Test(tPut); TxBuf[tPut] ← Port; Return(Z); Resume(PortStart)
[
CarryIn = low; Function = RorS; Source = ZB
AReg = PortStart; BReg = tPut; Destination = Nop
TBufCE, BufWE, PRead = true, true, true
Resume = true
Branch = Zero
Next = PortWriteReq1
endcase
]
case PortWriteReq1: //tPut ← tPut-1; Return(NZ); Goto(TxStart); Resume(PortStart3)
[
CarryIn = low; Function = SminusR; Source = ZB
AReg = PortStart3; BReg = tPut; Destination = RamF
Resume = true
Branch = NonZero
Next = TxStart
endcase
]
case PortStart: //tBase ← DataBus
[
CarryIn = low; Function = RorS; Source = DZ
AReg = spare; BReg = tBase; Destination = RamF
Next = PortStart1
endcase
]
case PortStart1: //tPut ← tBase
[
CarryIn = low; Function = RorS; Source = ZA
AReg = tBase; BReg = tPut; Destination = RamF
Next = PortStart2
endcase
]
case PortStart2: //mask ← 0 (mask is in Q register)
[
CarryIn = low; Function = RandS; Source = ZQ
AReg = spare; BReg = spare; Destination = QReg
Next = PortStart3
endcase
]
case PortStart3: //retry ← 0
[
CarryIn = low; Function = RandS; Source = ZB
AReg = spare; BReg = retry; Destination = RamF
Next = PortStart4
endcase
]
case PortStart4: //timer ← 0; Return
[
CarryIn = low; Function = RandS; Source = ZB
AReg = spare; BReg = timer; Destination = RamF
Branch = Always
endcase
]
case TxStart: //tGet ← tBase; Goto(TxReady)
[
CarryIn = low; Function = RorS; Source = ZA
AReg = tBase; BReg = tGet; Destination = RamF
Next = TxReady
endcase
]
case TxReady: //Tx ← TxBuf[tGet]; tGet ← tGet-1; Ack; Goto(Idle)
[
CarryIn = low; Function = SminusR; Source = ZA
AReg = tGet; BReg = tGet; Destination = RamA
TBufCE, TWrite = true, true
Ack = true
Next = Idle
endcase
]
case TxAbort: //mask ← ShiftLeft(mask); Ack
[
CarryIn = low; Function = RorS; Source = ZQ
AReg = spare; BReg = spare; Destination = RamQU
Ack = true
Next = TxAbort1
endcase
]
case TxAbort1: //retry ← random & mask; Return(NZ); Goto(TxStart)
[
CarryIn = low; Function = RandS; Source = AQ
AReg = random; BReg = retry; Destination = RamF
Branch = NonZero
Next = TxStart
endcase
]
case Idle: //random ← random+1; Return(NCY8); Goto(TxTimer)
[
CarryIn = high; Function = RplusS; Source = ZB
AReg = spare; BReg = random; Destination = RamF
Branch = NoCarry8
Next = TxTimer
endcase
]
case TxTimer: //Test(tGet); Return(Neg)
[
CarryIn = low; Function = RorS; Source = ZB
AReg = spare; BReg = tGet; Destination = Nop
Branch = Negative
Next = TxTimer1
endcase
]
case TxTimer1: //timer ← timer-1; Return(Z); SetTxTimeout(Z); Resume(TxTimer4)
[
CarryIn = low; Function = SminusR; Source = ZB
AReg = TxTimer4; BReg = timer; Destination = RamF
Resume, TxTimeout = true, true
Branch = Zero
Next = TxTimer2
endcase
]
case TxTimer2: //Test(retry); Return(Z)
[
CarryIn = low; Function = RorS; Source = ZB
AReg = spare; BReg = retry; Destination = Nop
Branch = Zero
Next = TxTimer3
endcase
]
case TxTimer3: //Retry ← Retry-1; Return(NZ); Goto(TxStart)
[
CarryIn = low; Function = SminusR; Source = ZB
AReg = spare; BReg = retry; Destination = RamF
Branch = NonZero
Next = TxStart
endcase
]
case TxTimer4: //tGet ← -1; Return
[
CarryIn = low; Function = RxnorS; Source = AB
AReg = tGet; BReg = tGet; Destination = RamF
Branch = Always
endcase
]
]
data>>Data.BufWE = BufWE? high, low
data>>Data.RBufCE = RBufCE? low, high
data>>Data.TBufCE = TBufCE? low, high
data>>Data.CRead = CRead? low, high
data>>Data.PWrite = PWrite? low, high
data>>Data.PRead = PRead? low, high
data>>Data.TWrite = TWrite? low, high
data>>Data.RRead = RRead? low, high
data>>Data.RxOverflow = RxOverflow? high, low
data>>Data.TxTimeout = TxTimeout? high, low
data>>Data.RxInterrupt = RxInterrupt? high, low
data>>Data.QEmpty = QEmpty? high, low
data>>Data.Ack = Ack? low, high
data>>Data.Resume = Resume? high, low
data>>Data.CarryIn = CarryIn
data>>Data.DestHigh = Destination rshift 2
data>>Data.DestLow = Destination
data>>Data.Function = Function
data>>Data.Source = Source
data>>Data.BReg = BReg
data>>Data.AReg = AReg
data>>Data.Branch = Branch
data>>Data.Next = Next xor 20b
]