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/MdioController.lvt
namespace Livt.IO
/** Clause 22 controller. MDC is a clock-enabled output, never an internal clock. */
component MdioController : IMdioController
{
pins: IMdioPins
HALF_TICKS: uint
request: bool
completed: bool
readRequest: bool
frame: logic[32]
readValue: logic[16]
result: EthernetResult
new(pins: IMdioPins)
{
HALF_TICKS = this.context.TicksFor(500ns)
this.pins = pins
}
// One command owner avoids cross-method writes to the request mailbox.
fn Execute(commandFrame: logic[32], reading: bool) EthernetResult
{
state { frame = commandFrame; readRequest = reading; request = !request }
while (request != completed) { state {} }
return result
}
override fn Read(phy: byte, register: byte, value: out logic[16]) EthernetResult
{
value = 0
if (phy > 31 || register > 31) { return EthernetResult.Invalid }
var commandFrame = 0x60000000 | (((phy as uint) << 23) as logic[32])
| (((register as uint) << 18) as logic[32])
var answer = Execute(commandFrame, true)
if (answer == EthernetResult.Success) { value = readValue }
return answer
}
override fn Write(phy: byte, register: byte, value: logic[16]) EthernetResult
{
if (phy > 31 || register > 31) { return EthernetResult.Invalid }
var commandFrame = 0x50020000 | (((phy as uint) << 23) as logic[32])
| (((register as uint) << 18) as logic[32]) | ((value as uint) as logic[32])
return Execute(commandFrame, false)
}
process Transfer()
{
var bitIndex: int = 0
var ticks: uint = 0
var captured: logic[16] = 0
var failed = false
state Idle {
pins.mdc = 0
pins.mdioOutputEnable = false
pins.mdioOutput = 0
if (request != completed) {
bitIndex = 0
captured = 0
failed = false
goto Drive
} else { goto Idle }
}
state Drive {
pins.mdc = 0
pins.mdioOutputEnable = !(readRequest && bitIndex >= 46)
pins.mdioOutput = 1
if (bitIndex >= 32 && !(readRequest && bitIndex >= 46)) {
var shifted = frame >> (63 - bitIndex)
pins.mdioOutput = shifted as logic
}
ticks = 0
goto Low
}
state Low {
if (ticks + 1 < HALF_TICKS) {
ticks++
goto Low
} else {
// Sample before raising MDC. The PHY advances its next bit after
// this edge; the current bit has settled since the previous rise.
if (readRequest && bitIndex == 47 && pins.mdioInput != 0b0) {
failed = true
}
if (readRequest && bitIndex >= 48) {
captured = (captured << 1) | ((pins.mdioInput as uint) as logic[16])
}
pins.mdc = 1
ticks = 0
goto High
}
}
state High {
if (ticks + 1 < HALF_TICKS) {
ticks++
goto High
} else {
pins.mdc = 0
if (bitIndex == 63) {
pins.mdioOutputEnable = false
readValue = captured
result = EthernetResult.Success
if (failed) {
readValue = 0
result = EthernetResult.DeviceFailure
}
completed = request
goto Idle
} else {
bitIndex++
goto Drive
}
}
}
}
}