Livt packages
Livt.IO
Version 1.8.1
Memory, UART, I2C, SPI, and Ethernet input/output components for Livt hardware designs.
Published files (126)
- phy
- EthernetCrc.lvt
- EthernetReceiver.lvt
- EthernetResult.lvt
- EthernetTransmitter.lvt
- IEthernetLinkStatus.lvt
- IEthernetMedia.lvt
- IEthernetReceiver.lvt
- IEthernetTransmitter.lvt
- IMdioController.lvt
- IMdioPins.lvt
- IMiiPins.lvt
- IRmiiPins.lvt
- MdioController.lvt
- MiiAdapter.lvt
- MiiClearEndpoint.lvt
- MiiClockBridge.lvt
- MiiCompletionReceiver.lvt
- MiiFifoStorage.lvt
- MiiReadBuffer.lvt
- MiiReceiver.lvt
- MiiTransmitter.lvt
- RmiiAdapter.lvt
src/ethernet/MiiAdapter.lvt
namespace Livt.IO
/**
* Full-duplex MII media adapter: 50 MHz MAC context and independent PHY-derived
* RX/TX contexts (25 MHz at 100 Mb/s, 2.5 MHz at 10 Mb/s). Both rates use identical
* nibble logic. Owns two block-memory FIFOs. TX buffers one complete wire frame
* before commit; completion means TX_EN has fallen, not merely FIFO admission.
* All three resets must assert together, asynchronously, and release locally.
* Board constraints must cover FIFO Gray buses and mailbox synchronizers.
* Committed discard metadata remains immutable until acknowledgement; a late
* abort changes only the MAC-domain completion result.
*/
@Context(ClockFrequency = 50MHz, ResetStyle = ResetStyle.Asynchronous)
component MiiAdapter : IEthernetMedia
{
// FIFO token flag marking the final TX byte or RX terminator.
const FRAME_END: logic[11] = 0x200
// FIFO token flag marking the first RX byte.
const FRAME_START: logic[11] = 0x100
// FIFO token flag marking a malformed RX frame.
const FRAME_ERROR: logic[11] = 0x400
// Reserve one of 2048 FIFO entries when committing or aborting a frame.
const LAST_BUFFER_INDEX: logic[11] = 2046
// Borrowed PHY clock contexts; both resets assert with the MAC reset.
@Context(ResetStyle = ResetStyle.Asynchronous)
receiveDomain: IContext
// Borrowed PHY clock contexts; both resets assert with the MAC reset.
@Context(ResetStyle = ResetStyle.Asynchronous)
transmitDomain: IContext
// Borrowed physical pins and coherent link status.
pins: IMiiPins
link: IEthernetLinkStatus
// Owned receive/serialize engines and block-memory clock bridges.
receive: MiiReceiver
transmit: MiiTransmitter
completion: MiiCompletionReceiver
rxQueue: MiiClockBridge<2048>
txQueue: MiiClockBridge<2048>
// Complete-frame mailbox and producer occupancy.
commit: bool
discard: bool
busy: bool
count: logic[11]
// MAC-domain failure after commit; never sampled by the PHY domain.
lateAbort: bool
// Four application cycles preserve the existing MAC synchronous-RAM byte cadence.
byteSlot: logic[2]
// Coherent completion mailbox and one-cycle MAC terminal events.
terminal: bool
terminalFault: bool
// Combinational MAC input aliases and FIFO admission signals.
inputData: byte
inputValid: bool
inputFirst: bool
inputLast: bool
inputAbort: bool
accept: bool
abortFrame: bool
enabled: bool
push: bool
token: logic[11]
/**
* Borrows pins, link status, and media clocks; keeps MAC work in this context.
*/
new(macContext: IContext, receiveContext: IContext, transmitContext: IContext,
pins: IMiiPins, link: IEthernetLinkStatus)
{
context = macContext
receiveDomain = receiveContext
transmitDomain = transmitContext
this.pins = pins
this.link = link
rxQueue = new MiiClockBridge<2048>(receiveDomain, context, receive.valid, receive.data, true)
txQueue = new MiiClockBridge<2048>(context, transmitDomain, push, token, transmit.ready)
receive = new MiiReceiver(receiveDomain, pins.rxData, pins.rxValid, pins.rxError, rxQueue.writeReady)
transmit = new MiiTransmitter(transmitDomain, commit, discard,
txQueue.readValid, txQueue.readData)
completion = new MiiCompletionReceiver(context, transmit)
}
/**
* Wires FIFO transfers and exposes one-cycle terminal events in the MAC domain.
*/
process Ports[]()
{
pins.txData = transmit.txData
pins.txEnable = transmit.txEnable
inputData = txData
inputValid = txValid
inputFirst = txFirst
inputLast = txLast
inputAbort = txAbort
enabled = link.ready && (link.speed == EthernetSpeed.Mbps100
|| link.speed == EthernetSpeed.Mbps10)
txReady = enabled && !busy && !inputAbort && txQueue.writeReady && byteSlot == 0
accept = enabled && !busy && !inputAbort && txQueue.writeReady && byteSlot == 0 && inputValid
abortFrame = !busy && count != 0 && (inputAbort || !enabled)
push = accept || (abortFrame && txQueue.writeReady)
var nextToken = inputData as logic[11]
if (inputLast || abortFrame || count == LAST_BUFFER_INDEX) {
nextToken = nextToken | FRAME_END
}
token = nextToken
txDone = terminal && !terminalFault
txFault = terminal && terminalFault
rxData = rxQueue.readData as byte
rxValid = enabled && rxQueue.readValid && (rxQueue.readData & FRAME_END) == 0
rxStart = enabled && rxQueue.readValid && (rxQueue.readData & FRAME_START) != 0
rxEnd = rxQueue.readValid && (rxQueue.readData & FRAME_END) != 0
rxError = rxQueue.readValid && ((rxQueue.readData & FRAME_ERROR) != 0 || !enabled)
}
/**
* Commits complete frames and retains metadata until the remote acknowledgement.
*/
process Frames()
{
state {
byteSlot++
terminal = false
if (busy) {
// Keep discard frozen while the PHY consumes the committed frame.
if (!enabled || inputAbort) {
lateAbort = true
}
if (completion.acknowledged == commit) {
busy = false
count = 0
terminal = true
terminalFault = completion.fault || discard || lateAbort
discard = false
lateAbort = false
}
} elif (abortFrame && txQueue.writeReady) {
discard = true
commit = !commit
busy = true
} elif (accept) {
if ((count == 0 && !inputFirst) || (count != 0 && inputFirst)) {
discard = true
}
if (inputLast || count == LAST_BUFFER_INDEX) {
discard = discard || !inputLast
commit = !commit
busy = true
}
count++
}
}
}
}