Rename PTP clock timestamp signals to tod and rel

Signed-off-by: Alex Forencich <alex@alexforencich.com>
This commit is contained in:
Alex Forencich
2023-11-07 01:28:04 -08:00
parent 357dd26aae
commit c44f928bea
7 changed files with 288 additions and 264 deletions

View File

@@ -585,15 +585,15 @@ Methods:
### PTP clock
The `PtpClock` class implements a PTP hardware clock that produces IEEE 1588 format 96 and 64 bit PTP timestamps.
The `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_96=dut.ts_96,
ts_64=dut.ts_64,
ts_tod=dut.ts_tod,
ts_rel=dut.ts_rel,
ts_step=dut.ts_step,
pps=dut.pps,
clock=dut.clk,
@@ -605,15 +605,15 @@ Once the clock is instantiated, it will generate a continuous stream of monotoni
#### Signals
* `ts_96`: 96-bit timestamp (48 bit seconds, 32 bit ns, 16 bit fractional ns)
* `ts_64`: 64-bit timestamp (48 bit ns, 16 bit fractional ns)
* `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 occurs
* `pps`: pulse-per-second output, pulsed when ts_96 seconds field increments
* `pps`: pulse-per-second output, pulsed when ts_tod seconds field increments
#### Constructor parameters:
* _ts_96_: 96-bit timestamp signal (optional)
* _ts_64_: 64-bit timestamp signal (optional)
* _ts_tod_: 96-bit time-of-day timestamp signal (optional)
* _ts_rel_: 64-bit relative timestamp signal (optional)
* _ts_step_: timestamp step signal (optional)
* _pps_: pulse-per-second signal (optional)
* _clock_: clock
@@ -623,11 +623,11 @@ Once the clock is instantiated, it will generate a continuous stream of monotoni
#### Attributes:
* _ts_96_s_: current 96-bit timestamp seconds field
* _ts_96_ns_: current 96-bit timestamp ns field
* _ts_96_fns_: current 96-bit timestamp fractional ns field
* _ts_64_ns_: current 64-bit timestamp ns field
* _ts_64_fns_: current 64-bit timestamp fractional ns field
* _ts_tod_s_: current 96-bit ToD timestamp seconds field
* _ts_tod_ns_: current 96-bit ToD timestamp ns field
* _ts_tod_fns_: current 96-bit ToD timestamp fractional ns field
* _ts_rel_ns_: current 64-bit relative timestamp ns field
* _ts_rel_fns_: current 64-bit relative timestamp fractional ns field
#### Methods
@@ -635,30 +635,34 @@ Once the clock is instantiated, it will generate a continuous stream of monotoni
* `set_drift(num, denom)`: set clock drift from separate fields
* `set_period_ns(t)`: set clock period in ns (float)
* `get_period_ns()`: return current clock period in ns (float)
* `set_ts_96(ts_s, ts_ns=None, ts_fns=None)`: set 96-bit timestamp from integer or from separate fields
* `set_ts_96_ns(t)`: set 96-bit timestamp from ns (float)
* `set_ts_96_s(t)`: set 96-bit timestamp from seconds (float)
* `get_ts_96()`: return current 96-bit timestamp as an integer
* `get_ts_96_ns()`: return current 96-bit timestamp in ns (float)
* `get_ts_96_s()`: return current 96-bit timestamp in seconds (float)
* `set_ts_64(ts_ns, ts_fns=None)`: set 64-bit timestamp from integer or from separate fields
* `set_ts_64_ns(t)`: set 64-bit timestamp from ns (float)
* `set_ts_64_s(t)`: set 64-bit timestamp from seconds (float)
* `get_ts_64()`: return current 64-bit timestamp as an integer
* `get_ts_64_ns()`: return current 64-bit timestamp in ns (float)
* `get_ts_64_s()`: return current 64-bit timestamp in seconds (float)
* `set_ts_tod(ts_s, ts_ns, ts_fns)`: set 96-bit ToD timestamp from separate fields
* `set_ts_tod_96(ts)`: set 96-bit ToD timestamp from integer
* `set_ts_tod_ns(t)`: set 96-bit ToD timestamp from ns (float)
* `set_ts_tod_s(t)`: set 96-bit ToD timestamp from seconds (float)
* `get_ts_tod()`: return current 96-bit ToD timestamp as separate fields
* `get_ts_tod_96()`: return current 96-bit ToD timestamp as an integer
* `get_ts_tod_ns()`: return current 96-bit ToD timestamp in ns (float)
* `get_ts_tod_s()`: return current 96-bit ToD timestamp in seconds (float)
* `set_ts_rel(ts_ns, ts_fns)`: set 64-bit relative timestamp from separate fields
* `set_ts_rel_64(ts)`: set 64-bit relative timestamp from integer
* `set_ts_rel_ns(t)`: set 64-bit relative timestamp from ns (float)
* `set_ts_rel_s(t)`: set 64-bit relative timestamp from seconds (float)
* `get_ts_rel()`: return current 64-bit relative timestamp as separate fields
* `get_ts_rel_64()`: return current 64-bit relative timestamp as an integer
* `get_ts_rel_ns()`: return current 64-bit relative timestamp in ns (float)
* `get_ts_rel_s()`: return current 64-bit relative timestamp in seconds (float)
### PTP clock (sim time)
The `PtpClockSimTime` class implements a PTP hardware clock that produces IEEE 1588 format 96 and 64 bit 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.
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_96=dut.ts_96,
ts_64=dut.ts_64,
ts_tod=dut.ts_tod,
ts_rel=dut.ts_rel,
pps=dut.pps,
clock=dut.clk
)
@@ -667,30 +671,32 @@ Once the clock is instantiated, it will generate a continuous stream of monotoni
#### Signals
* `ts_96`: 96-bit timestamp (48 bit seconds, 32 bit ns, 16 bit fractional ns)
* `ts_64`: 64-bit timestamp (48 bit ns, 16 bit fractional ns)
* `pps`: pulse-per-second output, pulsed when ts_96 seconds field increments
* `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 increments
#### Constructor parameters:
* _ts_96_: 96-bit timestamp signal (optional)
* _ts_64_: 64-bit timestamp signal (optional)
* _ts_tod_: 96-bit time-of-day timestamp signal (optional)
* _ts_rel_: 64-bit relative timestamp signal (optional)
* _pps_: pulse-per-second signal (optional)
* _clock_: clock
#### Attributes:
* _ts_96_s_: current 96-bit timestamp seconds field
* _ts_96_ns_: current 96-bit timestamp ns field
* _ts_96_fns_: current 96-bit timestamp fractional ns field
* _ts_64_ns_: current 64-bit timestamp ns field
* _ts_64_fns_: current 64-bit timestamp fractional ns field
* _ts_tod_s_: current 96-bit ToD timestamp seconds field
* _ts_tod_ns_: current 96-bit ToD timestamp ns field
* _ts_tod_fns_: current 96-bit ToD timestamp fractional ns field
* _ts_rel_ns_: current 64-bit relative timestamp ns field
* _ts_rel_fns_: current 64-bit relative timestamp fractional ns field
#### Methods
* `get_ts_96()`: return current 96-bit timestamp as an integer
* `get_ts_96_ns()`: return current 96-bit timestamp in ns (float)
* `get_ts_96_s()`: return current 96-bit timestamp in seconds (float)
* `get_ts_64()`: return current 64-bit timestamp as an integer
* `get_ts_64_ns()`: return current 64-bit timestamp in ns (float)
* `get_ts_64_s()`: return current 64-bit timestamp in seconds (float)
* `get_ts_tod()`: return current 96-bit ToD timestamp as separate fields
* `get_ts_tod_96()`: return current 96-bit ToD timestamp as an integer
* `get_ts_tod_ns()`: return current 96-bit ToD timestamp in ns (float)
* `get_ts_tod_s()`: return current 96-bit ToD timestamp in seconds (float)
* `get_ts_rel()`: return current 64-bit relative timestamp as separate fields
* `get_ts_rel_96()`: return current 64-bit relative timestamp as an integer
* `get_ts_rel_ns()`: return current 64-bit relative timestamp in ns (float)
* `get_ts_rel_s()`: return current 64-bit relative timestamp in seconds (float)

View File

@@ -38,8 +38,8 @@ class PtpClock(Reset):
def __init__(
self,
ts_96=None,
ts_64=None,
ts_tod=None,
ts_rel=None,
ts_step=None,
pps=None,
clock=None,
@@ -49,8 +49,8 @@ class PtpClock(Reset):
*args, **kwargs):
self.log = logging.getLogger(f"cocotb.eth.{type(self).__name__}")
self.ts_96 = ts_96
self.ts_64 = ts_64
self.ts_tod = ts_tod
self.ts_rel = ts_rel
self.ts_step = ts_step
self.pps = pps
self.clock = clock
@@ -70,19 +70,19 @@ class PtpClock(Reset):
super().__init__(*args, **kwargs)
self.ts_96_s = 0
self.ts_96_ns = 0
self.ts_96_fns = 0
self.ts_tod_s = 0
self.ts_tod_ns = 0
self.ts_tod_fns = 0
self.ts_64_ns = 0
self.ts_64_fns = 0
self.ts_rel_ns = 0
self.ts_rel_fns = 0
self.ts_updated = False
if self.ts_96 is not None:
self.ts_96.setimmediatevalue(0)
if self.ts_64 is not None:
self.ts_64.setimmediatevalue(0)
if self.ts_tod is not None:
self.ts_tod.setimmediatevalue(0)
if self.ts_rel is not None:
self.ts_rel.setimmediatevalue(0)
if self.ts_step is not None:
self.ts_step.setimmediatevalue(0)
if self.pps is not None:
@@ -115,65 +115,70 @@ class PtpClock(Reset):
return p + self.drift_num / self.drift_rate / 2**16
return p
def set_ts_96(self, ts_s, ts_ns=None, ts_fns=None):
ts_s = int(ts_s)
if ts_fns is not None:
# got separate fields
self.ts_96_s = ts_s
self.ts_96_ns = int(ts_ns)
self.ts_96_fns = int(ts_fns)
else:
# got timestamp as integer
self.ts_96_s = ts_s >> 48
self.ts_96_ns = (ts_s >> 16) & 0x3fffffff
self.ts_96_fns = ts_s & 0xffff
def set_ts_tod(self, ts_s, ts_ns, ts_fns):
self.ts_tod_s = int(ts_s)
self.ts_tod_ns = int(ts_ns)
self.ts_tod_fns = int(ts_fns)
self.ts_updated = True
def set_ts_96_ns(self, t):
self.set_ts_96_s(t*1e-9)
def set_ts_tod_96(self, ts):
ts = int(ts)
self.set_ts_tod(ts >> 48, (ts >> 32) & 0x3fffffff, ts & 0xffff)
def set_ts_96_s(self, t):
def set_ts_tod_ns(self, t):
self.set_ts_tod_s(t*1e-9)
def set_ts_tod_s(self, t):
ts_ns, ts_s = math.modf(t)
ts_ns *= 1e9
ts_fns, ts_ns = math.modf(ts_ns)
ts_fns *= 2**16
self.set_ts_96(ts_s, ts_ns, ts_fns)
self.set_ts_tod(ts_s, ts_ns, ts_fns)
def get_ts_96(self):
return (self.ts_96_s << 48) | (self.ts_96_ns << 16) | self.ts_96_fns
def get_ts_tod(self):
return (self.ts_tod_s, self.ts_tod_ns, self.ts_tod_fns)
def get_ts_96_ns(self):
return self.ts_96_s*1e9+self.ts_96_ns+self.ts_96_fns/2**16
def get_ts_tod_96(self):
ts_s, ts_ns, ts_fns = self.get_ts_tod()
return (ts_s << 48) | (ts_ns << 16) | ts_fns
def get_ts_96_s(self):
return self.get_ts_96_ns()*1e-9
def get_ts_tod_ns(self):
ts_s, ts_ns, ts_fns = self.get_ts_tod()
return ts_s*1e9+ts_ns+ts_fns/2**16
def set_ts_64(self, ts_ns, ts_fns=None):
ts_ns = int(ts_ns)
if ts_fns is not None:
# got separate fields
self.ts_64_ns = ts_ns
self.ts_64_fns = int(ts_fns)
else:
# got timestamp as integer
self.ts_64_ns = ts_ns >> 16
self.ts_64_fns = ts_ns & 0xffff
def get_ts_tod_s(self):
return self.get_ts_tod_ns()*1e-9
def set_ts_rel(self, ts_ns, ts_fns):
self.ts_rel_ns = int(ts_ns)
self.ts_rel_fns = int(ts_fns)
self.ts_updated = True
def set_ts_64_ns(self, t):
self.set_ts_64(t*2**16)
def set_ts_rel_64(self, ts):
ts = int(ts)
self.set_ts_rel(ts >> 16, (ts & 0xffff) << 16)
def set_ts_64_s(self, t):
self.set_ts_64_ns(t*1e9)
def set_ts_rel_ns(self, t):
ts_fns, ts_ns = math.modf(t)
ts_fns *= 2**16
self.set_ts_rel(ts_ns, ts_fns)
def get_ts_64(self):
return (self.ts_64_ns << 16) | self.ts_64_fns
def set_ts_rel_s(self, t):
self.set_ts_rel_ns(t*1e9)
def get_ts_64_ns(self):
return self.get_ts_64()/2**16
def get_ts_rel(self):
return (self.ts_rel_ns, self.ts_rel_fns)
def get_ts_64_s(self):
return self.get_ts_64()*1e-9
def get_ts_rel_64(self):
ts_ns, ts_fns = self.get_ts_rel()
return (ts_ns << 16) | (ts_fns >> 16)
def get_ts_rel_ns(self):
ts_ns, ts_fns = self.get_ts_rel()
return ts_ns + ts_fns/2**16
def get_ts_rel_s(self):
return self.get_ts_rel()*1e-9
def _handle_reset(self, state):
if state:
@@ -182,16 +187,16 @@ class PtpClock(Reset):
self._run_cr.kill()
self._run_cr = None
self.ts_96_s = 0
self.ts_96_ns = 0
self.ts_96_fns = 0
self.ts_64_ns = 0
self.ts_64_fns = 0
self.ts_tod_s = 0
self.ts_tod_ns = 0
self.ts_tod_fns = 0
self.ts_rel_ns = 0
self.ts_rel_fns = 0
self.drift_cnt = 0
if self.ts_96 is not None:
self.ts_96.value = 0
if self.ts_64 is not None:
self.ts_64.value = 0
if self.ts_tod is not None:
self.ts_tod.value = 0
if self.ts_rel is not None:
self.ts_rel.value = 0
if self.ts_step is not None:
self.ts_step.value = 0
if self.pps is not None:
@@ -215,35 +220,35 @@ class PtpClock(Reset):
self.pps.value = 0
# increment 96 bit timestamp
if self.ts_96 is not None or self.pps is not None:
t = ((self.ts_96_ns << 16) + self.ts_96_fns) + ((self.period_ns << 16) + self.period_fns)
if self.ts_tod is not None or self.pps is not None:
t = ((self.ts_tod_ns << 16) + self.ts_tod_fns) + ((self.period_ns << 16) + self.period_fns)
if self.drift_denom and self.drift_cnt == 0:
t += self.drift_num
if t > (1000000000 << 16):
self.ts_96_s += 1
self.ts_tod_s += 1
t -= (1000000000 << 16)
if self.pps is not None:
self.pps.value = 1
self.ts_96_fns = t & 0xffff
self.ts_96_ns = t >> 16
self.ts_tod_fns = t & 0xffff
self.ts_tod_ns = t >> 16
if self.ts_96 is not None:
self.ts_96.value = (self.ts_96_s << 48) | (self.ts_96_ns << 16) | (self.ts_96_fns)
if self.ts_tod is not None:
self.ts_tod.value = (self.ts_tod_s << 48) | (self.ts_tod_ns << 16) | (self.ts_tod_fns)
# increment 64 bit timestamp
if self.ts_64 is not None:
t = ((self.ts_64_ns << 16) + self.ts_64_fns) + ((self.period_ns << 16) + self.period_fns)
if self.ts_rel is not None:
t = ((self.ts_rel_ns << 16) + self.ts_rel_fns) + ((self.period_ns << 16) + self.period_fns)
if self.drift_denom and self.drift_cnt == 0:
t += self.drift_num
self.ts_64_fns = t & 0xffff
self.ts_64_ns = t >> 16
self.ts_rel_fns = t & 0xffff
self.ts_rel_ns = t >> 16
self.ts_64.value = (self.ts_64_ns << 16) | self.ts_64_fns
self.ts_rel.value = (self.ts_rel_ns << 16) | self.ts_rel_fns
if self.drift_denom:
if self.drift_cnt > 0:
@@ -254,10 +259,10 @@ class PtpClock(Reset):
class PtpClockSimTime:
def __init__(self, ts_96=None, ts_64=None, pps=None, clock=None, *args, **kwargs):
def __init__(self, ts_tod=None, ts_rel=None, pps=None, clock=None, *args, **kwargs):
self.log = logging.getLogger(f"cocotb.eth.{type(self).__name__}")
self.ts_96 = ts_96
self.ts_64 = ts_64
self.ts_tod = ts_tod
self.ts_rel = ts_rel
self.pps = pps
self.clock = clock
@@ -268,41 +273,48 @@ class PtpClockSimTime:
super().__init__(*args, **kwargs)
self.ts_96_s = 0
self.ts_96_ns = 0
self.ts_96_fns = 0
self.ts_tod_s = 0
self.ts_tod_ns = 0
self.ts_tod_fns = 0
self.ts_64_ns = 0
self.ts_64_fns = 0
self.ts_rel_ns = 0
self.ts_rel_fns = 0
self.last_ts_96_s = 0
self.last_ts_tod_s = 0
if self.ts_96 is not None:
self.ts_96.setimmediatevalue(0)
if self.ts_64 is not None:
self.ts_64.setimmediatevalue(0)
if self.ts_tod is not None:
self.ts_tod.setimmediatevalue(0)
if self.ts_rel is not None:
self.ts_rel.setimmediatevalue(0)
if self.pps is not None:
self.pps.value = 0
self._run_cr = cocotb.start_soon(self._run())
def get_ts_96(self):
return (self.ts_96_s << 48) | (self.ts_96_ns << 16) | self.ts_96_fns
def get_ts_tod(self):
return (self.ts_tod_s, self.ts_tod_ns, self.ts_tod_fns)
def get_ts_96_ns(self):
return self.ts_96_s*1e9+self.ts_96_ns+self.ts_96_fns/2**16
def get_ts_tod_96(self):
ts_s, ts_ns, ts_fns = self.get_ts_tod()
return (ts_s << 48) | (ts_ns << 16) | ts_fns
def get_ts_96_s(self):
return self.get_ts_96_ns()*1e-9
def get_ts_tod_ns(self):
ts_s, ts_ns, ts_fns = self.get_ts_tod()
return ts_s*1e9+ts_ns+ts_fns/2**16
def get_ts_64(self):
return (self.ts_64_ns << 16) | self.ts_64_fns
def get_ts_rel(self):
return (self.ts_rel_ns, self.ts_rel_fns)
def get_ts_64_ns(self):
return self.get_ts_64()/2**16
def get_ts_rel_64(self):
ts_ns, ts_fns = self.get_ts_rel()
return (ts_ns << 16) | (ts_fns >> 16)
def get_ts_64_s(self):
return self.get_ts_64()*1e-9
def get_ts_rel_ns(self):
ts_ns, ts_fns = self.get_ts_rel()
return ts_ns + ts_fns/2**16
def get_ts_rel_s(self):
return self.get_ts_rel()*1e-9
async def _run(self):
clock_edge_event = RisingEdge(self.clock)
@@ -310,21 +322,21 @@ class PtpClockSimTime:
while True:
await clock_edge_event
self.ts_64_fns, self.ts_64_ns = math.modf(get_sim_time('ns'))
self.ts_rel_fns, self.ts_rel_ns = math.modf(get_sim_time('ns'))
self.ts_64_ns = int(self.ts_64_ns)
self.ts_64_fns = int(self.ts_64_fns*0x10000)
self.ts_rel_ns = int(self.ts_rel_ns)
self.ts_rel_fns = int(self.ts_rel_fns*0x10000)
self.ts_96_s, self.ts_96_ns = divmod(self.ts_64_ns, 1000000000)
self.ts_96_fns = self.ts_64_fns
self.ts_tod_s, self.ts_tod_ns = divmod(self.ts_rel_ns, 1000000000)
self.ts_tod_fns = self.ts_rel_fns
if self.ts_96 is not None:
self.ts_96.value = (self.ts_96_s << 48) | (self.ts_96_ns << 16) | self.ts_96_fns
if self.ts_tod is not None:
self.ts_tod.value = (self.ts_tod_s << 48) | (self.ts_tod_ns << 16) | self.ts_tod_fns
if self.ts_64 is not None:
self.ts_64.value = (self.ts_64_ns << 16) | self.ts_64_fns
if self.ts_rel is not None:
self.ts_rel.value = (self.ts_rel_ns << 16) | self.ts_rel_fns
if self.pps is not None:
self.pps.value = int(self.last_ts_96_s != self.ts_96_s)
self.pps.value = int(self.last_ts_tod_s != self.ts_tod_s)
self.last_ts_96_s = self.ts_96_s
self.last_ts_tod_s = self.ts_tod_s

View File

@@ -77,12 +77,12 @@ class TB:
)
self.tx_ptp = PtpClockSimTime(
ts_96=dut.tx_ptp_time,
ts_tod=dut.tx_ptp_time,
clock=dut.tx_clk
)
self.rx_ptp = PtpClockSimTime(
ts_96=dut.rx_ptp_time,
ts_tod=dut.rx_ptp_time,
clock=dut.rx_clk
)

View File

@@ -46,8 +46,8 @@ class TB:
cocotb.start_soon(Clock(dut.clk, 6.4, units="ns").start())
self.ptp_clock = PtpClock(
ts_96=dut.ts_96,
ts_64=dut.ts_64,
ts_tod=dut.ts_tod,
ts_rel=dut.ts_rel,
ts_step=dut.ts_step,
pps=dut.pps,
clock=dut.clk,
@@ -76,30 +76,31 @@ async def run_default_rate(dut):
await RisingEdge(dut.clk)
start_time = get_sim_time('sec')
start_ts_96 = (dut.ts_96.value.integer >> 48) + ((dut.ts_96.value.integer & 0xffffffffffff)/2**16*1e-9)
start_ts_64 = dut.ts_64.value.integer/2**16*1e-9
start_ts_tod = (dut.ts_tod.value.integer >> 48) + ((dut.ts_tod.value.integer & 0xffffffffffff)/2**16*1e-9)
start_ts_rel = dut.ts_rel.value.integer/2**16*1e-9
await ClockCycles(dut.clk, 10000)
stop_time = get_sim_time('sec')
stop_ts_96 = (dut.ts_96.value.integer >> 48) + ((dut.ts_96.value.integer & 0xffffffffffff)/2**16*1e-9)
stop_ts_64 = dut.ts_64.value.integer/2**16*1e-9
stop_ts_tod = (dut.ts_tod.value.integer >> 48) + ((dut.ts_tod.value.integer & 0xffffffffffff)/2**16*1e-9)
stop_ts_rel = dut.ts_rel.value.integer/2**16*1e-9
time_delta = stop_time-start_time
ts_96_delta = stop_ts_96-start_ts_96
ts_64_delta = stop_ts_64-start_ts_64
ts_tod_delta = stop_ts_tod-start_ts_tod
ts_rel_delta = stop_ts_rel-start_ts_rel
ts_96_diff = time_delta - ts_96_delta
ts_64_diff = time_delta - ts_64_delta
tb.log.info("sim time delta : %g s", time_delta)
tb.log.info("ToD ts delta : %g s", ts_tod_delta)
tb.log.info("rel ts delta : %g s", ts_rel_delta)
tb.log.info("sim time delta : %g s", time_delta)
tb.log.info("96 bit ts delta : %g s", ts_96_delta)
tb.log.info("64 bit ts delta : %g s", ts_64_delta)
tb.log.info("96 bit ts diff : %g s", ts_96_diff)
tb.log.info("64 bit ts diff : %g s", ts_64_diff)
ts_tod_diff = time_delta - ts_tod_delta
ts_rel_diff = time_delta - ts_rel_delta
assert abs(ts_96_diff) < 1e-12
assert abs(ts_64_diff) < 1e-12
tb.log.info("ToD ts diff : %g s", ts_tod_diff)
tb.log.info("rel ts diff : %g s", ts_rel_diff)
assert abs(ts_tod_diff) < 1e-12
assert abs(ts_rel_diff) < 1e-12
await RisingEdge(dut.clk)
await RisingEdge(dut.clk)
@@ -112,40 +113,41 @@ async def run_load_timestamps(dut):
await tb.reset()
tb.ptp_clock.set_ts_96(12345678)
tb.ptp_clock.set_ts_64(12345678)
tb.ptp_clock.set_ts_tod_ns(12345678)
tb.ptp_clock.set_ts_rel_ns(12345678)
await RisingEdge(dut.clk)
assert dut.ts_96.value.integer == 12345678+((tb.ptp_clock.period_ns << 16) + tb.ptp_clock.period_fns)
assert dut.ts_64.value.integer == 12345678+((tb.ptp_clock.period_ns << 16) + tb.ptp_clock.period_fns)
assert dut.ts_tod.value.integer == 12345678*2**16 + (tb.ptp_clock.period_ns << 16) + tb.ptp_clock.period_fns
assert dut.ts_rel.value.integer == 12345678*2**16 + (tb.ptp_clock.period_ns << 16) + tb.ptp_clock.period_fns
assert dut.ts_step.value.integer == 1
start_time = get_sim_time('sec')
start_ts_96 = (dut.ts_96.value.integer >> 48) + ((dut.ts_96.value.integer & 0xffffffffffff)/2**16*1e-9)
start_ts_64 = dut.ts_64.value.integer/2**16*1e-9
start_ts_tod = (dut.ts_tod.value.integer >> 48) + ((dut.ts_tod.value.integer & 0xffffffffffff)/2**16*1e-9)
start_ts_rel = dut.ts_rel.value.integer/2**16*1e-9
await ClockCycles(dut.clk, 2000)
stop_time = get_sim_time('sec')
stop_ts_96 = (dut.ts_96.value.integer >> 48) + ((dut.ts_96.value.integer & 0xffffffffffff)/2**16*1e-9)
stop_ts_64 = dut.ts_64.value.integer/2**16*1e-9
stop_ts_tod = (dut.ts_tod.value.integer >> 48) + ((dut.ts_tod.value.integer & 0xffffffffffff)/2**16*1e-9)
stop_ts_rel = dut.ts_rel.value.integer/2**16*1e-9
time_delta = stop_time-start_time
ts_96_delta = stop_ts_96-start_ts_96
ts_64_delta = stop_ts_64-start_ts_64
ts_tod_delta = stop_ts_tod-start_ts_tod
ts_rel_delta = stop_ts_rel-start_ts_rel
ts_96_diff = time_delta - ts_96_delta
ts_64_diff = time_delta - ts_64_delta
tb.log.info("sim time delta : %g s", time_delta)
tb.log.info("ToD ts delta : %g s", ts_tod_delta)
tb.log.info("rel ts delta : %g s", ts_rel_delta)
tb.log.info("sim time delta : %g s", time_delta)
tb.log.info("96 bit ts delta : %g s", ts_96_delta)
tb.log.info("64 bit ts delta : %g s", ts_64_delta)
tb.log.info("96 bit ts diff : %g s", ts_96_diff)
tb.log.info("64 bit ts diff : %g s", ts_64_diff)
ts_tod_diff = time_delta - ts_tod_delta
ts_rel_diff = time_delta - ts_rel_delta
assert abs(ts_96_diff) < 1e-12
assert abs(ts_64_diff) < 1e-12
tb.log.info("ToD ts diff : %g s", ts_tod_diff)
tb.log.info("rel ts diff : %g s", ts_rel_diff)
assert abs(ts_tod_diff) < 1e-12
assert abs(ts_rel_diff) < 1e-12
await RisingEdge(dut.clk)
await RisingEdge(dut.clk)
@@ -158,15 +160,15 @@ async def run_seconds_increment(dut):
await tb.reset()
tb.ptp_clock.set_ts_96(999990000*2**16)
tb.ptp_clock.set_ts_64(999990000*2**16)
tb.ptp_clock.set_ts_tod_ns(999990000)
tb.ptp_clock.set_ts_rel_ns(999990000)
await RisingEdge(dut.clk)
await RisingEdge(dut.clk)
start_time = get_sim_time('sec')
start_ts_96 = (dut.ts_96.value.integer >> 48) + ((dut.ts_96.value.integer & 0xffffffffffff)/2**16*1e-9)
start_ts_64 = dut.ts_64.value.integer/2**16*1e-9
start_ts_tod = (dut.ts_tod.value.integer >> 48) + ((dut.ts_tod.value.integer & 0xffffffffffff)/2**16*1e-9)
start_ts_rel = dut.ts_rel.value.integer/2**16*1e-9
saw_pps = False
@@ -175,30 +177,31 @@ async def run_seconds_increment(dut):
if dut.pps.value.integer:
saw_pps = True
assert dut.ts_96.value.integer >> 48 == 1
assert dut.ts_96.value.integer & 0xffffffffffff < 10*2**16
assert dut.ts_tod.value.integer >> 48 == 1
assert dut.ts_tod.value.integer & 0xffffffffffff < 10*2**16
assert saw_pps
stop_time = get_sim_time('sec')
stop_ts_96 = (dut.ts_96.value.integer >> 48) + ((dut.ts_96.value.integer & 0xffffffffffff)/2**16*1e-9)
stop_ts_64 = dut.ts_64.value.integer/2**16*1e-9
stop_ts_tod = (dut.ts_tod.value.integer >> 48) + ((dut.ts_tod.value.integer & 0xffffffffffff)/2**16*1e-9)
stop_ts_rel = dut.ts_rel.value.integer/2**16*1e-9
time_delta = stop_time-start_time
ts_96_delta = stop_ts_96-start_ts_96
ts_64_delta = stop_ts_64-start_ts_64
ts_tod_delta = stop_ts_tod-start_ts_tod
ts_rel_delta = stop_ts_rel-start_ts_rel
ts_96_diff = time_delta - ts_96_delta
ts_64_diff = time_delta - ts_64_delta
tb.log.info("sim time delta : %g s", time_delta)
tb.log.info("ToD ts delta : %g s", ts_tod_delta)
tb.log.info("rel ts delta : %g s", ts_rel_delta)
tb.log.info("sim time delta : %g s", time_delta)
tb.log.info("96 bit ts delta : %g s", ts_96_delta)
tb.log.info("64 bit ts delta : %g s", ts_64_delta)
tb.log.info("96 bit ts diff : %g s", ts_96_diff)
tb.log.info("64 bit ts diff : %g s", ts_64_diff)
ts_tod_diff = time_delta - ts_tod_delta
ts_rel_diff = time_delta - ts_rel_delta
assert abs(ts_96_diff) < 1e-12
assert abs(ts_64_diff) < 1e-12
tb.log.info("ToD ts diff : %g s", ts_tod_diff)
tb.log.info("rel ts diff : %g s", ts_rel_diff)
assert abs(ts_tod_diff) < 1e-12
assert abs(ts_rel_diff) < 1e-12
await RisingEdge(dut.clk)
await RisingEdge(dut.clk)
@@ -216,30 +219,31 @@ async def run_frequency_adjustment(dut):
await RisingEdge(dut.clk)
start_time = get_sim_time('sec')
start_ts_96 = (dut.ts_96.value.integer >> 48) + ((dut.ts_96.value.integer & 0xffffffffffff)/2**16*1e-9)
start_ts_64 = dut.ts_64.value.integer/2**16*1e-9
start_ts_tod = (dut.ts_tod.value.integer >> 48) + ((dut.ts_tod.value.integer & 0xffffffffffff)/2**16*1e-9)
start_ts_rel = dut.ts_rel.value.integer/2**16*1e-9
await ClockCycles(dut.clk, 10000)
stop_time = get_sim_time('sec')
stop_ts_96 = (dut.ts_96.value.integer >> 48) + ((dut.ts_96.value.integer & 0xffffffffffff)/2**16*1e-9)
stop_ts_64 = dut.ts_64.value.integer/2**16*1e-9
stop_ts_tod = (dut.ts_tod.value.integer >> 48) + ((dut.ts_tod.value.integer & 0xffffffffffff)/2**16*1e-9)
stop_ts_rel = dut.ts_rel.value.integer/2**16*1e-9
time_delta = stop_time-start_time
ts_96_delta = stop_ts_96-start_ts_96
ts_64_delta = stop_ts_64-start_ts_64
ts_tod_delta = stop_ts_tod-start_ts_tod
ts_rel_delta = stop_ts_rel-start_ts_rel
ts_96_diff = time_delta - ts_96_delta * 6.4/(6+(0x6624+2/5)/2**16)
ts_64_diff = time_delta - ts_64_delta * 6.4/(6+(0x6624+2/5)/2**16)
tb.log.info("sim time delta : %g s", time_delta)
tb.log.info("ToD ts delta : %g s", ts_tod_delta)
tb.log.info("rel ts delta : %g s", ts_rel_delta)
tb.log.info("sim time delta : %g s", time_delta)
tb.log.info("96 bit ts delta : %g s", ts_96_delta)
tb.log.info("64 bit ts delta : %g s", ts_64_delta)
tb.log.info("96 bit ts diff : %g s", ts_96_diff)
tb.log.info("64 bit ts diff : %g s", ts_64_diff)
ts_tod_diff = time_delta - ts_tod_delta * 6.4/(6+(0x6624+2/5)/2**16)
ts_rel_diff = time_delta - ts_rel_delta * 6.4/(6+(0x6624+2/5)/2**16)
assert abs(ts_96_diff) < 1e-12
assert abs(ts_64_diff) < 1e-12
tb.log.info("ToD ts diff : %g s", ts_tod_diff)
tb.log.info("rel ts diff : %g s", ts_rel_diff)
assert abs(ts_tod_diff) < 1e-12
assert abs(ts_rel_diff) < 1e-12
await RisingEdge(dut.clk)
await RisingEdge(dut.clk)
@@ -257,30 +261,31 @@ async def run_drift_adjustment(dut):
await RisingEdge(dut.clk)
start_time = get_sim_time('sec')
start_ts_96 = (dut.ts_96.value.integer >> 48) + ((dut.ts_96.value.integer & 0xffffffffffff)/2**16*1e-9)
start_ts_64 = dut.ts_64.value.integer/2**16*1e-9
start_ts_tod = (dut.ts_tod.value.integer >> 48) + ((dut.ts_tod.value.integer & 0xffffffffffff)/2**16*1e-9)
start_ts_rel = dut.ts_rel.value.integer/2**16*1e-9
await ClockCycles(dut.clk, 10000)
stop_time = get_sim_time('sec')
stop_ts_96 = (dut.ts_96.value.integer >> 48) + ((dut.ts_96.value.integer & 0xffffffffffff)/2**16*1e-9)
stop_ts_64 = dut.ts_64.value.integer/2**16*1e-9
stop_ts_tod = (dut.ts_tod.value.integer >> 48) + ((dut.ts_tod.value.integer & 0xffffffffffff)/2**16*1e-9)
stop_ts_rel = dut.ts_rel.value.integer/2**16*1e-9
time_delta = stop_time-start_time
ts_96_delta = stop_ts_96-start_ts_96
ts_64_delta = stop_ts_64-start_ts_64
ts_tod_delta = stop_ts_tod-start_ts_tod
ts_rel_delta = stop_ts_rel-start_ts_rel
ts_96_diff = time_delta - ts_96_delta * 6.4/(6+(0x6666+20/5)/2**16)
ts_64_diff = time_delta - ts_64_delta * 6.4/(6+(0x6666+20/5)/2**16)
tb.log.info("sim time delta : %g s", time_delta)
tb.log.info("ToD ts delta : %g s", ts_tod_delta)
tb.log.info("rel ts delta : %g s", ts_rel_delta)
tb.log.info("sim time delta : %g s", time_delta)
tb.log.info("96 bit ts delta : %g s", ts_96_delta)
tb.log.info("64 bit ts delta : %g s", ts_64_delta)
tb.log.info("96 bit ts diff : %g s", ts_96_diff)
tb.log.info("64 bit ts diff : %g s", ts_64_diff)
ts_tod_diff = time_delta - ts_tod_delta * 6.4/(6+(0x6666+20/5)/2**16)
ts_rel_diff = time_delta - ts_rel_delta * 6.4/(6+(0x6666+20/5)/2**16)
assert abs(ts_96_diff) < 1e-12
assert abs(ts_64_diff) < 1e-12
tb.log.info("ToD ts diff : %g s", ts_tod_diff)
tb.log.info("rel ts diff : %g s", ts_rel_diff)
assert abs(ts_tod_diff) < 1e-12
assert abs(ts_rel_diff) < 1e-12
await RisingEdge(dut.clk)
await RisingEdge(dut.clk)

View File

@@ -34,8 +34,8 @@ module test_ptp_clock
input wire clk,
input wire rst,
inout wire [95:0] ts_96,
inout wire [63:0] ts_64,
inout wire [95:0] ts_tod,
inout wire [63:0] ts_rel,
inout wire ts_step,
inout wire pps
);

View File

@@ -46,8 +46,8 @@ class TB:
cocotb.start_soon(Clock(dut.clk, 6.4, units="ns").start())
self.ptp_clock = PtpClockSimTime(
ts_96=dut.ts_96,
ts_64=dut.ts_64,
ts_tod=dut.ts_tod,
ts_rel=dut.ts_rel,
pps=dut.pps,
clock=dut.clk
)
@@ -63,30 +63,31 @@ async def run_test(dut):
await RisingEdge(dut.clk)
start_time = get_sim_time('sec')
start_ts_96 = (dut.ts_96.value.integer >> 48) + ((dut.ts_96.value.integer & 0xffffffffffff)/2**16*1e-9)
start_ts_64 = dut.ts_64.value.integer/2**16*1e-9
start_ts_tod = (dut.ts_tod.value.integer >> 48) + ((dut.ts_tod.value.integer & 0xffffffffffff)/2**16*1e-9)
start_ts_rel = dut.ts_rel.value.integer/2**16*1e-9
await ClockCycles(dut.clk, 10000)
stop_time = get_sim_time('sec')
stop_ts_96 = (dut.ts_96.value.integer >> 48) + ((dut.ts_96.value.integer & 0xffffffffffff)/2**16*1e-9)
stop_ts_64 = dut.ts_64.value.integer/2**16*1e-9
stop_ts_tod = (dut.ts_tod.value.integer >> 48) + ((dut.ts_tod.value.integer & 0xffffffffffff)/2**16*1e-9)
stop_ts_rel = dut.ts_rel.value.integer/2**16*1e-9
time_delta = stop_time-start_time
ts_96_delta = stop_ts_96-start_ts_96
ts_64_delta = stop_ts_64-start_ts_64
ts_tod_delta = stop_ts_tod-start_ts_tod
ts_rel_delta = stop_ts_rel-start_ts_rel
ts_96_diff = time_delta - ts_96_delta
ts_64_diff = time_delta - ts_64_delta
tb.log.info("sim time delta : %g s", time_delta)
tb.log.info("ToD ts delta : %g s", ts_tod_delta)
tb.log.info("rel ts delta : %g s", ts_rel_delta)
tb.log.info("sim time delta : %g s", time_delta)
tb.log.info("96 bit ts delta : %g s", ts_96_delta)
tb.log.info("64 bit ts delta : %g s", ts_64_delta)
tb.log.info("96 bit ts diff : %g s", ts_96_diff)
tb.log.info("64 bit ts diff : %g s", ts_64_diff)
ts_tod_diff = time_delta - ts_tod_delta
ts_rel_diff = time_delta - ts_rel_delta
assert abs(ts_96_diff) < 1e-12
assert abs(ts_64_diff) < 1e-12
tb.log.info("ToD ts diff : %g s", ts_tod_diff)
tb.log.info("rel ts diff : %g s", ts_rel_diff)
assert abs(ts_tod_diff) < 1e-12
assert abs(ts_rel_diff) < 1e-12
await RisingEdge(dut.clk)
await RisingEdge(dut.clk)

View File

@@ -33,8 +33,8 @@ module test_ptp_clock_sim_time
(
input wire clk,
inout wire [95:0] ts_96,
inout wire [63:0] ts_64,
inout wire [95:0] ts_tod,
inout wire [63:0] ts_rel,
inout wire pps
);