Skip to content

Commit

Permalink
sim: represent time internally as 100ps units
Browse files Browse the repository at this point in the history
Using floats to represent simulation time internally isn't ideal
instead use 100ps internal units while continuing to use a floating
point based interface for compatibility.

Fixes amaranth-lang#535.
  • Loading branch information
Lunaphied committed Dec 13, 2021
1 parent 0b74d1c commit b106d05
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 13 deletions.
2 changes: 1 addition & 1 deletion amaranth/sim/_pyclock.py
Expand Up @@ -31,4 +31,4 @@ def run(self):
else:
clk_state = self.state.slots[self.slot]
clk_state.set(not clk_state.curr)
self.state.wait_interval(self, self.period / 2)
self.state.wait_interval(self, self.period // 2)
9 changes: 7 additions & 2 deletions amaranth/sim/core.py
Expand Up @@ -130,12 +130,15 @@ def add_clock(self, period, *, phase=None, domain="sync", if_exists=False):
if domain in self._clocked:
raise ValueError("Domain {!r} already has a clock driving it"
.format(domain.name))

# We represent times internally in 1 ps units, but users supply float quantities of seconds
period = int(period * 1e12)

if phase is None:
# By default, delay the first edge by half period. This causes any synchronous activity
# to happen at a non-zero time, distinguishing it from the reset values in the waveform
# viewer.
phase = period / 2
phase = period // 2
self._engine.add_clock_process(domain.clk, phase=phase, period=period)
self._clocked.add(domain)

Expand Down Expand Up @@ -181,6 +184,8 @@ def run_until(self, deadline, *, run_passive=False):
If the simulation stops advancing, this function will never return.
"""
# Convert deadline in seconds into internal 100 ps units
deadline = deadline * (10 ** 10)
assert self._engine.now <= deadline
while (self.advance() or run_passive) and self._engine.now < deadline:
pass
Expand All @@ -204,7 +209,7 @@ def write_vcd(self, vcd_file, gtkw_file=None, *, traces=()):
traces : iterable of Signal
Signals to display traces for.
"""
if self._engine.now != 0.0:
if self._engine.now != 0:
for file in (vcd_file, gtkw_file):
if hasattr(file, "close"):
file.close()
Expand Down
17 changes: 7 additions & 10 deletions amaranth/sim/pysim.py
Expand Up @@ -48,10 +48,6 @@ def add_signal_name(signal):


class _VCDWriter:
@staticmethod
def timestamp_to_vcd(timestamp):
return timestamp * (10 ** 10) # 1/(100 ps)

@staticmethod
def decode_to_vcd(signal, value):
return signal.decoder(value).expandtabs().replace(" ", "_")
Expand All @@ -65,7 +61,7 @@ def __init__(self, fragment, *, vcd_file, gtkw_file=None, traces=()):
self.vcd_vars = SignalDict()
self.vcd_file = vcd_file
self.vcd_writer = vcd_file and VCDWriter(self.vcd_file,
timescale="100 ps", comment="Generated by Amaranth")
timescale="1 ps", comment="Generated by Amaranth")

self.gtkw_names = SignalDict()
self.gtkw_file = gtkw_file
Expand Down Expand Up @@ -127,16 +123,15 @@ def update(self, timestamp, signal, value):
if vcd_var is None:
return

vcd_timestamp = self.timestamp_to_vcd(timestamp)
if signal.decoder:
var_value = self.decode_to_vcd(signal, value)
else:
var_value = value
self.vcd_writer.change(vcd_var, vcd_timestamp, var_value)
self.vcd_writer.change(vcd_var, timestamp, var_value)

def close(self, timestamp):
if self.vcd_writer is not None:
self.vcd_writer.close(self.timestamp_to_vcd(timestamp))
self.vcd_writer.close(timestamp)

if self.gtkw_save is not None:
self.gtkw_save.dumpfile(self.vcd_file.name)
Expand All @@ -158,11 +153,11 @@ def close(self, timestamp):

class _Timeline:
def __init__(self):
self.now = 0.0
self.now = 0
self.deadlines = dict()

def reset(self):
self.now = 0.0
self.now = 0
self.deadlines.clear()

def at(self, run_at, process):
Expand Down Expand Up @@ -265,6 +260,8 @@ def remove_trigger(self, process, signal):
del self.slots[index].waiters[process]

def wait_interval(self, process, interval):
# Internal timeline is in 1ps integeral units, intervals are public API and in floating point
interval = int(interval * 1e12) if interval is not None else None
self.timeline.delay(interval, process)

def commit(self, changed=None):
Expand Down

0 comments on commit b106d05

Please sign in to comment.