Skip to content

Commit 93d37f5

Browse files
authored
Merge pull request #4 from dau-dev/tkp/amstd
Add regression test for mixed clock edge, add amaranth shim for combined triggers
2 parents 6934875 + 9f5cd4e commit 93d37f5

2 files changed

Lines changed: 102 additions & 0 deletions

File tree

dau_sim/tests/test_cocotb_backend.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -956,3 +956,45 @@ async def test_coro():
956956
assert results == [1, 0]
957957
finally:
958958
self._teardown_cocotb()
959+
960+
def test_timer_and_edge_same_timestep(self):
961+
"""Timer+edge combination should complete when both happen together."""
962+
import cocotb
963+
964+
engine = self._setup_cocotb(_make_comb_module())
965+
try:
966+
from cocotb._gpi_triggers import RisingEdge, Timer
967+
from cocotb.task import Task
968+
from cocotb.triggers import Combine
969+
970+
result = []
971+
972+
async def driver():
973+
# Schedule a rising edge at the exact same time as Timer(100).
974+
await Timer(100, unit="step")
975+
cocotb.top.a.value = 1
976+
977+
async def waiter():
978+
await Combine(
979+
Timer(100, unit="step"),
980+
RisingEdge(cocotb.top.a),
981+
)
982+
result.append(engine._sim_time)
983+
engine.stop()
984+
985+
t1 = Task(driver())
986+
t2 = Task(waiter())
987+
cocotb._scheduler_inst._schedule_task_internal(t1)
988+
cocotb._scheduler_inst._schedule_task_internal(t2)
989+
cocotb.handle._start_write_scheduler()
990+
cocotb._scheduler_inst._event_loop()
991+
992+
engine._running = True
993+
engine.run(max_steps=100_000)
994+
995+
cocotb.handle._stop_write_scheduler()
996+
997+
assert len(result) == 1
998+
assert result[0] == 100
999+
finally:
1000+
self._teardown_cocotb()

dau_sim/tests/test_sim_seq.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,66 @@ def test_different_rates(self):
491491
assert slow_vals[-1] == 5, f"Expected slow_count=5, got {slow_vals[-1]}"
492492

493493

494+
def _make_mixed_edge_single_clock() -> Module:
495+
"""Two counters sharing one clock, one posedge and one negedge."""
496+
return Module(
497+
name="mixed_edge",
498+
ports=(
499+
Port(Signal("clk", Shape(1)), PortDirection.INPUT),
500+
Port(Signal("pos_count", Shape(8), init=0), PortDirection.OUTPUT),
501+
Port(Signal("neg_count", Shape(8), init=0), PortDirection.OUTPUT),
502+
),
503+
clock_domains=(
504+
ClockDomain("pos", clk="clk", edge=EdgePolarity.POSEDGE),
505+
ClockDomain("neg", clk="clk", edge=EdgePolarity.NEGEDGE),
506+
),
507+
seq_blocks=(
508+
SeqBlock(
509+
"pos",
510+
stmts=(
511+
Assign(
512+
"pos_count",
513+
Binary(
514+
Shape(8),
515+
BinaryOp.ADD,
516+
SignalRef(Shape(8), "pos_count"),
517+
Const(Shape(8), 1),
518+
),
519+
),
520+
),
521+
),
522+
SeqBlock(
523+
"neg",
524+
stmts=(
525+
Assign(
526+
"neg_count",
527+
Binary(
528+
Shape(8),
529+
BinaryOp.ADD,
530+
SignalRef(Shape(8), "neg_count"),
531+
Const(Shape(8), 1),
532+
),
533+
),
534+
),
535+
),
536+
),
537+
)
538+
539+
540+
class TestMixedClockEdges:
541+
def test_posedge_and_negedge_domains_progress_equally(self):
542+
"""Both domains should tick once per full period on shared clock."""
543+
m = _make_mixed_edge_single_clock()
544+
cm = compile_module(m)
545+
traces = cm.run(cycles=8)
546+
547+
pos_vals = [v for _, v in traces["pos_count"]]
548+
neg_vals = [v for _, v in traces["neg_count"]]
549+
550+
assert pos_vals[-1] == 8, f"Expected pos_count=8, got {pos_vals[-1]}"
551+
assert neg_vals[-1] == 8, f"Expected neg_count=8, got {neg_vals[-1]}"
552+
553+
494554
class TestLongRunCounter:
495555
def test_100_cycle_counter(self):
496556
"""Simulate 4-bit counter with reset for 100 cycles."""

0 commit comments

Comments
 (0)