// EtherRoms.bcpl -- Model 1 // Last modified 27-Aug-81 15:44:35 by Taft get "DoradoProms.defs" external EtherProms //---------------------------------------------------------------------------- let EtherProms(mem) be //---------------------------------------------------------------------------- [ let buff = vec 300 if StEq(mem, "DskEth") then mem!0 = DoAll if StEq(mem, "EtherFifo") & ICtype eq MC10149 then // define the Fifo Prom [ for adr = 0 to 255 do buff!adr = EtherFifo(adr) Header("EtherFifo", 4, buff, 256, 0) PromCommand("Eth-l10") Header("EtherFifo", 4, buff, 256, 0) // the second one is identical PromCommand("Eth-l15") ] if StEq(mem, "EtherPD") & ICtype eq MC10149 then // define the PD Prom [ for adr = 0 to 255 do buff!adr = EtherPD(adr) Header("EtherPD", 4, buff, 256, 0) PromCommand("Eth-h22") ] if StEq(mem, "EtherRcvr") & ICtype eq MC10149 then // define the Rcvr Prom [ for adr = 0 to 255 do buff!adr = EtherRcvr(adr) Header("EtherRcvr", 12, buff, 256, 0) PromCommand("Eth-h09") // command to blow the left nibble PromCommand("Eth-h10", "4") // command to blow the middle nibble PromCommand("Eth-h11", "8") // command to blow the right nibble ] if StEq(mem, "EtherXmtr") & ICtype eq MC10149 then // define the Xmtr Prom [ for adr = 0 to 255 do buff!adr = EtherXmtr(adr) Header("EtherXmtr", 12, buff, 256, 0) PromCommand("Eth-h14") // command to blow the left nibble PromCommand("Eth-h15", "4") // command to blow the middle nibble PromCommand("Eth-h16", "8") // command to blow the right nibble ] ] //---------------------------------------------------------------------------- and EtherFifo(input) = valof //---------------------------------------------------------------------------- // An MCM10150 or MCM10149 (either type will work) // The transmitter fifo and the receiver fifo each use one of these proms. [ manifest [ // The correspondence between voltage levels and bits in the .MB file: high = 1; low = 0 ] structure Input: [ blank bit 8 write bit 4 // msb is A0 pin 4 read bit 4 // msb is A4 pin 10 ] structure Output: [ full bit // Q0 pin 15 notFull bit empty bit notEmpty bit blank bit 12 ] let write = input<<Input.write let read = input<<Input.read let output = nil output<<Output.full = ((read-1) & 17b) eq write? high, low output<<Output.notFull = ((read-1) & 17b) eq write? low, high output<<Output.empty = read eq write? high, low output<<Output.notEmpty = read eq write? low, high resultis output ] //---------------------------------------------------------------------------- and EtherPD(input) = valof //---------------------------------------------------------------------------- // An MCM10150 or MCM10149 (either type will work) [ manifest [ // The correspondence between voltage levels and bits in the .MB file: high = 1; low = 0 // pdEvent values noEvent = low lshift 1 + low collision = low lshift 1 + high dataZero = high lshift 1 + low dataOne = high lshift 1 + high // cntCntrl values count = high; load = low ] structure Input: [ blank bit 8 pdCarrier bit // A0 pin 4 newData bit oldData bit timer bit 4 // msb is A3 pin 9 reportCollisions bit ] structure Output: [ carrier bit // Q0 pin 15 event bit 2 cntCtrl bit blank bit 12 ] let pdCarrier = input<<Input.pdCarrier ne 0 let newData = input<<Input.newData ne 0 let oldData = input<<Input.oldData ne 0 let timer = input<<Input.timer let reportCollisions = input<<Input.reportCollisions ne 0 let carrier = pdCarrier let event = noEvent let cntCtrl = count test pdCarrier ifso test oldData ne newData ifso switchon timer into [ case 0 to 1: // too many transitions [ if reportCollisions then event = collision endcase ] case 2 to 4: endcase // setup transition case 5 to 9: // data transition [ cntCtrl = load event = newData? dataOne, dataZero endcase ] case 10 to 15: // too few transitions [ cntCtrl = load event = reportCollisions? collision, newData? dataOne, dataZero endcase ] ] ifnot if timer ge 12 then // jam or end of packet [ carrier = newData? high, low cntCtrl = load ] ifnot if oldData ne newData then // first transition of new packet [ cntCtrl = load carrier = high event = newData? dataOne, collision ] let output = nil output<<Output.carrier = carrier output<<Output.event = event output<<Output.cntCtrl = cntCtrl resultis output ] //---------------------------------------------------------------------------- and EtherRcvr(input) = valof //---------------------------------------------------------------------------- // Three MCM10150s or MCM10149s (either type will work) [ manifest [ // The correspondence between voltage levels and bits in the .MB file: high = 1; low = 0 // srCtrl values srLoad = low lshift 1 + low srShift = high lshift 1 + low // shift left, count down srHold = high lshift 1 + high // state values idle = 0; maybe = 1; full = 2; imip = 3 // pdEvent values noEvent = 0; collision = 1; dataZero = 2; dataOne = 3 ] structure Input: [ blank bit 8 currentState bit 3 // rxState.0 is A0 pin 4 rxCollision bit pdCarrier bit pdEvent bit 2 // pdEvent.0 is A5 pin 6 rxSRFull bit // *** Low True *** ] structure Output: [ nextState bit 3 // rxState.0 is Q0 pin 15 rxCollision bit rxEOP bit // Q0 pin 15 rxSync bit // *** Low True *** rxIncTrans bit rxCRCReset bit rxCRCClk bit // Q0 pin 15 rxData bit rxSRCtrl bit 2 // rxSRCtrl.0 is Q2 pin 12 blank bit 4 ] let currentState = input<<Input.currentState let rxCollision = input<<Input.rxCollision ne 0 let pdCarrier = input<<Input.pdCarrier ne 0 let pdEvent = input<<Input.pdEvent let rxSRFull = input<<Input.rxSRFull eq 0 //rxCollision, rxIncTrans, rxEOP, and rxSync are treated as booleans and // converted to the correct voltage level at the end of this procedure. //rxCRCReset, rxCRCClk and rxData are treated as voltage levels throughout. let nextState = currentState let preCollision = rxCollision let rxEOP = false let rxSync = false let rxIncTrans = false let rxCRCReset = low let rxCRCClk = low let rxData = low let rxSRCtrl = srHold switchon currentState into [ case idle: [ //In this state we are waiting for the beginning of a packet. //Assertion: all paths to this state have done a rxCtrl = srLoad //in order to reset the bit counter. rxCRCReset = high preCollision = false if pdCarrier then [ nextState = maybe switchon pdEvent into [ case collision: case dataZero: [ //Getting dataZero means we are out of sync with // the phase decoder. This may happen just after power-on. //Getting collision means the phase decoder missed the first // bit of the packet (a common failure of Ethernets which // are too long, aggravated by the too-short preamble). preCollision = true endcase ] case dataOne: [ //All Ethernet packets are preceeded by a degenerate // preamble consisting of a single one bit. //Absense of carrier and then a one bit marks the // beginning of a packet. //The bit is clocked into the CRC register but not // into the receiver SR. rxCRCReset = low rxCRCClk = high rxData = high endcase ] ] ] endcase ] case maybe: [ //In this state we are in the first part of a packet. We have // not put anything into the Fifo, so if things go sour, we can // just go back to the idle state without having to notify people // down the pipe. //Collisions will generally cause very short (less then 16 bit) // packets or at least packets with phase encoding violations // (too many or too few transitions). //If carrier drops and the phase decoder has reported a collision, // then its reportCollisions input must be true, which implies that the // microcode wants to see collisions, so report status for the fragment. //If carrier drops but the PD hasn't reported a collision, then // reportCollisions is probably false, so just go back to the // idle state without putting anything into the pipe. test pdCarrier ifnot [ // We lost carrier. // This was probably a runt packet caused by a collision. // Note that we discard the data. if rxCollision then [ rxIncTrans = true rxEOP = true rxSync = true ] rxSRCtrl = srLoad nextState = idle ] ifso switchon pdEvent into [ case collision: [ preCollision = true endcase ] case dataZero: case dataOne: [ rxSRCtrl = srShift rxCRCClk = high rxData = pdEvent eq dataOne? high, low if rxSRFull then [ //The receiver SR is full - dump it into the Fifo. nextState = full rxSync = true ] endcase ] ] endcase ] case full: [ //In this state we are at the end of a word. //When a packet ends, the phase decoder will drop carrier. //If this happens when the shift register is full, // then we assume that it is the normal end of a packet // (if it isn't the CRC will probably be wrong). //If carrier drops when the shift register is not full (states // IMIP or Maybe), then the packet is damaged so the incomplete // transmission status bit is set. test pdCarrier ifnot //carrier dropped [ nextState = idle rxSRCtrl = srLoad rxIncTrans = false rxEOP = true rxSync = true ] ifso switchon pdEvent into [ case collision: [ preCollision = true endcase ] case dataZero: case dataOne: [ rxSRCtrl = srShift rxCRCClk = high rxData = pdEvent eq dataOne? high, low nextState = imip endcase ] ] endcase ] case imip: [ //In this state, we are in the middle of a word test pdCarrier ifnot //carrier dropped [ nextState = idle rxSRCtrl = srLoad rxIncTrans = true rxEOP = true rxSync = true ] ifso switchon pdEvent into [ case collision: [ preCollision = true endcase ] case dataZero: case dataOne: [ rxSRCtrl = srShift rxCRCClk = high rxData = pdEvent eq dataOne? high, low if rxSRFull then [ //The receiver SR is full - dump it into the Fifo. nextState = full rxSync = true ] endcase ] ] endcase ] default: //unused states go to idle [ nextState = idle rxSRCtrl = srLoad endcase ] ] let output = nil output<<Output.nextState = nextState output<<Output.rxCollision = preCollision? high, low output<<Output.rxEOP = rxEOP? high, low output<<Output.rxSync = rxSync? low, high //low true output<<Output.rxIncTrans = rxIncTrans? high, low output<<Output.rxCRCReset = rxCRCReset output<<Output.rxCRCClk = rxCRCClk output<<Output.rxData = rxData output<<Output.rxSRCtrl = rxSRCtrl resultis output ] //---------------------------------------------------------------------------- and EtherXmtr(input) = valof //---------------------------------------------------------------------------- //Three MCM10150s or MCM10149s (either type will work) [ manifest [ //the correspondence between voltage levels and bits in the .MB file: high = 1; low = 0 //srCtrl values srLoad = low lshift 1 + low srShift = high lshift 1 + low //shift left, count down srHold = high lshift 1 + high //state values idle = 0; mark = 1; data = 2; preCRC = 3; crc = 4; postCRC = 5 ] structure Input: [ blank bit 8 currentState bit 3 //TxState.0 is A0 pin 4 gotTxBit bit txStop bit //TxEOP & TxFifoEmpty txAbort bit //TxCollision % TxDataLate % TxFifoPE % TxOff **Low txStart bit //(TxFifoFull % TxEOP) & PDCarrier' txSREmpty bit //*** Low True *** ] structure Output: [ nextState bit 3 //preTxState.0 is Q0 pin 15 txCRCEnbl bit txCRCClk bit //Q0 pin 15 txGone bit txGo bit txData bit txSRCtrl bit 2 //txSRCtrl.0 is Q0 pin 15 spare bit 2 blank bit 4 ] let currentState = input<<Input.currentState let gotTxBit = input<<Input.gotTxBit ne 0 let txStop = input<<Input.txStop ne 0 let txAbort = input<<Input.txAbort eq 0 //*** low true let txStart = input<<Input.txStart ne 0 let txSREmpty = input<<Input.txSREmpty eq 0 //*** low true //txGone and txGo are treated as booleans //txCRCEnbl, txCRCClk, and txData are treated as voltages let nextState = currentState let txCRCEnbl = low let txCRCClk = low let txGone = txAbort let txGo = false let txData = low let txSRCtrl = srHold test txAbort ifso nextState = idle ifnot switchon currentState into [ case idle: [ //In this state the transmitter is shut down. if txStart then [ //The Fifo is full or as full as it is going to get // (i.e. the packet is < the length of the Fifo), and there // is no carrier present so start transmitting. //A one bit (the 'mark' bit) is inserted before the first // user data bit to allow the receiver to aquire bit phase. nextState = mark txGo = true //enable the phase encoder ] endcase ] case mark: [ //In this state we are wire ORing a one onto the output of the // shift register to form the mark bit, and waiting for the // phase encoder to acknowledge it. txGo = true txData = high if gotTxBit then [ //The Phase encoder has acked the mark bit. nextState = data txCRCClk = high txSRCtrl = srLoad ] endcase ] case data: [ //In this state we are sending user data to the phase encoder. //Note: txCRCClk and txSRCtrl are set several times. txGo = true if gotTxBit then [ //The phase encoder has acked a bit. Clock the bit into // the CRC and shift the next bit into place. txCRCClk = high txSRCtrl = srShift if txSREmpty then [ //That bit was the last one in the register. //Load instead of shifting. txSRCtrl = srLoad if txStop then [ //That was the last bit of the last word of user data. //Supply the CRC output to the phase encoder. //We DO want to shift TxSR so that a zero comes out // because the CRC output is wire ORed to it. txSRCtrl = srShift nextState = preCRC ] ] ] endcase ] case preCRC: [ //We stay in this state for one Dorado cycle. //The purpose of this state is to predecrement the counter so that // we are notified of the end of the packet one bit time early. //This will also shift the shift register, but that's unimportant // since we are supplying the CRC output to the phase encoder. //However it is important that the shift register produce zeros // whenever we shift it since the CRC output is wire ORed to it. //Fortunately this is the case. txGo = true txSRCtrl = srShift txCRCEnbl = high nextState = crc endcase ] case crc: [ //In this state we are sending CRC data to the phase encoder. txGo = true txCRCEnbl = high if gotTxBit then [ //The phase encoder has acked another CRC bit. txCRCClk = high txSRCtrl = srShift if txSREmpty then [ //That was an ack for the next to last CRC bit. txGo = false nextState = postCRC ] ] endcase ] case postCRC: [ //In this state we are waiting for the phase encoder to acknowledge // that it has read the last bit of the CRC. txCRCEnbl = high if gotTxBit then [ //As we transition to the idle state, generate txGone // for one cycle. This will clear txEOP and wakeup the // microcode for the last time. txGone = true nextState = idle ] endcase ] default: [ nextState = idle endcase ] ] let output = nil output<<Output.nextState = nextState output<<Output.txCRCEnbl = txCRCEnbl output<<Output.txCRCClk = txCRCClk output<<Output.txGone = txGone? high, low output<<Output.txGo = txGo? high, low output<<Output.txData = txData output<<Output.txSRCtrl = txSRCtrl resultis output ]