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