GitHub repository: https://github.com/alexforencich/cocotbext-eth
Ethernet interface models for cocotb.
Includes PHY-attach interface models for MII, GMII, RGMII, and XGMII; PHY chip interface models for MII, GMII, and RGMII; PTP clock simulation models; and a generic Ethernet MAC model that supports rate enforcement and PTP timestamping.
Installation from pip (release version, stable):
$ pip install cocotbext-eth
Installation from git (latest development version, potentially unstable):
$ pip install https://github.com/alexforencich/cocotbext-eth/archive/master.zip
Installation for active development:
$ git clone https://github.com/alexforencich/cocotbext-eth
$ pip install -e cocotbext-eth
See the tests
directory, verilog-ethernet, and corundum for complete testbenches using these modules.
The GmiiSource
and GmiiSink
classes can be used to drive, receive, and monitor GMII traffic. The GmiiSource
drives GMII traffic into a design. The GmiiSink
receives GMII traffic, including monitoring internal interfaces. The GmiiPhy
class is a wrapper around GmiiSource
and GmiiSink
that also provides clocking and rate-switching to emulate a GMII PHY chip.
To use these modules, import the one you need and connect it to the DUT:
from cocotbext.eth import GmiiSource, GmiiSink
gmii_source = GmiiSource(dut.rxd, dut.rx_er, dut.rx_en, dut.clk, dut.rst)
gmii_sink = GmiiSink(dut.txd, dut.tx_er, dut.tx_en, dut.clk, dut.rst)
To send data into a design with a GmiiSource
, call send()
or send_nowait()
. Accepted data types are iterables that can be converted to bytearray or GmiiFrame
objects. Optionally, call wait()
to wait for the transmit operation to complete. Example:
await gmii_source.send(GmiiFrame.from_payload(b'test data'))
# wait for operation to complete (optional)
await gmii_source.wait()
It is also possible to wait for the transmission of a specific frame to complete by passing an event in the tx_complete field of the GmiiFrame
object, and then awaiting the event. The frame, with simulation time fields set, will be returned in the event data. Example:
frame = GmiiFrame.from_payload(b'test data', tx_complete=Event())
await gmii_source.send(frame)
await frame.tx_complete.wait()
print(frame.tx_complete.data.sim_time_sfd)
To receive data with a GmiiSink
, call recv()
or recv_nowait()
. Optionally call wait()
to wait for new receive data.
data = await gmii_sink.recv()
The GmiiPhy
class provides a model of a GMII PHY chip. It wraps instances of GmiiSource
(rx
) and GmiiSink
(tx
), provides the necessary clocking components, and provides the set_speed()
method to change the link speed. set_speed()
changes the tx_clk
and rx_clk
frequencies, switches between gtx_clk
and tx_clk
, and selects the appropriate mode (MII or GMII) on the source and sink instances. In general, the GmiiPhy
class is intended to be used for integration tests where the design expects to be directly connected to an external GMII PHY chip and contains all of the necessary IO and clocking logic. Example:
from cocotbext.eth import GmiiFrame, GmiiPhy
gmii_phy = GmiiPhy(dut.txd, dut.tx_er, dut.tx_en, dut.tx_clk, dut.gtx_clk,
dut.rxd, dut.rx_er, dut.rx_en, dut.rx_clk, dut.rst, speed=1000e6)
gmii_phy.set_speed(100e6)
await gmii_phy.rx.send(GmiiFrame.from_payload(b'test RX data'))
tx_data = await gmii_phy.tx.recv()
txd
, rxd
: datatx_er
, rx_er
: error (when asserted with tx_en
or rx_dv
)tx_en
, rx_dv
: data validTrue
)send(frame)
: send frame (blocking) (source)send_nowait(frame)
: send frame (non-blocking) (source)recv()
: receive a frame as a GmiiFrame
(blocking) (sink)recv_nowait()
: receive a frame as a GmiiFrame
(non-blocking) (sink)count()
: returns the number of items in the queue (all)empty()
: returns True if the queue is empty (all)full()
: returns True if the queue occupancy limits are met (source)idle()
: returns True if no transfer is in progress (all) or if the queue is not empty (source)clear()
: drop all data in queue (all)wait()
: wait for idle (source)wait(timeout=0, timeout_unit='ns')
: wait for frame received (sink)Example transfer via GMII at 1 Gbps:
__ __ __ __ _ __ __ __ __
tx_clk __/ \__/ \__/ \__/ \__/ ... _/ \__/ \__/ \__/ \__
_____ _____ _____ _ _ _____ _____
tx_d[7:0] XXXXXXXXX_55__X_55__X_55__X_ ... _X_72__X_fb__XXXXXXXXXXXX
tx_er ____________________________ ... _________________________
___________________ _____________
tx_en ________/ ... \___________
The GmiiFrame
object is a container for a frame to be transferred via GMII. The data
field contains the packet data in the form of a list of bytes. error
contains the er
signal level state associated with each byte as a list of ints.
Attributes:
data
: bytearrayerror
: error field, optional; list, each entry qualifies the corresponding entry in data
.sim_time_start
: simulation time of first transfer cycle of frame.sim_time_sfd
: simulation time at which the SFD was transferred.sim_time_end
: simulation time of last transfer cycle of frame.start_lane
: byte lane in which the start control character was transferred.tx_complete
: event or callable triggered when frame is transmitted.Methods:
from_payload(payload, min_len=60)
: create GmiiFrame
from payload data, inserts preamble, zero-pads frame to minimum length and computes and inserts FCS (class method)from_raw_payload(payload)
: create GmiiFrame
from payload data, inserts preamble only (class method)get_preamble_len()
: locate SFD and return preamble lengthget_preamble()
: return preambleget_payload(strip_fcs=True)
: return payload, optionally strip FCSget_fcs()
: return FCScheck_fcs()
: returns True if FCS is correctnormalize()
: pack error
to the same length as data
, replicating last element if necessary, initialize to list of 0
if not specified.compact()
: remove error
if all zeroThe MiiSource
and MiiSink
classes can be used to drive, receive, and monitor MII traffic. The MiiSource
drives MII traffic into a design. The MiiSink
receives MII traffic, including monitoring internal interfaces. The MiiPhy
class is a wrapper around MiiSource
and MiiSink
that also provides clocking and rate-switching to emulate an MII PHY chip.
To use these modules, import the one you need and connect it to the DUT:
from cocotbext.eth import MiiSource, MiiSink
mii_source = MiiSource(dut.rxd, dut.rx_er, dut.rx_en, dut.clk, dut.rst)
mii_sink = MiiSink(dut.txd, dut.tx_er, dut.tx_en, dut.clk, dut.rst)
All signals must be passed separately into these classes.
To send data into a design with an MiiSource
, call send()
or send_nowait()
. Accepted data types are iterables that can be converted to bytearray or GmiiFrame
objects. Optionally, call wait()
to wait for the transmit operation to complete. Example:
await mii_source.send(GmiiFrame.from_payload(b'test data'))
# wait for operation to complete (optional)
await mii_source.wait()
It is also possible to wait for the transmission of a specific frame to complete by passing an event in the tx_complete field of the GmiiFrame
object, and then awaiting the event. The frame, with simulation time fields set, will be returned in the event data. Example:
frame = GmiiFrame.from_payload(b'test data', tx_complete=Event())
await mii_source.send(frame)
await frame.tx_complete.wait()
print(frame.tx_complete.data.sim_time_sfd)
To receive data with an MiiSink
, call recv()
or recv_nowait()
. Optionally call wait()
to wait for new receive data.
data = await mii_sink.recv()
The MiiPhy
class provides a model of an MII PHY chip. It wraps instances of MiiSource
(rx
) and MiiSink
(tx
), provides the necessary clocking components, and provides the set_speed()
method to change the link speed. set_speed()
changes the tx_clk
and rx_clk
frequencies. In general, the MiiPhy
class is intended to be used for integration tests where the design expects to be directly connected to an external MII PHY chip and contains all of the necessary IO and clocking logic. Example:
from cocotbext.eth import GmiiFrame, MiiPhy
mii_phy = MiiPhy(dut.txd, dut.tx_er, dut.tx_en, dut.tx_clk,
dut.rxd, dut.rx_er, dut.rx_en, dut.rx_clk, dut.rst, speed=100e6)
mii_phy.set_speed(10e6)
await mii_phy.rx.send(GmiiFrame.from_payload(b'test RX data'))
tx_data = await mii_phy.tx.recv()
txd
, rxd
: datatx_er
, rx_er
: error (when asserted with tx_en
or rx_dv
)tx_en
, rx_dv
: data validTrue
)send(frame)
: send frame (blocking) (source)send_nowait(frame)
: send frame (non-blocking) (source)recv()
: receive a frame as a GmiiFrame
(blocking) (sink)recv_nowait()
: receive a frame as a GmiiFrame
(non-blocking) (sink)count()
: returns the number of items in the queue (all)empty()
: returns True if the queue is empty (all)full()
: returns True if the queue occupancy limits are met (source)idle()
: returns True if no transfer is in progress (all) or if the queue is not empty (source)clear()
: drop all data in queue (all)wait()
: wait for idle (source)wait(timeout=0, timeout_unit='ns')
: wait for frame received (sink)Example transfer via MII at 100 Mbps:
_ _ _ _ _ _ _ _ _ _
tx_clk _/ \_/ \_/ \_/ \_/ \_/ ... _/ \_/ \_/ \_/ \_
___ ___ ___ ___ _ _ ___ ___
tx_d[3:0] XXXXXX_5_X_5_X_5_X_5_X_ ... _X_f_X_b_XXXXXXXX
tx_er _______________________ ... _________________
_________________ _________
tx_en _____/ ... \_______
The RgmiiSource
and RgmiiSink
classes can be used to drive, receive, and monitor RGMII traffic. The RgmiiSource
drives RGMII traffic into a design. The RgmiiSink
receives RGMII traffic, including monitoring internal interfaces. The RgmiiPhy
class is a wrapper around RgmiiSource
and RgmiiSink
that also provides clocking and rate-switching to emulate an RGMII PHY chip.
To use these modules, import the one you need and connect it to the DUT:
from cocotbext.eth import RgmiiSource, RgmiiSink
rgmii_source = RgmiiSource(dut.rxd, dut.rx_ctl, dut.clk, dut.rst)
rgmii_sink = RgmiiSink(dut.txd, dut.tx_ctl, dut.clk, dut.rst)
All signals must be passed separately into these classes.
To send data into a design with an RgmiiSource
, call send()
or send_nowait()
. Accepted data types are iterables that can be converted to bytearray or GmiiFrame
objects. Optionally, call wait()
to wait for the transmit operation to complete. Example:
await rgmii_source.send(GmiiFrame.from_payload(b'test data'))
# wait for operation to complete (optional)
await rgmii_source.wait()
It is also possible to wait for the transmission of a specific frame to complete by passing an event in the tx_complete field of the GmiiFrame
object, and then awaiting the event. The frame, with simulation time fields set, will be returned in the event data. Example:
frame = GmiiFrame.from_payload(b'test data', tx_complete=Event())
await rgmii_source.send(frame)
await frame.tx_complete.wait()
print(frame.tx_complete.data.sim_time_sfd)
To receive data with an RgmiiSink
, call recv()
or recv_nowait()
. Optionally call wait()
to wait for new receive data.
data = await rgmii_sink.recv()
The RgmiiPhy
class provides a model of an RGMII PHY chip. It wraps instances of RgmiiSource
(rx
) and RgmiiSink
(tx
), provides the necessary clocking components, and provides the set_speed()
method to change the link speed. set_speed()
changes the rx_clk
frequency and selects the appropriate mode (SDR or DDR) on the source and sink instances. In general, the RgmiiPhy
class is intended to be used for integration tests where the design expects to be directly connected to an external RGMII PHY chip and contains all of the necessary IO and clocking logic. Example:
from cocotbext.eth import GmiiFrame, RgmiiPhy
rgmii_phy = RgmiiPhy(dut.txd, dut.tx_ctl, dut.tx_clk,
dut.rxd, dut.rx_ctl, dut.rx_clk, dut.rst, speed=1000e6)
rgmii_phy.set_speed(100e6)
await rgmii_phy.rx.send(GmiiFrame.from_payload(b'test RX data'))
tx_data = await rgmii_phy.tx.recv()
txd
, rxd
: data (DDR)tx_ctl
, rx_ctl
: control (DDR, combination of valid and error)True
)send(frame)
: send frame (blocking) (source)send_nowait(frame)
: send frame (non-blocking) (source)recv()
: receive a frame as a GmiiFrame
(blocking) (sink)recv_nowait()
: receive a frame as a GmiiFrame
(non-blocking) (sink)count()
: returns the number of items in the queue (all)empty()
: returns True if the queue is empty (all)full()
: returns True if the queue occupancy limits are met (source)idle()
: returns True if no transfer is in progress (all) or if the queue is not empty (source)clear()
: drop all data in queue (all)wait()
: wait for idle (source)wait(timeout=0, timeout_unit='ns')
: wait for frame received (sink)Example transfer via RGMII at 1 Gbps:
___ ___ ___ _ ___ ___
tx_clk _/ \___/ \___/ \___/ ... _/ \___/ \___
___ ___ ___ ___ ___ ___ ___
tx_d[3:0] XXXXXXXX_5_X_5_X_5_X_5_X_5_ ... _f_X_b_XXXXXXXXXX
___________________ _______
tx_ctl _______/ ... \_________
The XgmiiSource
and XgmiiSink
classes can be used to drive, receive, and monitor XGMII traffic. The XgmiiSource
drives XGMII traffic into a design. The XgmiiSink
receives XGMII traffic, including monitoring internal interfaces. The modules are capable of operating with XGMII interface widths of 32 or 64 bits.
To use these modules, import the one you need and connect it to the DUT:
from cocotbext.eth import XgmiiSource, XgmiiSink
xgmii_source = XgmiiSource(dut.rxd, dut.rxc, dut.clk, dut.rst)
xgmii_sink = XgmiiSink(dut.txd, dut.txc, dut.clk, dut.rst)
All signals must be passed separately into these classes.
To send data into a design with an XgmiiSource
, call send()
or send_nowait()
. Accepted data types are iterables that can be converted to bytearray or XgmiiFrame
objects. Optionally, call wait()
to wait for the transmit operation to complete. Example:
await xgmii_source.send(XgmiiFrame.from_payload(b'test data'))
# wait for operation to complete (optional)
await xgmii_source.wait()
It is also possible to wait for the transmission of a specific frame to complete by passing an event in the tx_complete field of the XgmiiFrame
object, and then awaiting the event. The frame, with simulation time fields set, will be returned in the event data. Example:
frame = XgmiiFrame.from_payload(b'test data', tx_complete=Event())
await xgmii_source.send(frame)
await frame.tx_complete.wait()
print(frame.tx_complete.data.sim_time_sfd)
To receive data with an XgmiiSink
, call recv()
or recv_nowait()
. Optionally call wait()
to wait for new receive data.
data = await xgmii_sink.recv()
txd
, rxd
: datatxc
, rxc
: controlTrue
)send(frame)
: send frame (blocking) (source)send_nowait(frame)
: send frame (non-blocking) (source)recv()
: receive a frame as an XgmiiFrame
(blocking) (sink)recv_nowait()
: receive a frame as an XgmiiFrame
(non-blocking) (sink)count()
: returns the number of items in the queue (all)empty()
: returns True if the queue is empty (all)full()
: returns True if the queue occupancy limits are met (source)idle()
: returns True if no transfer is in progress (all) or if the queue is not empty (source)clear()
: drop all data in queue (all)wait()
: wait for idle (source)wait(timeout=0, timeout_unit='ns')
: wait for frame received (sink)Example transfer via 64-bit XGMII:
__ __ __ __ __ _ __ __
tx_clk __/ \__/ \__/ \__/ \__/ \__/ ... _/ \__/ \__
__ _____ _____ _____ _____ _____ _ _ _____ _____
txd[63:56] __X_07__X_d5__X_51__X_01__X_09__X_ ... _X_fb__X_07__
__ _____ _____ _____ _____ _____ _ _ _____ _____
txd[55:48] __X_07__X_55__X_5a__X_00__X_08__X_ ... _X_72__X_07__
__ _____ _____ _____ _____ _____ _ _ _____ _____
txd[47:40] __X_07__X_55__X_d5__X_00__X_07__X_ ... _X_0d__X_07__
__ _____ _____ _____ _____ _____ _ _ _____ _____
txd[39:32] __X_07__X_55__X_d4__X_80__X_06__X_ ... _X_37__X_07__
__ _____ _____ _____ _____ _____ _ _ _____ _____
txd[31:24] __X_07__X_55__X_d3__X_55__X_05__X_ ... _X_2d__X_07__
__ _____ _____ _____ _____ _____ _ _ _____ _____
txd[23:16] __X_07__X_55__X_d2__X_54__X_04__X_ ... _X_2c__X_07__
__ _____ _____ _____ _____ _____ _ _ _____ _____
txd[15:8] __X_07__X_55__X_d1__X_53__X_03__X_ ... _X_2b__X_07__
__ _____ _____ _____ _____ _____ _ _ _____ _____
txd[7:0] __X_07__X_fb__X_da__X_52__X_02__X_ ... _X_2a__X_fd__
__ _____ _____ _____ _____ _____ _ _ _____ _____
txc[7:0] __X_ff__X_01__X_00__X_00__X_00__X_ ... _X_00__X_ff__
The XgmiiFrame
object is a container for a frame to be transferred via XGMII. The data
field contains the packet data in the form of a list of bytes. ctrl
contains the control signal level state associated with each byte as a list of ints. When ctrl
is high, the corresponding data
byte is interpreted as an XGMII control character.
Attributes:
data
: bytearrayctrl
: control field, optional; list, each entry qualifies the corresponding entry in data
as an XGMII control character.sim_time_start
: simulation time of first transfer cycle of frame.sim_time_sfd
: simulation time at which the SFD was transferred.sim_time_end
: simulation time of last transfer cycle of frame.start_lane
: byte lane in which the start control character was transferred.tx_complete
: event or callable triggered when frame is transmitted.Methods:
from_payload(payload, min_len=60)
: create XgmiiFrame
from payload data, inserts preamble, zero-pads frame to minimum length and computes and inserts FCS (class method)from_raw_payload(payload)
: create XgmiiFrame
from payload data, inserts preamble only (class method)get_preamble_len()
: locate SFD and return preamble lengthget_preamble()
: return preambleget_payload(strip_fcs=True)
: return payload, optionally strip FCSget_fcs()
: return FCScheck_fcs()
: returns True if FCS is correctnormalize()
: pack ctrl
to the same length as data
, replicating last element if necessary, initialize to list of 0
if not specified.compact()
: remove ctrl
if all zeroThe EthMac
, EthMacTx
and EthMacRx
modules are models of an Ethernet MAC with an AXI stream interface. The EthMacRx
module drives Ethernet frames in the form of AXI stream traffic into a design. The EthMacTx
module accepts Ethernet frames in the form of AXI stream traffic from a design. EthMac
is a wrapper module containing EthMacRx
(rx
) and EthMacTx
(tx
). The modules are capable of operating with any interface width. The MAC models enforce the correct data rates and timings in both the receive and transmit direction, and can also collect PTP timestamps from a PTP hardware clock.
To use these modules, import the one you need and connect it to the DUT:
from cocotbext.axi import AxiStreamBus
from cocotbext.eth import EthMac
mac = EthMac(
tx_clk=dut.tx_clk,
tx_rst=dut.tx_rst,
tx_bus=AxiStreamBus.from_prefix(dut, "tx_axis"),
tx_ptp_time=dut.tx_ptp_time,
tx_ptp_ts=dut.tx_ptp_ts,
tx_ptp_ts_tag=dut.tx_ptp_ts_tag,
tx_ptp_ts_valid=dut.tx_ptp_ts_valid,
rx_clk=dut.rx_clk,
rx_rst=dut.rx_rst,
rx_bus=AxiStreamBus.from_prefix(dut, "rx_axis"),
rx_ptp_time=dut.rx_ptp_time,
ifg=12, speed=speed
)
To send data into a design, call send()
or send_nowait()
. Accepted data types are iterables that can be converted to bytearray or EthMacFrame
objects. Optionally, call wait()
to wait for the transmit operation to complete. Example:
await mac.tx.send(EthMacFrame.from_payload(b'test data'))
# wait for operation to complete (optional)
await mac.tx.wait()
It is also possible to wait for the transmission of a specific frame to complete by passing an event in the tx_complete field of the EthMacFrame
object, and then awaiting the event. The frame, with simulation time fields set, will be returned in the event data. Example:
frame = EthMacFrame.from_payload(b'test data', tx_complete=Event())
await mac.tx.send(frame)
await frame.tx_complete.wait()
print(frame.tx_complete.data.sim_time_sfd)
To receive data, call recv()
or recv_nowait()
. Optionally call wait()
to wait for new receive data.
data = await mac.tx.recv()
PTP timestamping requires free-running PTP clocks driving the PTP time inputs, synchronous with the corresponding MAC clocks. The values of these fields are then captured when the frame SFD is transferred and returned either on tuser (for received frames) or on a separate streaming interface (for transmitted frames). Additionally, on the transmit path, a tag value from tuser is returned along with the timestamp.
tdata
: payload data, must be a multiple of 8 bitstvalid
: qualifies all other signalstready
: indicates sink is ready for data (tx only)tlast
: marks the last cycle of a frametkeep
: qualifies data byte, data bus width must be evenly divisible by tkeep
signal widthtuser
: user data, carries frame error mark and captured receive PTP timestamp (RX) or PTP timestamp tag (TX)ptp_time
: PTP time input from PHC, captured into ptp_timestamp
field coincident with transfer of frame SFD and output on ptp_ts
(TX) or tuser
(RX)ptp_ts
: captured transmit PTP timestampptp_ts_tag
: captured transmit PTP timestamp tagptp_ts_valid
: qualifies captured transmit PTP timestampEthMacRx
and EthMacTx
):AxiStreamBus
object containing AXI stream interface signalsTrue
)12
)1000e6
)EthMac
):AxiStreamBus
object containing transmit AXI stream interface signalsAxiStreamBus
object containing receive AXI stream interface signalsTrue
)12
)1000e6
)send(frame)
: send frame (blocking) (rx)send_nowait(frame)
: send frame (non-blocking) (rx)recv()
: receive a frame as an EthMacFrame
(blocking) (tx)recv_nowait()
: receive a frame as an EthMacFrame
(non-blocking) (tx)count()
: returns the number of items in the queue (all)empty()
: returns True if the queue is empty (all)full()
: returns True if the queue occupancy limits are met (rx)idle()
: returns True if no transfer is in progress (all) or if the queue is not empty (rx)clear()
: drop all data in queue (all)wait()
: wait for idle (rx)wait(timeout=0, timeout_unit='ns')
: wait for frame received (tx)The EthMacFrame
object is a container for a frame to be transferred via XGMII. The data
field contains the packet data in the form of a list of bytes.
Attributes:
data
: bytearraysim_time_start
: simulation time of first transfer cycle of frame.sim_time_sfd
: simulation time at which the SFD was transferred.sim_time_end
: simulation time of last transfer cycle of frame.ptp_tag
: PTP timestamp tag for transmitted frames.ptp_timestamp
: captured value of ptp_time
at frame SFDtx_complete
: event or callable triggered when frame is transmitted.Methods:
from_payload(payload, min_len=60)
: create EthMacFrame
from payload data, zero-pads frame to minimum length and computes and inserts FCS (class method)from_raw_payload(payload)
: create EthMacFrame
from payload data (class method)get_payload(strip_fcs=True)
: return payload, optionally strip FCSget_fcs()
: return FCScheck_fcs()
: returns True if FCS is correctThe PtpClock
class implements a PTP hardware clock that produces IEEE 1588 format 96-bit time-of-day and 64-bit relative PTP timestamps.
To use this module, import it and connect it to the DUT:
from cocotbext.eth import PtpClock
ptp_clock = PtpClock(
ts_tod=dut.ts_tod,
ts_rel=dut.ts_rel,
ts_step=dut.ts_step,
pps=dut.pps,
clock=dut.clk,
reset=dut.reset,
period_ns=6.4
)
Once the clock is instantiated, it will generate a continuous stream of monotonically increasing PTP timestamps on every clock edge.
Internally, the PtpClock
module uses 32-bit fractional ns fields for higher frequency resolution. Only the upper 16 bits are returned in the timestamps, but the full fns value can be accessed with the _ts_todfns and _ts_relfns attributes.
All APIs that handle fractional values use the Decimal
type for maximum precision, as the combination of timestamp range and resolution is usually too much for normal floating point numbers to handle without significant loss of precision.
ts_tod
: 96-bit time-of-day timestamp (48 bit seconds, 32 bit ns, 16 bit fractional ns)ts_rel
: 64-bit relative timestamp (48 bit ns, 16 bit fractional ns)ts_step
: step output, pulsed when non-monotonic step occurspps
: pulse-per-second output, pulsed when ts_tod seconds field incrementsTrue
)6.4
)set_period(ns, fns)
: set clock period from separate fieldsset_drift(num, denom)
: set clock drift from separate fieldsset_period_ns(t)
: set clock period and drift in ns (Decimal)get_period_ns()
: return current clock period in ns (Decimal)set_ts_tod(ts_s, ts_ns, ts_fns)
: set 96-bit ToD timestamp from separate fieldsset_ts_tod_96(ts)
: set 96-bit ToD timestamp from integerset_ts_tod_ns(t)
: set 96-bit ToD timestamp from ns (Decimal)set_ts_tod_s(t)
: set 96-bit ToD timestamp from seconds (Decimal)set_ts_tod_sim_time()
: set 96-bit ToD timestamp from sim timeget_ts_tod()
: return current 96-bit ToD timestamp as separate fieldsget_ts_tod_96()
: return current 96-bit ToD timestamp as an integerget_ts_tod_ns()
: return current 96-bit ToD timestamp in ns (Decimal)get_ts_tod_s()
: return current 96-bit ToD timestamp in seconds (Decimal)set_ts_rel(ts_ns, ts_fns)
: set 64-bit relative timestamp from separate fieldsset_ts_rel_64(ts)
: set 64-bit relative timestamp from integerset_ts_rel_ns(t)
: set 64-bit relative timestamp from ns (Decimal)set_ts_rel_s(t)
: set 64-bit relative timestamp from seconds (Decimal)set_ts_rel_sim_time()
: set 64-bit relative timestamp from sim timeget_ts_rel()
: return current 64-bit relative timestamp as separate fieldsget_ts_rel_64()
: return current 64-bit relative timestamp as an integerget_ts_rel_ns()
: return current 64-bit relative timestamp in ns (Decimal)get_ts_rel_s()
: return current 64-bit relative timestamp in seconds (Decimal)The PtpClockSimTime
class implements a PTP hardware clock that produces IEEE 1588 format 96-bit time-of-day and 64-bit relative PTP timestamps, derived from the current simulation time. This module can be used in place of PtpClock
so that captured PTP timestamps can be easily compared to captured simulation time.
To use this module, import it and connect it to the DUT:
from cocotbext.eth import PtpClockSimTime
ptp_clock = PtpClockSimTime(
ts_tod=dut.ts_tod,
ts_rel=dut.ts_rel,
pps=dut.pps,
clock=dut.clk
)
Once the clock is instantiated, it will generate a continuous stream of monotonically increasing PTP timestamps on every clock edge.
All APIs that handle fractional values use the Decimal
type for maximum precision, as the combination of timestamp range and resolution is usually too much for normal floating point numbers to handle without significant loss of precision.
ts_tod
: 96-bit time-of-day timestamp (48 bit seconds, 32 bit ns, 16 bit fractional ns)ts_rel
: 64-bit relative timestamp (48 bit ns, 16 bit fractional ns)pps
: pulse-per-second output, pulsed when ts_tod seconds field incrementsget_ts_tod()
: return current 96-bit ToD timestamp as separate fieldsget_ts_tod_96()
: return current 96-bit ToD timestamp as an integerget_ts_tod_ns()
: return current 96-bit ToD timestamp in ns (Decimal)get_ts_tod_s()
: return current 96-bit ToD timestamp in seconds (Decimal)get_ts_rel()
: return current 64-bit relative timestamp as separate fieldsget_ts_rel_96()
: return current 64-bit relative timestamp as an integerget_ts_rel_ns()
: return current 64-bit relative timestamp in ns (Decimal)get_ts_rel_s()
: return current 64-bit relative timestamp in seconds (Decimal)