Source code for hwtLib.peripheral.mdio.intf

from hwt.synthesizer.interface import Interface
from hwt.interfaces.std import Clk
from hwt.interfaces.tristate import TristateSig
from pyMathBitPrecise.bit_utils import mask, get_bit
from hwt.synthesizer.param import Param
from hwt.simulator.agentBase import SyncAgentBase
from hwtSimApi.hdlSimulator import HdlSimulator
from hwtSimApi.process_utils import OnRisingCallbackLoop, OnFallingCallbackLoop
from collections import deque
from typing import Deque, Tuple
from hwtSimApi.triggers import WaitWriteOnly, WaitCombStable, \
    Edge, Timer
from hwtSimApi.constants import Time
from hwtSimApi.simCalendar import DONE
from ipCorePackager.intfIpMeta import IntfIpMeta
from hwt.hdl.types.bits import Bits


[docs]class Mdio(Interface): """ Management Data Input/Output (MDIO), also known as Serial Management Interface (SMI) or Media Independent Interface Management (MIIM), is a serial bus defined for the Ethernet family of IEEE 802.3 standards for the Media Independent Interface, :note: Typical clock frequency is 2.5 MHz * MDIO packet format: <PRE><ST><OP><PA><RA><TA><D> * PRE: 32b preamble * ST: 2b start field * OP: 2b operation code * PA: 5b PHY address * RA: 5b register address * TA: 2b turn arround * D 16b data :note: When data is being written to the slave, the master writes '10' to the MDIO line. When data is being read, the master releases the MDIO line and slave sets the second bit to 1. .. hwt-autodoc:: """ # http://ww1.microchip.com/downloads/en/devicedoc/00002165b.pdf PRE_W = 32 ST_W = 2 OP_W = 2 PA_W = 5 RA_W = 5 TA_W = 2 ADDR_BLOCK_W = ST_W + OP_W + PA_W + RA_W D_W = 16 PRE = Bits(PRE_W).from_py(mask(PRE_W)) ST = Bits(ST_W).from_py(0b01) TA = Bits(TA_W).from_py(0b10)
[docs] class OP: READ = 0b10 WRITE = 0b01
DEFAULT_FREQ = int(2.5e6) def _config(self): self.FREQ = Param(self.DEFAULT_FREQ) def _declr(self): self.c = Clk() self.c.FREQ = self.FREQ with self._associated(clk=self.c): self.io = TristateSig()
[docs] def _initSimAgent(self, sim: HdlSimulator): self._ag = MdioAgent(sim, self)
[docs] def _getIpCoreIntfClass(self): return IP_mdio
[docs]def pop_int(bits: Deque[int], bit_cnt: int): res = 0 for _ in range(bit_cnt): b = bits.popleft() res <<= 1 res |= b return res
[docs]class MdioAgent(SyncAgentBase): PULL = 1
[docs] def __init__(self, sim: HdlSimulator, intf, allowNoReset=False): super(MdioAgent, self).__init__(sim, intf, allowNoReset=allowNoReset) self.intf.io._initSimAgent(sim) self.rx_bits_tmp = deque() self.tx_bits_tmp = deque() self.reset_state() self.data = {}
[docs] def reset_state(self): self.preamble_detected = False self.start_detected = False self.turn_arround_check = False self.rx_w_data = False # (opcode, phyaddr, regaddr) self.acutal_req = (None, None, None)
[docs] def on_read(self, phyaddr, regaddr): data = self.data[(phyaddr, regaddr)] D_W = self.intf.D_W tx_bits = self.tx_bits_tmp # turn arround (1 is actually Z but due to open-drain...) tx_bits.append(1) tx_bits.append(0) for i in range(D_W): # MSB first tx_bits.append(get_bit(data, D_W - i - 1))
# print(tx_bits)
[docs] def on_write(self, phyaddr, regaddr, data): self.data[(phyaddr, regaddr)] = data
[docs] def tx_bits(self): """ Transmit bit to io tristate signal on falling edge of c clock """ if self.sim._current_time_slot.write_only is DONE: yield Timer(1) yield WaitWriteOnly() tx_bits = self.tx_bits_tmp if tx_bits: b = tx_bits.popleft() self.intf.io.i.write(b) if not tx_bits: yield Edge(self.intf.c) self.reset_state() # release the io bus if self.sim._current_time_slot.write_only is DONE: yield Timer(1) yield self.intf.io._ag.monitor()
[docs] def unpack_addr(self, rx_bits) -> Tuple[int, int, int]: # <OP><PA><RA> mdio = self.intf op = pop_int(rx_bits, mdio.OP_W) pa = pop_int(rx_bits, mdio.PA_W) ra = pop_int(rx_bits, mdio.RA_W) return int(op), int(pa), int(ra)
[docs] def rx_bits(self): """ Recieve bit from io tristate signal on rising edge of c clock """ yield WaitCombStable() rx_bits = self.rx_bits_tmp mdio = self.intf b = mdio.io._ag._read() b = int(b) # print(self.sim.now/ Time.ns, b) if not self.preamble_detected: rx_bits.append(b) if len(rx_bits) == Mdio.PRE_W: self.preamble_detected = True rx_bits.clear() # print(self.sim.now / Time.ns, "preamble_detected") elif not self.start_detected: if not rx_bits: if not b: rx_bits.append(b) # else skip an extra 1 from potentiall idle or preamble else: # because start condition is 0b01 assert b == 1, (self.sim.now / Time.ns, b) rx_bits.clear() self.start_detected = True # print(self.sim.now / Time.ns, "start_detected") elif self.turn_arround_check: rx_bits.append(b) if len(rx_bits) == mdio.TA_W: if self.acutal_req[0] != mdio.OP.READ: assert rx_bits[0] == 1, rx_bits assert rx_bits[1] == 0, rx_bits else: self.rx_w_data = True rx_bits.clear() self.turn_arround_check = False # print(self.sim.now / Time.ns, "turn_arround_check_passed") elif self.rx_w_data: rx_bits.append(b) if len(rx_bits) >= mdio.D_W: data = pop_int(rx_bits, mdio.D_W) self.on_write(self.acutal_req[1], self.acutal_req[2], data) self.reset_state() # print(self.sim.now / Time.ns, "write_data_recieved") assert not rx_bits elif self.tx_bits_tmp: # responding with read data pass else: # <OP><PA><RA> rx_bits.append(b) if len(rx_bits) >= mdio.OP_W + mdio.PA_W + mdio.RA_W: opcode, phyaddr, regaddr = self.unpack_addr(rx_bits) self.acutal_req = (opcode, phyaddr, regaddr) if opcode == mdio.OP.READ: # print(self.sim.now / Time.ns, ("READ", phyaddr, regaddr)) self.on_read(phyaddr, regaddr) elif opcode == mdio.OP.WRITE: self.rx_w_data = True self.turn_arround_check = True # print(self.sim.now / Time.ns, ("WRITE", phyaddr, regaddr)) else: raise ValueError(opcode) rx_bits.clear()
[docs] def getMonitors(self): self.rx_bits = OnRisingCallbackLoop( self.sim, self.intf.c, self.rx_bits, lambda: True) self.tx_bits = OnFallingCallbackLoop( self.sim, self.intf.c, self.tx_bits, lambda: True) yield from self.intf.io._ag.getMonitors() yield self.rx_bits() yield self.tx_bits()
[docs]class IP_mdio(IntfIpMeta):
[docs] def __init__(self): super().__init__() self.name = "mdio" self.version = "1.0" self.vendor = "xilinx.com" self.library = "interface" self.map = {"c": "MDC", "io": {"t": "MDIO_T", "i": "MDIO_I", "o": "MDIO_O"} }