// 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 ]