From b6a49066ba10e38fd701ada8230a73784bbdbc6f Mon Sep 17 00:00:00 2001 From: Nikil-Shyamsunder Date: Sun, 15 Feb 2026 14:15:52 -0800 Subject: [PATCH 01/18] integrate with turnt --- .github/workflows/test.yml | 4 + examples/picorv32/unsigned_mul.rt | 1 + examples/serv/serv_regfile.rt | 1 + examples/tinyaes128/aes128.rt | 1 + examples/turnt.toml | 5 + justfile | 4 + protocols/src/scheduler.rs | 3 + .../adders/adder_d0/illegal_assignment.rt | 1 + .../adder_d0/illegal_observation_assertion.rt | 1 + .../illegal_observation_conditional.rt | 1 + .../tests/adders/adder_d1/add_incorrect.rt | 1 + .../adders/adder_d1/add_incorrect_implicit.rt | 1 + .../tests/adders/adder_d1/add_multitrace.rt | 1 + .../adders/adder_d1/both_threads_fail.rt | 1 + .../tests/adders/adder_d1/busy_wait_fail.rt | 1 + .../adders/adder_d1/didnt_end_in_step.rt | 1 + .../adders/adder_d1/double_fork_error.rt | 1 + .../adder_d1/first_fail_second_norun.rt | 1 + .../adders/adder_d1/first_thread_fails.rt | 1 + .../adders/adder_d1/fork_before_step_error.rt | 1 + .../adders/adder_d1/second_thread_fails.rt | 1 + .../wait_and_add_incorrect_implicit.rt | 1 + .../adders/adder_d2/both_threads_pass.rt | 1 + .../adders/adder_d2/no_dontcare_conflict.rt | 1 + protocols/tests/alus/alu_d1.rt | 1 + protocols/tests/alus/alu_d2.rt | 1 + .../bit_truncation/bit_truncation_fft_bug.rt | 1 + .../bit_truncation/bit_truncation_fft_fix.rt | 1 + .../bit_truncation/bit_truncation_sha_bug.rt | 1 + .../bit_truncation/bit_truncation_sha_fix.rt | 1 + .../failure_to_update/ftu_sha_bug.rt | 1 + .../failure_to_update/ftu_sha_fix.rt | 1 + .../signal_asynchrony/signal_async_bug.rt | 1 + .../signal_asynchrony/signal_async_fix.rt | 1 + .../use_without_valid_bug.rt | 1 + .../use_without_valid_fix.rt | 1 + protocols/tests/counters/counter.rt | 1 + protocols/tests/fifo/fifo.rt | 1 + protocols/tests/fifo/pop_before_push_fail.rt | 1 + protocols/tests/fifo/pop_empty_fail.rt | 1 + protocols/tests/fifo/push_pop_conflict.rt | 1 + .../dual_identity_d0_combdep.rt | 1 + .../dual_identity_d1/dual_identity_d1.rt | 1 + .../identities/identity_d1/explicit_fork.rt | 1 + .../identities/identity_d1/slicing_err.rt | 1 + .../identities/identity_d1/slicing_invalid.rt | 1 + .../identity_d2/single_thread_passes.rt | 1 + .../identity_d2/two_assignments_same_value.rt | 1 + .../two_different_assignments_error.rt | 1 + .../identities/identity_d2/two_fork_err.rt | 1 + .../identity_d2/two_fork_ill_formed.rt | 1 + protocols/tests/inverters/inverter_d0.rt | 1 + protocols/tests/multi/multi0/multi0.rt | 1 + .../tests/multi/multi0keep/multi0keep.rt | 1 + .../multi0keep2const/multi0keep2const.rt | 1 + .../tests/multi/multi2const/multi2const.rt | 1 + .../tests/multi/multi2multi/multi2multi.rt | 1 + .../tests/multi/multi_data/multi_data.rt | 1 + .../multipliers/mult_d2/both_threads_fail.rt | 1 + .../multipliers/mult_d2/both_threads_pass.rt | 1 + .../multipliers/mult_d2/first_thread_fails.rt | 1 + .../mult_d2/second_thread_fails.rt | 1 + .../tests/picorv32/unsigned_mul_no_reset.rt | 1 + ..._no_reset_thread_assignment_persistence.rt | 1 + protocols/tests/turnt.toml | 5 + scripts/roundtrip_case.py | 239 ++++++++++++++++++ turnt.toml | 5 + 67 files changed, 325 insertions(+) create mode 100644 examples/picorv32/unsigned_mul.rt create mode 100644 examples/serv/serv_regfile.rt create mode 100644 examples/tinyaes128/aes128.rt create mode 100644 protocols/tests/adders/adder_d0/illegal_assignment.rt create mode 100644 protocols/tests/adders/adder_d0/illegal_observation_assertion.rt create mode 100644 protocols/tests/adders/adder_d0/illegal_observation_conditional.rt create mode 100644 protocols/tests/adders/adder_d1/add_incorrect.rt create mode 100644 protocols/tests/adders/adder_d1/add_incorrect_implicit.rt create mode 100644 protocols/tests/adders/adder_d1/add_multitrace.rt create mode 100644 protocols/tests/adders/adder_d1/both_threads_fail.rt create mode 100644 protocols/tests/adders/adder_d1/busy_wait_fail.rt create mode 100644 protocols/tests/adders/adder_d1/didnt_end_in_step.rt create mode 100644 protocols/tests/adders/adder_d1/double_fork_error.rt create mode 100644 protocols/tests/adders/adder_d1/first_fail_second_norun.rt create mode 100644 protocols/tests/adders/adder_d1/first_thread_fails.rt create mode 100644 protocols/tests/adders/adder_d1/fork_before_step_error.rt create mode 100644 protocols/tests/adders/adder_d1/second_thread_fails.rt create mode 100644 protocols/tests/adders/adder_d1/wait_and_add_incorrect_implicit.rt create mode 100644 protocols/tests/adders/adder_d2/both_threads_pass.rt create mode 100644 protocols/tests/adders/adder_d2/no_dontcare_conflict.rt create mode 100644 protocols/tests/alus/alu_d1.rt create mode 100644 protocols/tests/alus/alu_d2.rt create mode 100644 protocols/tests/brave_new_world/bit_truncation/bit_truncation_fft_bug.rt create mode 100644 protocols/tests/brave_new_world/bit_truncation/bit_truncation_fft_fix.rt create mode 100644 protocols/tests/brave_new_world/bit_truncation/bit_truncation_sha_bug.rt create mode 100644 protocols/tests/brave_new_world/bit_truncation/bit_truncation_sha_fix.rt create mode 100644 protocols/tests/brave_new_world/failure_to_update/ftu_sha_bug.rt create mode 100644 protocols/tests/brave_new_world/failure_to_update/ftu_sha_fix.rt create mode 100644 protocols/tests/brave_new_world/signal_asynchrony/signal_async_bug.rt create mode 100644 protocols/tests/brave_new_world/signal_asynchrony/signal_async_fix.rt create mode 100644 protocols/tests/brave_new_world/use_without_valid/use_without_valid_bug.rt create mode 100644 protocols/tests/brave_new_world/use_without_valid/use_without_valid_fix.rt create mode 100644 protocols/tests/counters/counter.rt create mode 100644 protocols/tests/fifo/fifo.rt create mode 100644 protocols/tests/fifo/pop_before_push_fail.rt create mode 100644 protocols/tests/fifo/pop_empty_fail.rt create mode 100644 protocols/tests/fifo/push_pop_conflict.rt create mode 100644 protocols/tests/identities/dual_identity_d0/dual_identity_d0_combdep.rt create mode 100644 protocols/tests/identities/dual_identity_d1/dual_identity_d1.rt create mode 100644 protocols/tests/identities/identity_d1/explicit_fork.rt create mode 100644 protocols/tests/identities/identity_d1/slicing_err.rt create mode 100644 protocols/tests/identities/identity_d1/slicing_invalid.rt create mode 100644 protocols/tests/identities/identity_d2/single_thread_passes.rt create mode 100644 protocols/tests/identities/identity_d2/two_assignments_same_value.rt create mode 100644 protocols/tests/identities/identity_d2/two_different_assignments_error.rt create mode 100644 protocols/tests/identities/identity_d2/two_fork_err.rt create mode 100644 protocols/tests/identities/identity_d2/two_fork_ill_formed.rt create mode 100644 protocols/tests/inverters/inverter_d0.rt create mode 100644 protocols/tests/multi/multi0/multi0.rt create mode 100644 protocols/tests/multi/multi0keep/multi0keep.rt create mode 100644 protocols/tests/multi/multi0keep2const/multi0keep2const.rt create mode 100644 protocols/tests/multi/multi2const/multi2const.rt create mode 100644 protocols/tests/multi/multi2multi/multi2multi.rt create mode 100644 protocols/tests/multi/multi_data/multi_data.rt create mode 100644 protocols/tests/multipliers/mult_d2/both_threads_fail.rt create mode 100644 protocols/tests/multipliers/mult_d2/both_threads_pass.rt create mode 100644 protocols/tests/multipliers/mult_d2/first_thread_fails.rt create mode 100644 protocols/tests/multipliers/mult_d2/second_thread_fails.rt create mode 100644 protocols/tests/picorv32/unsigned_mul_no_reset.rt create mode 100644 protocols/tests/picorv32/unsigned_mul_no_reset_thread_assignment_persistence.rt create mode 100644 scripts/roundtrip_case.py diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3ee8a0ca..238ac88d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -34,6 +34,10 @@ jobs: run: turnt --env interp $(find . -type f -name '*.tx') - name: Run Turnt tests for monitor run: turnt --env monitor $(find . -type f -name '*.prot') + - name: Run Turnt roundtrip tests (non-blocking) + if: matrix.toolchain == 'stable' + continue-on-error: true + run: turnt --env roundtrip $(find . -type f -name '*.tx') msrv: name: Check Minimum Rust Version for protocols library diff --git a/examples/picorv32/unsigned_mul.rt b/examples/picorv32/unsigned_mul.rt new file mode 100644 index 00000000..feb77132 --- /dev/null +++ b/examples/picorv32/unsigned_mul.rt @@ -0,0 +1 @@ +Roundtrip trace 0 executed successfully! diff --git a/examples/serv/serv_regfile.rt b/examples/serv/serv_regfile.rt new file mode 100644 index 00000000..feb77132 --- /dev/null +++ b/examples/serv/serv_regfile.rt @@ -0,0 +1 @@ +Roundtrip trace 0 executed successfully! diff --git a/examples/tinyaes128/aes128.rt b/examples/tinyaes128/aes128.rt new file mode 100644 index 00000000..feb77132 --- /dev/null +++ b/examples/tinyaes128/aes128.rt @@ -0,0 +1 @@ +Roundtrip trace 0 executed successfully! diff --git a/examples/turnt.toml b/examples/turnt.toml index 8c08bf47..36dcf31a 100644 --- a/examples/turnt.toml +++ b/examples/turnt.toml @@ -1,2 +1,7 @@ [envs.interp] command = "cargo run --package protocols-interp -- --color never --transactions {filename} {args}" + +[envs.roundtrip] +command = "python3 ../scripts/roundtrip_case.py {filename}" +binary = true +output.rt = "-" diff --git a/justfile b/justfile index 9ae3743c..1d6621c0 100644 --- a/justfile +++ b/justfile @@ -7,6 +7,10 @@ interp: monitor: turnt --env monitor $(find . -type f -name '*.prot') +# Run roundtrip checks (interp -> fst -> monitor) for all transactions +roundtrip: + turnt --env roundtrip $(find . -type f -name '*.tx') + # Run Turnt tests for the monitor based on the Brave New World artifacts bnw_monitor: turnt --env monitor $(find monitor/tests/fpga-debugging -type f -name '*.prot') diff --git a/protocols/src/scheduler.rs b/protocols/src/scheduler.rs index bb87d0c0..a8eb7789 100644 --- a/protocols/src/scheduler.rs +++ b/protocols/src/scheduler.rs @@ -403,6 +403,9 @@ impl<'a> Scheduler<'a> { } } + // Emit one trailing empty cycle so all generated .fst files having timing information + self.evaluator.sim_step(); + // Emit diagnostics for all errors after execution is complete self.emit_all_diagnostics(); self.results.clone() diff --git a/protocols/tests/adders/adder_d0/illegal_assignment.rt b/protocols/tests/adders/adder_d0/illegal_assignment.rt new file mode 100644 index 00000000..d79ced8c --- /dev/null +++ b/protocols/tests/adders/adder_d0/illegal_assignment.rt @@ -0,0 +1 @@ +SKIP: non-zero // RETURN diff --git a/protocols/tests/adders/adder_d0/illegal_observation_assertion.rt b/protocols/tests/adders/adder_d0/illegal_observation_assertion.rt new file mode 100644 index 00000000..d79ced8c --- /dev/null +++ b/protocols/tests/adders/adder_d0/illegal_observation_assertion.rt @@ -0,0 +1 @@ +SKIP: non-zero // RETURN diff --git a/protocols/tests/adders/adder_d0/illegal_observation_conditional.rt b/protocols/tests/adders/adder_d0/illegal_observation_conditional.rt new file mode 100644 index 00000000..d79ced8c --- /dev/null +++ b/protocols/tests/adders/adder_d0/illegal_observation_conditional.rt @@ -0,0 +1 @@ +SKIP: non-zero // RETURN diff --git a/protocols/tests/adders/adder_d1/add_incorrect.rt b/protocols/tests/adders/adder_d1/add_incorrect.rt new file mode 100644 index 00000000..d79ced8c --- /dev/null +++ b/protocols/tests/adders/adder_d1/add_incorrect.rt @@ -0,0 +1 @@ +SKIP: non-zero // RETURN diff --git a/protocols/tests/adders/adder_d1/add_incorrect_implicit.rt b/protocols/tests/adders/adder_d1/add_incorrect_implicit.rt new file mode 100644 index 00000000..d79ced8c --- /dev/null +++ b/protocols/tests/adders/adder_d1/add_incorrect_implicit.rt @@ -0,0 +1 @@ +SKIP: non-zero // RETURN diff --git a/protocols/tests/adders/adder_d1/add_multitrace.rt b/protocols/tests/adders/adder_d1/add_multitrace.rt new file mode 100644 index 00000000..d79ced8c --- /dev/null +++ b/protocols/tests/adders/adder_d1/add_multitrace.rt @@ -0,0 +1 @@ +SKIP: non-zero // RETURN diff --git a/protocols/tests/adders/adder_d1/both_threads_fail.rt b/protocols/tests/adders/adder_d1/both_threads_fail.rt new file mode 100644 index 00000000..d79ced8c --- /dev/null +++ b/protocols/tests/adders/adder_d1/both_threads_fail.rt @@ -0,0 +1 @@ +SKIP: non-zero // RETURN diff --git a/protocols/tests/adders/adder_d1/busy_wait_fail.rt b/protocols/tests/adders/adder_d1/busy_wait_fail.rt new file mode 100644 index 00000000..d79ced8c --- /dev/null +++ b/protocols/tests/adders/adder_d1/busy_wait_fail.rt @@ -0,0 +1 @@ +SKIP: non-zero // RETURN diff --git a/protocols/tests/adders/adder_d1/didnt_end_in_step.rt b/protocols/tests/adders/adder_d1/didnt_end_in_step.rt new file mode 100644 index 00000000..d79ced8c --- /dev/null +++ b/protocols/tests/adders/adder_d1/didnt_end_in_step.rt @@ -0,0 +1 @@ +SKIP: non-zero // RETURN diff --git a/protocols/tests/adders/adder_d1/double_fork_error.rt b/protocols/tests/adders/adder_d1/double_fork_error.rt new file mode 100644 index 00000000..d79ced8c --- /dev/null +++ b/protocols/tests/adders/adder_d1/double_fork_error.rt @@ -0,0 +1 @@ +SKIP: non-zero // RETURN diff --git a/protocols/tests/adders/adder_d1/first_fail_second_norun.rt b/protocols/tests/adders/adder_d1/first_fail_second_norun.rt new file mode 100644 index 00000000..d79ced8c --- /dev/null +++ b/protocols/tests/adders/adder_d1/first_fail_second_norun.rt @@ -0,0 +1 @@ +SKIP: non-zero // RETURN diff --git a/protocols/tests/adders/adder_d1/first_thread_fails.rt b/protocols/tests/adders/adder_d1/first_thread_fails.rt new file mode 100644 index 00000000..d79ced8c --- /dev/null +++ b/protocols/tests/adders/adder_d1/first_thread_fails.rt @@ -0,0 +1 @@ +SKIP: non-zero // RETURN diff --git a/protocols/tests/adders/adder_d1/fork_before_step_error.rt b/protocols/tests/adders/adder_d1/fork_before_step_error.rt new file mode 100644 index 00000000..d79ced8c --- /dev/null +++ b/protocols/tests/adders/adder_d1/fork_before_step_error.rt @@ -0,0 +1 @@ +SKIP: non-zero // RETURN diff --git a/protocols/tests/adders/adder_d1/second_thread_fails.rt b/protocols/tests/adders/adder_d1/second_thread_fails.rt new file mode 100644 index 00000000..d79ced8c --- /dev/null +++ b/protocols/tests/adders/adder_d1/second_thread_fails.rt @@ -0,0 +1 @@ +SKIP: non-zero // RETURN diff --git a/protocols/tests/adders/adder_d1/wait_and_add_incorrect_implicit.rt b/protocols/tests/adders/adder_d1/wait_and_add_incorrect_implicit.rt new file mode 100644 index 00000000..d79ced8c --- /dev/null +++ b/protocols/tests/adders/adder_d1/wait_and_add_incorrect_implicit.rt @@ -0,0 +1 @@ +SKIP: non-zero // RETURN diff --git a/protocols/tests/adders/adder_d2/both_threads_pass.rt b/protocols/tests/adders/adder_d2/both_threads_pass.rt new file mode 100644 index 00000000..feb77132 --- /dev/null +++ b/protocols/tests/adders/adder_d2/both_threads_pass.rt @@ -0,0 +1 @@ +Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/adders/adder_d2/no_dontcare_conflict.rt b/protocols/tests/adders/adder_d2/no_dontcare_conflict.rt new file mode 100644 index 00000000..d79ced8c --- /dev/null +++ b/protocols/tests/adders/adder_d2/no_dontcare_conflict.rt @@ -0,0 +1 @@ +SKIP: non-zero // RETURN diff --git a/protocols/tests/alus/alu_d1.rt b/protocols/tests/alus/alu_d1.rt new file mode 100644 index 00000000..feb77132 --- /dev/null +++ b/protocols/tests/alus/alu_d1.rt @@ -0,0 +1 @@ +Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/alus/alu_d2.rt b/protocols/tests/alus/alu_d2.rt new file mode 100644 index 00000000..feb77132 --- /dev/null +++ b/protocols/tests/alus/alu_d2.rt @@ -0,0 +1 @@ +Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/brave_new_world/bit_truncation/bit_truncation_fft_bug.rt b/protocols/tests/brave_new_world/bit_truncation/bit_truncation_fft_bug.rt new file mode 100644 index 00000000..d79ced8c --- /dev/null +++ b/protocols/tests/brave_new_world/bit_truncation/bit_truncation_fft_bug.rt @@ -0,0 +1 @@ +SKIP: non-zero // RETURN diff --git a/protocols/tests/brave_new_world/bit_truncation/bit_truncation_fft_fix.rt b/protocols/tests/brave_new_world/bit_truncation/bit_truncation_fft_fix.rt new file mode 100644 index 00000000..feb77132 --- /dev/null +++ b/protocols/tests/brave_new_world/bit_truncation/bit_truncation_fft_fix.rt @@ -0,0 +1 @@ +Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/brave_new_world/bit_truncation/bit_truncation_sha_bug.rt b/protocols/tests/brave_new_world/bit_truncation/bit_truncation_sha_bug.rt new file mode 100644 index 00000000..d79ced8c --- /dev/null +++ b/protocols/tests/brave_new_world/bit_truncation/bit_truncation_sha_bug.rt @@ -0,0 +1 @@ +SKIP: non-zero // RETURN diff --git a/protocols/tests/brave_new_world/bit_truncation/bit_truncation_sha_fix.rt b/protocols/tests/brave_new_world/bit_truncation/bit_truncation_sha_fix.rt new file mode 100644 index 00000000..feb77132 --- /dev/null +++ b/protocols/tests/brave_new_world/bit_truncation/bit_truncation_sha_fix.rt @@ -0,0 +1 @@ +Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/brave_new_world/failure_to_update/ftu_sha_bug.rt b/protocols/tests/brave_new_world/failure_to_update/ftu_sha_bug.rt new file mode 100644 index 00000000..d79ced8c --- /dev/null +++ b/protocols/tests/brave_new_world/failure_to_update/ftu_sha_bug.rt @@ -0,0 +1 @@ +SKIP: non-zero // RETURN diff --git a/protocols/tests/brave_new_world/failure_to_update/ftu_sha_fix.rt b/protocols/tests/brave_new_world/failure_to_update/ftu_sha_fix.rt new file mode 100644 index 00000000..feb77132 --- /dev/null +++ b/protocols/tests/brave_new_world/failure_to_update/ftu_sha_fix.rt @@ -0,0 +1 @@ +Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/brave_new_world/signal_asynchrony/signal_async_bug.rt b/protocols/tests/brave_new_world/signal_asynchrony/signal_async_bug.rt new file mode 100644 index 00000000..d79ced8c --- /dev/null +++ b/protocols/tests/brave_new_world/signal_asynchrony/signal_async_bug.rt @@ -0,0 +1 @@ +SKIP: non-zero // RETURN diff --git a/protocols/tests/brave_new_world/signal_asynchrony/signal_async_fix.rt b/protocols/tests/brave_new_world/signal_asynchrony/signal_async_fix.rt new file mode 100644 index 00000000..feb77132 --- /dev/null +++ b/protocols/tests/brave_new_world/signal_asynchrony/signal_async_fix.rt @@ -0,0 +1 @@ +Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/brave_new_world/use_without_valid/use_without_valid_bug.rt b/protocols/tests/brave_new_world/use_without_valid/use_without_valid_bug.rt new file mode 100644 index 00000000..d79ced8c --- /dev/null +++ b/protocols/tests/brave_new_world/use_without_valid/use_without_valid_bug.rt @@ -0,0 +1 @@ +SKIP: non-zero // RETURN diff --git a/protocols/tests/brave_new_world/use_without_valid/use_without_valid_fix.rt b/protocols/tests/brave_new_world/use_without_valid/use_without_valid_fix.rt new file mode 100644 index 00000000..feb77132 --- /dev/null +++ b/protocols/tests/brave_new_world/use_without_valid/use_without_valid_fix.rt @@ -0,0 +1 @@ +Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/counters/counter.rt b/protocols/tests/counters/counter.rt new file mode 100644 index 00000000..feb77132 --- /dev/null +++ b/protocols/tests/counters/counter.rt @@ -0,0 +1 @@ +Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/fifo/fifo.rt b/protocols/tests/fifo/fifo.rt new file mode 100644 index 00000000..feb77132 --- /dev/null +++ b/protocols/tests/fifo/fifo.rt @@ -0,0 +1 @@ +Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/fifo/pop_before_push_fail.rt b/protocols/tests/fifo/pop_before_push_fail.rt new file mode 100644 index 00000000..d79ced8c --- /dev/null +++ b/protocols/tests/fifo/pop_before_push_fail.rt @@ -0,0 +1 @@ +SKIP: non-zero // RETURN diff --git a/protocols/tests/fifo/pop_empty_fail.rt b/protocols/tests/fifo/pop_empty_fail.rt new file mode 100644 index 00000000..d79ced8c --- /dev/null +++ b/protocols/tests/fifo/pop_empty_fail.rt @@ -0,0 +1 @@ +SKIP: non-zero // RETURN diff --git a/protocols/tests/fifo/push_pop_conflict.rt b/protocols/tests/fifo/push_pop_conflict.rt new file mode 100644 index 00000000..d79ced8c --- /dev/null +++ b/protocols/tests/fifo/push_pop_conflict.rt @@ -0,0 +1 @@ +SKIP: non-zero // RETURN diff --git a/protocols/tests/identities/dual_identity_d0/dual_identity_d0_combdep.rt b/protocols/tests/identities/dual_identity_d0/dual_identity_d0_combdep.rt new file mode 100644 index 00000000..d79ced8c --- /dev/null +++ b/protocols/tests/identities/dual_identity_d0/dual_identity_d0_combdep.rt @@ -0,0 +1 @@ +SKIP: non-zero // RETURN diff --git a/protocols/tests/identities/dual_identity_d1/dual_identity_d1.rt b/protocols/tests/identities/dual_identity_d1/dual_identity_d1.rt new file mode 100644 index 00000000..d79ced8c --- /dev/null +++ b/protocols/tests/identities/dual_identity_d1/dual_identity_d1.rt @@ -0,0 +1 @@ +SKIP: non-zero // RETURN diff --git a/protocols/tests/identities/identity_d1/explicit_fork.rt b/protocols/tests/identities/identity_d1/explicit_fork.rt new file mode 100644 index 00000000..d79ced8c --- /dev/null +++ b/protocols/tests/identities/identity_d1/explicit_fork.rt @@ -0,0 +1 @@ +SKIP: non-zero // RETURN diff --git a/protocols/tests/identities/identity_d1/slicing_err.rt b/protocols/tests/identities/identity_d1/slicing_err.rt new file mode 100644 index 00000000..d79ced8c --- /dev/null +++ b/protocols/tests/identities/identity_d1/slicing_err.rt @@ -0,0 +1 @@ +SKIP: non-zero // RETURN diff --git a/protocols/tests/identities/identity_d1/slicing_invalid.rt b/protocols/tests/identities/identity_d1/slicing_invalid.rt new file mode 100644 index 00000000..d79ced8c --- /dev/null +++ b/protocols/tests/identities/identity_d1/slicing_invalid.rt @@ -0,0 +1 @@ +SKIP: non-zero // RETURN diff --git a/protocols/tests/identities/identity_d2/single_thread_passes.rt b/protocols/tests/identities/identity_d2/single_thread_passes.rt new file mode 100644 index 00000000..feb77132 --- /dev/null +++ b/protocols/tests/identities/identity_d2/single_thread_passes.rt @@ -0,0 +1 @@ +Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/identities/identity_d2/two_assignments_same_value.rt b/protocols/tests/identities/identity_d2/two_assignments_same_value.rt new file mode 100644 index 00000000..feb77132 --- /dev/null +++ b/protocols/tests/identities/identity_d2/two_assignments_same_value.rt @@ -0,0 +1 @@ +Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/identities/identity_d2/two_different_assignments_error.rt b/protocols/tests/identities/identity_d2/two_different_assignments_error.rt new file mode 100644 index 00000000..d79ced8c --- /dev/null +++ b/protocols/tests/identities/identity_d2/two_different_assignments_error.rt @@ -0,0 +1 @@ +SKIP: non-zero // RETURN diff --git a/protocols/tests/identities/identity_d2/two_fork_err.rt b/protocols/tests/identities/identity_d2/two_fork_err.rt new file mode 100644 index 00000000..d79ced8c --- /dev/null +++ b/protocols/tests/identities/identity_d2/two_fork_err.rt @@ -0,0 +1 @@ +SKIP: non-zero // RETURN diff --git a/protocols/tests/identities/identity_d2/two_fork_ill_formed.rt b/protocols/tests/identities/identity_d2/two_fork_ill_formed.rt new file mode 100644 index 00000000..d79ced8c --- /dev/null +++ b/protocols/tests/identities/identity_d2/two_fork_ill_formed.rt @@ -0,0 +1 @@ +SKIP: non-zero // RETURN diff --git a/protocols/tests/inverters/inverter_d0.rt b/protocols/tests/inverters/inverter_d0.rt new file mode 100644 index 00000000..d79ced8c --- /dev/null +++ b/protocols/tests/inverters/inverter_d0.rt @@ -0,0 +1 @@ +SKIP: non-zero // RETURN diff --git a/protocols/tests/multi/multi0/multi0.rt b/protocols/tests/multi/multi0/multi0.rt new file mode 100644 index 00000000..feb77132 --- /dev/null +++ b/protocols/tests/multi/multi0/multi0.rt @@ -0,0 +1 @@ +Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/multi/multi0keep/multi0keep.rt b/protocols/tests/multi/multi0keep/multi0keep.rt new file mode 100644 index 00000000..feb77132 --- /dev/null +++ b/protocols/tests/multi/multi0keep/multi0keep.rt @@ -0,0 +1 @@ +Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/multi/multi0keep2const/multi0keep2const.rt b/protocols/tests/multi/multi0keep2const/multi0keep2const.rt new file mode 100644 index 00000000..feb77132 --- /dev/null +++ b/protocols/tests/multi/multi0keep2const/multi0keep2const.rt @@ -0,0 +1 @@ +Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/multi/multi2const/multi2const.rt b/protocols/tests/multi/multi2const/multi2const.rt new file mode 100644 index 00000000..feb77132 --- /dev/null +++ b/protocols/tests/multi/multi2const/multi2const.rt @@ -0,0 +1 @@ +Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/multi/multi2multi/multi2multi.rt b/protocols/tests/multi/multi2multi/multi2multi.rt new file mode 100644 index 00000000..feb77132 --- /dev/null +++ b/protocols/tests/multi/multi2multi/multi2multi.rt @@ -0,0 +1 @@ +Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/multi/multi_data/multi_data.rt b/protocols/tests/multi/multi_data/multi_data.rt new file mode 100644 index 00000000..feb77132 --- /dev/null +++ b/protocols/tests/multi/multi_data/multi_data.rt @@ -0,0 +1 @@ +Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/multipliers/mult_d2/both_threads_fail.rt b/protocols/tests/multipliers/mult_d2/both_threads_fail.rt new file mode 100644 index 00000000..d79ced8c --- /dev/null +++ b/protocols/tests/multipliers/mult_d2/both_threads_fail.rt @@ -0,0 +1 @@ +SKIP: non-zero // RETURN diff --git a/protocols/tests/multipliers/mult_d2/both_threads_pass.rt b/protocols/tests/multipliers/mult_d2/both_threads_pass.rt new file mode 100644 index 00000000..feb77132 --- /dev/null +++ b/protocols/tests/multipliers/mult_d2/both_threads_pass.rt @@ -0,0 +1 @@ +Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/multipliers/mult_d2/first_thread_fails.rt b/protocols/tests/multipliers/mult_d2/first_thread_fails.rt new file mode 100644 index 00000000..d79ced8c --- /dev/null +++ b/protocols/tests/multipliers/mult_d2/first_thread_fails.rt @@ -0,0 +1 @@ +SKIP: non-zero // RETURN diff --git a/protocols/tests/multipliers/mult_d2/second_thread_fails.rt b/protocols/tests/multipliers/mult_d2/second_thread_fails.rt new file mode 100644 index 00000000..d79ced8c --- /dev/null +++ b/protocols/tests/multipliers/mult_d2/second_thread_fails.rt @@ -0,0 +1 @@ +SKIP: non-zero // RETURN diff --git a/protocols/tests/picorv32/unsigned_mul_no_reset.rt b/protocols/tests/picorv32/unsigned_mul_no_reset.rt new file mode 100644 index 00000000..d79ced8c --- /dev/null +++ b/protocols/tests/picorv32/unsigned_mul_no_reset.rt @@ -0,0 +1 @@ +SKIP: non-zero // RETURN diff --git a/protocols/tests/picorv32/unsigned_mul_no_reset_thread_assignment_persistence.rt b/protocols/tests/picorv32/unsigned_mul_no_reset_thread_assignment_persistence.rt new file mode 100644 index 00000000..d79ced8c --- /dev/null +++ b/protocols/tests/picorv32/unsigned_mul_no_reset_thread_assignment_persistence.rt @@ -0,0 +1 @@ +SKIP: non-zero // RETURN diff --git a/protocols/tests/turnt.toml b/protocols/tests/turnt.toml index 8c08bf47..3d80931f 100644 --- a/protocols/tests/turnt.toml +++ b/protocols/tests/turnt.toml @@ -1,2 +1,7 @@ [envs.interp] command = "cargo run --package protocols-interp -- --color never --transactions {filename} {args}" + +[envs.roundtrip] +command = "python3 ../../scripts/roundtrip_case.py {filename}" +binary = true +output.rt = "-" diff --git a/scripts/roundtrip_case.py b/scripts/roundtrip_case.py new file mode 100644 index 00000000..5fe62204 --- /dev/null +++ b/scripts/roundtrip_case.py @@ -0,0 +1,239 @@ +#!/usr/bin/env python3 +"""Run one roundtrip check for a single .tx file. + +Usage: + python3 scripts/roundtrip_case.py path/to/test.tx +""" + +import os +import re +import subprocess +import sys +import tempfile +from pathlib import Path +from typing import Optional + + +def parse_arg(args: str, flag: str) -> Optional[str]: + m = re.search(rf"--{flag}[= ](\S+)", args) + return m.group(1) if m else None + + +def extract_struct_name(prot_path: Path) -> Optional[str]: + m = re.search(r"^struct\s+([A-Za-z_]\w*)", prot_path.read_text(), re.MULTILINE) + return m.group(1) if m else None + + +def normalize_trace_line(line: str) -> str: + line = line.strip() + if "//" in line: + line = line.split("//", 1)[0].rstrip() + if not line: + return line + + m = re.fullmatch(r"([A-Za-z_]\w*)\s*\((.*)\)\s*;?", line) + if not m: + return line + + fn_name = m.group(1) + args_blob = m.group(2).strip() + if not args_blob: + return f"{fn_name}();" + + normalized_args = [] + for raw_arg in args_blob.split(","): + arg = raw_arg.strip().replace("_", "") + if re.fullmatch(r"0[bB][01]+", arg): + normalized_args.append(str(int(arg[2:], 2))) + elif re.fullmatch(r"0[xX][0-9a-fA-F]+", arg): + normalized_args.append(str(int(arg[2:], 16))) + elif re.fullmatch(r"\d+", arg): + normalized_args.append(str(int(arg, 10))) + else: + normalized_args.append(arg) + + return f"{fn_name}({', '.join(normalized_args)});" + + +def parse_trace_blocks(text: str) -> list[list[str]]: + traces: list[list[str]] = [] + in_trace = False + current: list[str] = [] + + for raw_line in text.splitlines(): + line = raw_line.strip() + if not in_trace: + if line == "trace {": + in_trace = True + current = [] + continue + + if line == "}": + traces.append(current) + in_trace = False + current = [] + continue + + normalized = normalize_trace_line(raw_line) + if normalized: + current.append(normalized) + + return traces + + +def collect_generated_fsts(base_fst: Path) -> list[Path]: + indexed: list[tuple[int, Path]] = [] + for path in base_fst.parent.glob(f"{base_fst.stem}_*{base_fst.suffix}"): + suffix = path.stem[len(base_fst.stem) + 1 :] + if suffix.isdigit(): + indexed.append((int(suffix), path)) + + if indexed: + return [path for _, path in sorted(indexed, key=lambda item: item[0])] + if base_fst.exists(): + return [base_fst] + return [] + + +def cleanup_generated_fsts(base_fst: Path) -> None: + for path in base_fst.parent.glob(f"{base_fst.stem}_*{base_fst.suffix}"): + try: + path.unlink() + except OSError: + pass + try: + base_fst.unlink() + except OSError: + pass + + +def fail(msg: str) -> int: + print(msg) + return 1 + + +def main() -> int: + if len(sys.argv) != 2: + print("Usage: roundtrip_case.py ") + return 2 + + tx_file = Path(sys.argv[1]).resolve() + if not tx_file.exists(): + return fail(f"Missing tx file: {tx_file}") + + tx_text = tx_file.read_text() + args_match = re.search(r"^// ARGS:\s*(.+)$", tx_text, re.MULTILINE) + if not args_match: + print("SKIP: missing // ARGS") + return 0 + args = args_match.group(1) + + return_match = re.search(r"^// RETURN:\s*(\d+)", tx_text, re.MULTILINE) + if return_match and int(return_match.group(1)) != 0: + print("SKIP: non-zero // RETURN") + return 0 + + prot_rel = parse_arg(args, "protocol") + verilog_rel = parse_arg(args, "verilog") + if not prot_rel or not verilog_rel: + print("SKIP: missing --protocol or --verilog in // ARGS") + return 0 + + base_dir = tx_file.parent + while base_dir != base_dir.parent and not (base_dir / "turnt.toml").exists(): + base_dir = base_dir.parent + if not (base_dir / "turnt.toml").exists(): + return fail(f"No turnt.toml found for {tx_file}") + + prot_file = (base_dir / prot_rel).resolve() + if not prot_file.exists(): + return fail(f"Missing protocol file: {prot_file}") + + struct_name = extract_struct_name(prot_file) + if not struct_name: + return fail(f"Could not find struct in protocol: {prot_file}") + + module_name = parse_arg(args, "module") + instance_name = module_name if module_name else Path(verilog_rel).stem + expected_traces = parse_trace_blocks(tx_text) + + fd, fst_file = tempfile.mkstemp(suffix=".fst") + os.close(fd) + os.unlink(fst_file) + fst_path = Path(fst_file) + + try: + interp_cmd = ( + "cargo run --quiet --package protocols-interp -- " + f"--color never --transactions {tx_file} {args} --fst {fst_file}" + ) + interp = subprocess.run( + interp_cmd, + shell=True, + cwd=base_dir, + capture_output=True, + text=True, + ) + if interp.returncode != 0: + return fail("Interpreter failed during roundtrip generation") + + generated_fsts = collect_generated_fsts(fst_path) + if not generated_fsts: + return fail("No waveform file generated by interpreter") + + for trace_idx, generated_fst in enumerate(generated_fsts): + if trace_idx >= len(expected_traces): + return fail( + f"Interpreter generated unexpected extra trace {trace_idx} for {tx_file}" + ) + + monitor_cmd = ( + "cargo run --quiet --package protocols-monitor -- " + f"-p {prot_file} --wave {generated_fst} " + f"--instances {instance_name}:{struct_name}" + ) + monitor = subprocess.run( + monitor_cmd, + shell=True, + cwd=base_dir, + capture_output=True, + text=True, + ) + if monitor.returncode != 0: + output = (monitor.stdout + monitor.stderr).strip() + return fail( + f"Monitor failed for trace {trace_idx} in {tx_file}\n{output}" + ) + + monitor_traces = parse_trace_blocks(monitor.stdout) + expected = expected_traces[trace_idx] + if expected not in monitor_traces: + expected_dump = "\n".join(expected) or "" + observed_dump = ( + "\n\n".join( + f"trace {i}:\n" + ("\n".join(t) if t else "") + for i, t in enumerate(monitor_traces) + ) + if monitor_traces + else "" + ) + return fail( + f"Trace mismatch for {tx_file} trace {trace_idx}\n" + f"Expected:\n{expected_dump}\n\nObserved:\n{observed_dump}" + ) + + print(f"Roundtrip trace {trace_idx} executed successfully!") + + if len(generated_fsts) < len(expected_traces): + return fail( + f"Interpreter generated only {len(generated_fsts)} traces, " + f"but source has {len(expected_traces)}" + ) + + return 0 + finally: + cleanup_generated_fsts(fst_path) + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/turnt.toml b/turnt.toml index 70a5c157..5695ee05 100644 --- a/turnt.toml +++ b/turnt.toml @@ -1 +1,6 @@ command = "cargo run --package protocols-interp -- --color never --transactions {filename} {args}" + +[envs.roundtrip] +command = "python3 scripts/roundtrip_case.py {filename}" +binary = true +output.rt = "-" From 6d5fbe1bff3dce571eeff7503382e91c8ef56328 Mon Sep 17 00:00:00 2001 From: Nikil-Shyamsunder Date: Sun, 15 Feb 2026 14:36:17 -0800 Subject: [PATCH 02/18] make roundtrip a separate job --- .github/workflows/test.yml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 238ac88d..3788e58c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -34,10 +34,16 @@ jobs: run: turnt --env interp $(find . -type f -name '*.tx') - name: Run Turnt tests for monitor run: turnt --env monitor $(find . -type f -name '*.prot') - - name: Run Turnt roundtrip tests (non-blocking) - if: matrix.toolchain == 'stable' - continue-on-error: true - run: turnt --env roundtrip $(find . -type f -name '*.tx') + + roundtrip: + name: Roundtrip + runs-on: ubuntu-24.04 + continue-on-error: true + steps: + - uses: actions/checkout@v4 + - uses: ./.github/actions/setup-test-environment + - name: Run Turnt roundtrip tests + run: turnt --env roundtrip $(find . -type f -name '*.tx') msrv: name: Check Minimum Rust Version for protocols library From 6b03d040bf3e7d399030500fc14bf1b15059fadc Mon Sep 17 00:00:00 2001 From: Ernest Ng Date: Sun, 15 Feb 2026 19:27:47 -0500 Subject: [PATCH 03/18] Use `uv run` instead of `python3` when invoking round-tripping script" " --- examples/turnt.toml | 2 +- protocols/tests/turnt.toml | 2 +- scripts/roundtrip_case.py | 2 +- turnt.toml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/turnt.toml b/examples/turnt.toml index 36dcf31a..c3d1ec29 100644 --- a/examples/turnt.toml +++ b/examples/turnt.toml @@ -2,6 +2,6 @@ command = "cargo run --package protocols-interp -- --color never --transactions {filename} {args}" [envs.roundtrip] -command = "python3 ../scripts/roundtrip_case.py {filename}" +command = "uv run ../scripts/roundtrip_case.py {filename}" binary = true output.rt = "-" diff --git a/protocols/tests/turnt.toml b/protocols/tests/turnt.toml index 3d80931f..c57fc6f0 100644 --- a/protocols/tests/turnt.toml +++ b/protocols/tests/turnt.toml @@ -2,6 +2,6 @@ command = "cargo run --package protocols-interp -- --color never --transactions {filename} {args}" [envs.roundtrip] -command = "python3 ../../scripts/roundtrip_case.py {filename}" +command = "uv run ../../scripts/roundtrip_case.py {filename}" binary = true output.rt = "-" diff --git a/scripts/roundtrip_case.py b/scripts/roundtrip_case.py index 5fe62204..940ec350 100644 --- a/scripts/roundtrip_case.py +++ b/scripts/roundtrip_case.py @@ -2,7 +2,7 @@ """Run one roundtrip check for a single .tx file. Usage: - python3 scripts/roundtrip_case.py path/to/test.tx + uv run scripts/roundtrip_case.py path/to/test.tx """ import os diff --git a/turnt.toml b/turnt.toml index 5695ee05..995ecba7 100644 --- a/turnt.toml +++ b/turnt.toml @@ -1,6 +1,6 @@ command = "cargo run --package protocols-interp -- --color never --transactions {filename} {args}" [envs.roundtrip] -command = "python3 scripts/roundtrip_case.py {filename}" +command = "uv run scripts/roundtrip_case.py {filename}" binary = true output.rt = "-" From bff8547003e296361dd5462eb1fef0793f927267 Mon Sep 17 00:00:00 2001 From: Nikil-Shyamsunder Date: Sun, 15 Feb 2026 17:34:13 -0800 Subject: [PATCH 04/18] add docstrings --- scripts/roundtrip_case.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/scripts/roundtrip_case.py b/scripts/roundtrip_case.py index 940ec350..4383ede2 100644 --- a/scripts/roundtrip_case.py +++ b/scripts/roundtrip_case.py @@ -15,16 +15,19 @@ def parse_arg(args: str, flag: str) -> Optional[str]: + """Extract a CLI flag value from a // ARGS line.""" m = re.search(rf"--{flag}[= ](\S+)", args) return m.group(1) if m else None def extract_struct_name(prot_path: Path) -> Optional[str]: + """Return the first struct name declared in a .prot file.""" m = re.search(r"^struct\s+([A-Za-z_]\w*)", prot_path.read_text(), re.MULTILINE) return m.group(1) if m else None def normalize_trace_line(line: str) -> str: + """Normalize one trace statement line for stable expected/actual comparison.""" line = line.strip() if "//" in line: line = line.split("//", 1)[0].rstrip() @@ -56,6 +59,7 @@ def normalize_trace_line(line: str) -> str: def parse_trace_blocks(text: str) -> list[list[str]]: + """Parse `trace { ... }` blocks and return normalized statements per trace.""" traces: list[list[str]] = [] in_trace = False current: list[str] = [] @@ -82,6 +86,7 @@ def parse_trace_blocks(text: str) -> list[list[str]]: def collect_generated_fsts(base_fst: Path) -> list[Path]: + """Collect generated FSTs for a run, preferring indexed multi-trace outputs.""" indexed: list[tuple[int, Path]] = [] for path in base_fst.parent.glob(f"{base_fst.stem}_*{base_fst.suffix}"): suffix = path.stem[len(base_fst.stem) + 1 :] @@ -96,6 +101,7 @@ def collect_generated_fsts(base_fst: Path) -> list[Path]: def cleanup_generated_fsts(base_fst: Path) -> None: + """Delete base and indexed temporary waveform files created for a test case.""" for path in base_fst.parent.glob(f"{base_fst.stem}_*{base_fst.suffix}"): try: path.unlink() @@ -108,11 +114,13 @@ def cleanup_generated_fsts(base_fst: Path) -> None: def fail(msg: str) -> int: + """Print a user-facing failure message and return a non-zero code.""" print(msg) return 1 def main() -> int: + """Execute one roundtrip check for a single `.tx` file.""" if len(sys.argv) != 2: print("Usage: roundtrip_case.py ") return 2 From 841b5e6c9200fa5ac1b15c4789163e6c358c1577 Mon Sep 17 00:00:00 2001 From: Nikil-Shyamsunder Date: Mon, 16 Feb 2026 18:13:18 -0800 Subject: [PATCH 05/18] add trace outputs for both failing and passing cases, remove ci skip --- .github/workflows/test.yml | 1 - examples/picorv32/unsigned_mul.rt | 20 ++++ examples/serv/serv_regfile.rt | 14 +++ examples/tinyaes128/aes128.rt | 14 +++ .../adders/adder_d0/add_combinational.rt | 6 ++ .../adders/adder_d1/both_threads_pass.rt | 6 ++ .../tests/adders/adder_d1/busy_wait_pass.rt | 5 + .../adders/adder_d1/loop_with_assigns.rt | 5 + .../tests/adders/adder_d1/nested_busy_wait.rt | 5 + .../adders/adder_d1/wait_and_add_correct.rt | 6 ++ .../adders/adder_d2/both_threads_pass.rt | 14 +++ protocols/tests/alus/alu_d1.rt | 20 ++++ protocols/tests/alus/alu_d2.rt | 20 ++++ .../bit_truncation/bit_truncation_fft_fix.rt | 12 +++ .../bit_truncation/bit_truncation_sha_fix.rt | 12 +++ .../failure_to_update/ftu_sha_fix.rt | 12 +++ .../signal_asynchrony/signal_async_fix.rt | 12 +++ .../use_without_valid_fix.rt | 12 +++ protocols/tests/counters/counter.rt | 12 +++ protocols/tests/fifo/fifo.rt | 22 +++++ protocols/tests/fifo/push_pop_identity_ok.rt | 18 ++++ protocols/tests/fifo/push_pop_loop_empty.rt | 5 + .../tests/fifo/push_pop_loop_not_empty.rt | 5 + .../identity_d0/passthrough_combdep.rt | 12 +++ .../identities/identity_d1/slicing_ok.rt | 11 +++ .../identity_d2/single_thread_passes.rt | 12 +++ .../identity_d2/two_assignments_same_value.rt | 20 ++++ protocols/tests/multi/multi0/multi0.rt | 12 +++ .../tests/multi/multi0keep/multi0keep.rt | 12 +++ .../multi0keep2const/multi0keep2const.rt | 12 +++ .../tests/multi/multi2const/multi2const.rt | 12 +++ .../tests/multi/multi2multi/multi2multi.rt | 12 +++ .../tests/multi/multi_data/multi_data.rt | 12 +++ .../multipliers/mult_d2/both_threads_pass.rt | 14 +++ scripts/roundtrip_case.py | 94 ++++++++++++++----- 35 files changed, 466 insertions(+), 27 deletions(-) create mode 100644 protocols/tests/adders/adder_d0/add_combinational.rt create mode 100644 protocols/tests/adders/adder_d1/both_threads_pass.rt create mode 100644 protocols/tests/adders/adder_d1/busy_wait_pass.rt create mode 100644 protocols/tests/adders/adder_d1/loop_with_assigns.rt create mode 100644 protocols/tests/adders/adder_d1/nested_busy_wait.rt create mode 100644 protocols/tests/adders/adder_d1/wait_and_add_correct.rt create mode 100644 protocols/tests/fifo/push_pop_identity_ok.rt create mode 100644 protocols/tests/fifo/push_pop_loop_empty.rt create mode 100644 protocols/tests/fifo/push_pop_loop_not_empty.rt create mode 100644 protocols/tests/identities/identity_d0/passthrough_combdep.rt create mode 100644 protocols/tests/identities/identity_d1/slicing_ok.rt diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3788e58c..4a6e5f44 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -38,7 +38,6 @@ jobs: roundtrip: name: Roundtrip runs-on: ubuntu-24.04 - continue-on-error: true steps: - uses: actions/checkout@v4 - uses: ./.github/actions/setup-test-environment diff --git a/examples/picorv32/unsigned_mul.rt b/examples/picorv32/unsigned_mul.rt index feb77132..8396d5a4 100644 --- a/examples/picorv32/unsigned_mul.rt +++ b/examples/picorv32/unsigned_mul.rt @@ -1 +1,21 @@ +trace_block: 0 +interpreter_trace: +trace { + pcpi_mul_reset(); + pcpi_mul(1, 1, 1); + pcpi_mul(1, 100, 100); + pcpi_mul(100, 1, 100); + pcpi_mul(33554483, 200, 2415929304); +} + +monitor_stdout: +// trace 0 +trace { + pcpi_mul_reset(); + pcpi_mul(1, 1, 1); + pcpi_mul(1, 100, 100); + pcpi_mul(100, 1, 100); + pcpi_mul(33554483, 200, 2415929304); +} + Roundtrip trace 0 executed successfully! diff --git a/examples/serv/serv_regfile.rt b/examples/serv/serv_regfile.rt index feb77132..df19af3c 100644 --- a/examples/serv/serv_regfile.rt +++ b/examples/serv/serv_regfile.rt @@ -1 +1,15 @@ +trace_block: 0 +interpreter_trace: +trace { + read_write(0, 0, 0, 0, 1, 5, 3735928559); + read_write(5, 3735928559, 0, 0, 0, 0, 0); +} + +monitor_stdout: +// trace 0 +trace { + read_write(0, 0, 0, 0, 1, 5, 3735928559); + read_write(5, 3735928559, 0, 0, 0, 0, 0); +} + Roundtrip trace 0 executed successfully! diff --git a/examples/tinyaes128/aes128.rt b/examples/tinyaes128/aes128.rt index feb77132..a3da5dd3 100644 --- a/examples/tinyaes128/aes128.rt +++ b/examples/tinyaes128/aes128.rt @@ -1 +1,15 @@ +trace_block: 0 +interpreter_trace: +trace { + aes128(5233100606242806050955395731361295, 88962710306127702866241727433142015, 140591190147677442632770771134392354138); + aes128(0, 0, 136792598789324718765670228683992083246); +} + +monitor_stdout: +// trace 0 +trace { + aes128(5233100606242806050955395731361295, 88962710306127702866241727433142015, 140591190147677442632770771134392354138); + aes128(0, 0, 136792598789324718765670228683992083246); +} + Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/adders/adder_d0/add_combinational.rt b/protocols/tests/adders/adder_d0/add_combinational.rt new file mode 100644 index 00000000..d68b7705 --- /dev/null +++ b/protocols/tests/adders/adder_d0/add_combinational.rt @@ -0,0 +1,6 @@ +trace_block: 0 +monitor_error: +thread 'main' panicked at monitor/src/interpreter.rs:65:17: +Transaction `add_combinational_illegal_observation_in_conditional`, cycle 0: Unable to find value for b (symbol5) in args_mapping, which is { (symbol4) a: 100 +(symbol6) s: 300 } +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/protocols/tests/adders/adder_d1/both_threads_pass.rt b/protocols/tests/adders/adder_d1/both_threads_pass.rt new file mode 100644 index 00000000..1804aed6 --- /dev/null +++ b/protocols/tests/adders/adder_d1/both_threads_pass.rt @@ -0,0 +1,6 @@ +trace_block: 0 +monitor_error: +All schedulers failed: No transactions match the waveform for DUT `Adder` +Failure at cycle 1: No transactions match the waveform in `.roundtrip_tmp/adders-adder_d1-both_threads_pass_0.fst`. +Possible transactions: [add, add_fork_early, add_doesnt_end_in_step, add_incorrect, add_incorrect_implicit, wait_and_add] +Error: Monitor failed diff --git a/protocols/tests/adders/adder_d1/busy_wait_pass.rt b/protocols/tests/adders/adder_d1/busy_wait_pass.rt new file mode 100644 index 00000000..5f1e646a --- /dev/null +++ b/protocols/tests/adders/adder_d1/busy_wait_pass.rt @@ -0,0 +1,5 @@ +trace_block: 0 +monitor_error: +thread 'main' panicked at monitor/src/interpreter.rs:479:17: +not yet implemented: Bounded loops is not yet implemented in the monitor +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/protocols/tests/adders/adder_d1/loop_with_assigns.rt b/protocols/tests/adders/adder_d1/loop_with_assigns.rt new file mode 100644 index 00000000..5f1e646a --- /dev/null +++ b/protocols/tests/adders/adder_d1/loop_with_assigns.rt @@ -0,0 +1,5 @@ +trace_block: 0 +monitor_error: +thread 'main' panicked at monitor/src/interpreter.rs:479:17: +not yet implemented: Bounded loops is not yet implemented in the monitor +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/protocols/tests/adders/adder_d1/nested_busy_wait.rt b/protocols/tests/adders/adder_d1/nested_busy_wait.rt new file mode 100644 index 00000000..5f1e646a --- /dev/null +++ b/protocols/tests/adders/adder_d1/nested_busy_wait.rt @@ -0,0 +1,5 @@ +trace_block: 0 +monitor_error: +thread 'main' panicked at monitor/src/interpreter.rs:479:17: +not yet implemented: Bounded loops is not yet implemented in the monitor +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/protocols/tests/adders/adder_d1/wait_and_add_correct.rt b/protocols/tests/adders/adder_d1/wait_and_add_correct.rt new file mode 100644 index 00000000..d027ae92 --- /dev/null +++ b/protocols/tests/adders/adder_d1/wait_and_add_correct.rt @@ -0,0 +1,6 @@ +trace_block: 0 +monitor_error: +All schedulers failed: No transactions match the waveform for DUT `Adder` +Failure at cycle 1: No transactions match the waveform in `.roundtrip_tmp/adders-adder_d1-wait_and_add_correct_0.fst`. +Possible transactions: [add, add_fork_early, add_doesnt_end_in_step, add_incorrect, add_incorrect_implicit, wait_and_add] +Error: Monitor failed diff --git a/protocols/tests/adders/adder_d2/both_threads_pass.rt b/protocols/tests/adders/adder_d2/both_threads_pass.rt index feb77132..1422f0b2 100644 --- a/protocols/tests/adders/adder_d2/both_threads_pass.rt +++ b/protocols/tests/adders/adder_d2/both_threads_pass.rt @@ -1 +1,15 @@ +trace_block: 0 +interpreter_trace: +trace { + add(1, 2, 3); + add(4, 5, 9); +} + +monitor_stdout: +// trace 0 +trace { + add(1, 2, 3); + add(4, 5, 9); +} + Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/alus/alu_d1.rt b/protocols/tests/alus/alu_d1.rt index feb77132..d548996f 100644 --- a/protocols/tests/alus/alu_d1.rt +++ b/protocols/tests/alus/alu_d1.rt @@ -1 +1,21 @@ +trace_block: 0 +interpreter_trace: +trace { + add(1, 2, 3); + add(123, 245, 368); + sub(200, 200, 0); + and(100, 100, 100); + or(0, 230, 230); +} + +monitor_stdout: +// trace 0 +trace { + add(1, 2, 3); + add(123, 245, 368); + sub(200, 200, 0); + and(100, 100, 100); + or(0, 230, 230); +} + Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/alus/alu_d2.rt b/protocols/tests/alus/alu_d2.rt index feb77132..d548996f 100644 --- a/protocols/tests/alus/alu_d2.rt +++ b/protocols/tests/alus/alu_d2.rt @@ -1 +1,21 @@ +trace_block: 0 +interpreter_trace: +trace { + add(1, 2, 3); + add(123, 245, 368); + sub(200, 200, 0); + and(100, 100, 100); + or(0, 230, 230); +} + +monitor_stdout: +// trace 0 +trace { + add(1, 2, 3); + add(123, 245, 368); + sub(200, 200, 0); + and(100, 100, 100); + or(0, 230, 230); +} + Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/brave_new_world/bit_truncation/bit_truncation_fft_fix.rt b/protocols/tests/brave_new_world/bit_truncation/bit_truncation_fft_fix.rt index feb77132..d6582f61 100644 --- a/protocols/tests/brave_new_world/bit_truncation/bit_truncation_fft_fix.rt +++ b/protocols/tests/brave_new_world/bit_truncation/bit_truncation_fft_fix.rt @@ -1 +1,13 @@ +trace_block: 0 +interpreter_trace: +trace { + bit_truncation_fft(8386560, 2047); +} + +monitor_stdout: +// trace 0 +trace { + bit_truncation_fft(8386560, 2047); +} + Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/brave_new_world/bit_truncation/bit_truncation_sha_fix.rt b/protocols/tests/brave_new_world/bit_truncation/bit_truncation_sha_fix.rt index feb77132..c9c3c17a 100644 --- a/protocols/tests/brave_new_world/bit_truncation/bit_truncation_sha_fix.rt +++ b/protocols/tests/brave_new_world/bit_truncation/bit_truncation_sha_fix.rt @@ -1 +1,13 @@ +trace_block: 0 +interpreter_trace: +trace { + bit_truncation_sha(4398046511104, 68719476736); +} + +monitor_stdout: +// trace 0 +trace { + bit_truncation_sha(4398046511104, 68719476736); +} + Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/brave_new_world/failure_to_update/ftu_sha_fix.rt b/protocols/tests/brave_new_world/failure_to_update/ftu_sha_fix.rt index feb77132..6da1773e 100644 --- a/protocols/tests/brave_new_world/failure_to_update/ftu_sha_fix.rt +++ b/protocols/tests/brave_new_world/failure_to_update/ftu_sha_fix.rt @@ -1 +1,13 @@ +trace_block: 0 +interpreter_trace: +trace { + failure_to_update_sha(); +} + +monitor_stdout: +// trace 0 +trace { + failure_to_update_sha(); +} + Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/brave_new_world/signal_asynchrony/signal_async_fix.rt b/protocols/tests/brave_new_world/signal_asynchrony/signal_async_fix.rt index feb77132..7ff9e076 100644 --- a/protocols/tests/brave_new_world/signal_asynchrony/signal_async_fix.rt +++ b/protocols/tests/brave_new_world/signal_asynchrony/signal_async_fix.rt @@ -1 +1,13 @@ +trace_block: 0 +interpreter_trace: +trace { + signal_async(6, 7); +} + +monitor_stdout: +// trace 0 +trace { + signal_async(6, 7); +} + Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/brave_new_world/use_without_valid/use_without_valid_fix.rt b/protocols/tests/brave_new_world/use_without_valid/use_without_valid_fix.rt index feb77132..1c6600a9 100644 --- a/protocols/tests/brave_new_world/use_without_valid/use_without_valid_fix.rt +++ b/protocols/tests/brave_new_world/use_without_valid/use_without_valid_fix.rt @@ -1 +1,13 @@ +trace_block: 0 +interpreter_trace: +trace { + use_without_valid(5, 5); +} + +monitor_stdout: +// trace 0 +trace { + use_without_valid(5, 5); +} + Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/counters/counter.rt b/protocols/tests/counters/counter.rt index feb77132..7c27d83e 100644 --- a/protocols/tests/counters/counter.rt +++ b/protocols/tests/counters/counter.rt @@ -1 +1,13 @@ +trace_block: 0 +interpreter_trace: +trace { + count_up(10); +} + +monitor_stdout: +// trace 0 +trace { + count_up(10); +} + Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/fifo/fifo.rt b/protocols/tests/fifo/fifo.rt index feb77132..547bbec0 100644 --- a/protocols/tests/fifo/fifo.rt +++ b/protocols/tests/fifo/fifo.rt @@ -1 +1,23 @@ +trace_block: 0 +interpreter_trace: +trace { + reset(); + push(3); + push(4); + idle(); + pop(3); + pop(4); +} + +monitor_stdout: +// trace 0 +trace { + reset(); + push(3); + push(4); + idle(); + pop(3); + pop(4); +} + Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/fifo/push_pop_identity_ok.rt b/protocols/tests/fifo/push_pop_identity_ok.rt new file mode 100644 index 00000000..16f07b38 --- /dev/null +++ b/protocols/tests/fifo/push_pop_identity_ok.rt @@ -0,0 +1,18 @@ +trace_block: 0 +interpreter_trace: +trace { + reset(); + push(2); + pop(2); + idle(); + push(3); + pop(3); +} + +monitor_stdout: +// trace 0 +trace { + reset(); + push(2); + pop(2); +} diff --git a/protocols/tests/fifo/push_pop_loop_empty.rt b/protocols/tests/fifo/push_pop_loop_empty.rt new file mode 100644 index 00000000..5f1e646a --- /dev/null +++ b/protocols/tests/fifo/push_pop_loop_empty.rt @@ -0,0 +1,5 @@ +trace_block: 0 +monitor_error: +thread 'main' panicked at monitor/src/interpreter.rs:479:17: +not yet implemented: Bounded loops is not yet implemented in the monitor +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/protocols/tests/fifo/push_pop_loop_not_empty.rt b/protocols/tests/fifo/push_pop_loop_not_empty.rt new file mode 100644 index 00000000..5f1e646a --- /dev/null +++ b/protocols/tests/fifo/push_pop_loop_not_empty.rt @@ -0,0 +1,5 @@ +trace_block: 0 +monitor_error: +thread 'main' panicked at monitor/src/interpreter.rs:479:17: +not yet implemented: Bounded loops is not yet implemented in the monitor +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/protocols/tests/identities/identity_d0/passthrough_combdep.rt b/protocols/tests/identities/identity_d0/passthrough_combdep.rt new file mode 100644 index 00000000..c1392505 --- /dev/null +++ b/protocols/tests/identities/identity_d0/passthrough_combdep.rt @@ -0,0 +1,12 @@ +trace_block: 0 +interpreter_trace: +trace { + passthrough(); +} + +monitor_stdout: +// trace 0 +trace { + passthrough(); + passthrough(); +} diff --git a/protocols/tests/identities/identity_d1/slicing_ok.rt b/protocols/tests/identities/identity_d1/slicing_ok.rt new file mode 100644 index 00000000..019e2fb7 --- /dev/null +++ b/protocols/tests/identities/identity_d1/slicing_ok.rt @@ -0,0 +1,11 @@ +trace_block: 0 +interpreter_trace: +trace { + slicing_ok(1, 1); +} + +monitor_stdout: +// trace 0 +trace { + explicit_fork(1, 1); +} diff --git a/protocols/tests/identities/identity_d2/single_thread_passes.rt b/protocols/tests/identities/identity_d2/single_thread_passes.rt index feb77132..25234853 100644 --- a/protocols/tests/identities/identity_d2/single_thread_passes.rt +++ b/protocols/tests/identities/identity_d2/single_thread_passes.rt @@ -1 +1,13 @@ +trace_block: 0 +interpreter_trace: +trace { + multiple_assign(1, 1); +} + +monitor_stdout: +// trace 0 +trace { + multiple_assign(1, 1); +} + Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/identities/identity_d2/two_assignments_same_value.rt b/protocols/tests/identities/identity_d2/two_assignments_same_value.rt index feb77132..810cb3f1 100644 --- a/protocols/tests/identities/identity_d2/two_assignments_same_value.rt +++ b/protocols/tests/identities/identity_d2/two_assignments_same_value.rt @@ -1 +1,21 @@ +trace_block: 0 +interpreter_trace: +trace { + multiple_assign(1, 1); + multiple_assign(1, 1); +} + +monitor_stdout: +// trace 0 +trace { + multiple_assign(1, 1); + multiple_assign(1, 1); +} + +// trace 1 +trace { + multiple_assign(1, 1); + two_fork_err(1, 1); +} + Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/multi/multi0/multi0.rt b/protocols/tests/multi/multi0/multi0.rt index feb77132..15feaa6f 100644 --- a/protocols/tests/multi/multi0/multi0.rt +++ b/protocols/tests/multi/multi0/multi0.rt @@ -1 +1,13 @@ +trace_block: 0 +interpreter_trace: +trace { + multi(10, 10); +} + +monitor_stdout: +// trace 0 +trace { + multi(10, 10); +} + Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/multi/multi0keep/multi0keep.rt b/protocols/tests/multi/multi0keep/multi0keep.rt index feb77132..15feaa6f 100644 --- a/protocols/tests/multi/multi0keep/multi0keep.rt +++ b/protocols/tests/multi/multi0keep/multi0keep.rt @@ -1 +1,13 @@ +trace_block: 0 +interpreter_trace: +trace { + multi(10, 10); +} + +monitor_stdout: +// trace 0 +trace { + multi(10, 10); +} + Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/multi/multi0keep2const/multi0keep2const.rt b/protocols/tests/multi/multi0keep2const/multi0keep2const.rt index feb77132..15feaa6f 100644 --- a/protocols/tests/multi/multi0keep2const/multi0keep2const.rt +++ b/protocols/tests/multi/multi0keep2const/multi0keep2const.rt @@ -1 +1,13 @@ +trace_block: 0 +interpreter_trace: +trace { + multi(10, 10); +} + +monitor_stdout: +// trace 0 +trace { + multi(10, 10); +} + Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/multi/multi2const/multi2const.rt b/protocols/tests/multi/multi2const/multi2const.rt index feb77132..15feaa6f 100644 --- a/protocols/tests/multi/multi2const/multi2const.rt +++ b/protocols/tests/multi/multi2const/multi2const.rt @@ -1 +1,13 @@ +trace_block: 0 +interpreter_trace: +trace { + multi(10, 10); +} + +monitor_stdout: +// trace 0 +trace { + multi(10, 10); +} + Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/multi/multi2multi/multi2multi.rt b/protocols/tests/multi/multi2multi/multi2multi.rt index feb77132..15feaa6f 100644 --- a/protocols/tests/multi/multi2multi/multi2multi.rt +++ b/protocols/tests/multi/multi2multi/multi2multi.rt @@ -1 +1,13 @@ +trace_block: 0 +interpreter_trace: +trace { + multi(10, 10); +} + +monitor_stdout: +// trace 0 +trace { + multi(10, 10); +} + Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/multi/multi_data/multi_data.rt b/protocols/tests/multi/multi_data/multi_data.rt index feb77132..15feaa6f 100644 --- a/protocols/tests/multi/multi_data/multi_data.rt +++ b/protocols/tests/multi/multi_data/multi_data.rt @@ -1 +1,13 @@ +trace_block: 0 +interpreter_trace: +trace { + multi(10, 10); +} + +monitor_stdout: +// trace 0 +trace { + multi(10, 10); +} + Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/multipliers/mult_d2/both_threads_pass.rt b/protocols/tests/multipliers/mult_d2/both_threads_pass.rt index feb77132..bcc7e2c6 100644 --- a/protocols/tests/multipliers/mult_d2/both_threads_pass.rt +++ b/protocols/tests/multipliers/mult_d2/both_threads_pass.rt @@ -1 +1,15 @@ +trace_block: 0 +interpreter_trace: +trace { + mul(1, 2, 2); + mul(6, 8, 48); +} + +monitor_stdout: +// trace 0 +trace { + mul(1, 2, 2); + mul(6, 8, 48); +} + Roundtrip trace 0 executed successfully! diff --git a/scripts/roundtrip_case.py b/scripts/roundtrip_case.py index 4383ede2..b0eac822 100644 --- a/scripts/roundtrip_case.py +++ b/scripts/roundtrip_case.py @@ -5,11 +5,10 @@ uv run scripts/roundtrip_case.py path/to/test.tx """ -import os import re import subprocess import sys -import tempfile +import traceback from pathlib import Path from typing import Optional @@ -20,6 +19,14 @@ def parse_arg(args: str, flag: str) -> Optional[str]: return m.group(1) if m else None +def relpath_str(path: Path, base_dir: Path) -> str: + """Return a path string relative to base_dir when possible.""" + try: + return str(path.relative_to(base_dir)) + except ValueError: + return str(path) + + def extract_struct_name(prot_path: Path) -> Optional[str]: """Return the first struct name declared in a .prot file.""" m = re.search(r"^struct\s+([A-Za-z_]\w*)", prot_path.read_text(), re.MULTILINE) @@ -114,16 +121,43 @@ def cleanup_generated_fsts(base_fst: Path) -> None: def fail(msg: str) -> int: - """Print a user-facing failure message and return a non-zero code.""" + """Print a failure message and return success for Turnt.""" print(msg) - return 1 + return 0 + + +def format_trace(trace: list[str]) -> str: + """Format one trace block for output.""" + if not trace: + return "" + return "\n".join(trace) + + +def format_trace_block(trace: list[str]) -> str: + """Format one trace using `trace { ... }` syntax with statement indentation.""" + if not trace: + return "trace {\n}" + indented = "\n".join(f" {stmt}" for stmt in trace) + return f"trace {{\n{indented}\n}}" + + +def tx_path_to_wave_stem(tx_file: Path, base_dir: Path) -> str: + """Build a deterministic wave stem from the tx path.""" + try: + rel = tx_file.relative_to(base_dir) + rel_no_suffix = rel.with_suffix("") + stem = str(rel_no_suffix).replace("/", "-").replace("\\", "-") + except ValueError: + stem = tx_file.stem + # Keep filenames portable and deterministic. + return re.sub(r"[^A-Za-z0-9._-]", "-", stem) def main() -> int: """Execute one roundtrip check for a single `.tx` file.""" if len(sys.argv) != 2: print("Usage: roundtrip_case.py ") - return 2 + return 0 tx_file = Path(sys.argv[1]).resolve() if not tx_file.exists(): @@ -161,19 +195,23 @@ def main() -> int: if not struct_name: return fail(f"Could not find struct in protocol: {prot_file}") + tx_file_rel = relpath_str(tx_file, base_dir) + prot_file_rel = relpath_str(prot_file, base_dir) + module_name = parse_arg(args, "module") instance_name = module_name if module_name else Path(verilog_rel).stem expected_traces = parse_trace_blocks(tx_text) - - fd, fst_file = tempfile.mkstemp(suffix=".fst") - os.close(fd) - os.unlink(fst_file) - fst_path = Path(fst_file) + wave_stem = tx_path_to_wave_stem(tx_file, base_dir) + roundtrip_tmp_dir = base_dir / ".roundtrip_tmp" + roundtrip_tmp_dir.mkdir(parents=True, exist_ok=True) + fst_path = roundtrip_tmp_dir / f"{wave_stem}.fst" + fst_path_rel = relpath_str(fst_path, base_dir) + cleanup_generated_fsts(fst_path) try: interp_cmd = ( "cargo run --quiet --package protocols-interp -- " - f"--color never --transactions {tx_file} {args} --fst {fst_file}" + f"--color never --transactions {tx_file_rel} {args} --fst {fst_path_rel}" ) interp = subprocess.run( interp_cmd, @@ -183,7 +221,11 @@ def main() -> int: text=True, ) if interp.returncode != 0: - return fail("Interpreter failed during roundtrip generation") + output = (interp.stdout + interp.stderr).strip() + return fail( + "interpreter_error:\n" + f"{output if output else ''}" + ) generated_fsts = collect_generated_fsts(fst_path) if not generated_fsts: @@ -197,7 +239,7 @@ def main() -> int: monitor_cmd = ( "cargo run --quiet --package protocols-monitor -- " - f"-p {prot_file} --wave {generated_fst} " + f"-p {prot_file_rel} --wave {relpath_str(generated_fst, base_dir)} " f"--instances {instance_name}:{struct_name}" ) monitor = subprocess.run( @@ -210,24 +252,20 @@ def main() -> int: if monitor.returncode != 0: output = (monitor.stdout + monitor.stderr).strip() return fail( - f"Monitor failed for trace {trace_idx} in {tx_file}\n{output}" + f"trace_block: {trace_idx}\n" + "monitor_error:\n" + f"{output if output else ''}" ) monitor_traces = parse_trace_blocks(monitor.stdout) expected = expected_traces[trace_idx] if expected not in monitor_traces: - expected_dump = "\n".join(expected) or "" - observed_dump = ( - "\n\n".join( - f"trace {i}:\n" + ("\n".join(t) if t else "") - for i, t in enumerate(monitor_traces) - ) - if monitor_traces - else "" - ) return fail( - f"Trace mismatch for {tx_file} trace {trace_idx}\n" - f"Expected:\n{expected_dump}\n\nObserved:\n{observed_dump}" + f"trace_block: {trace_idx}\n" + "interpreter_trace:\n" + f"{format_trace_block(expected)}\n\n" + "monitor_stdout:\n" + f"{monitor.stdout.strip() if monitor.stdout.strip() else ''}" ) print(f"Roundtrip trace {trace_idx} executed successfully!") @@ -244,4 +282,8 @@ def main() -> int: if __name__ == "__main__": - raise SystemExit(main()) + try: + raise SystemExit(main()) + except Exception: + print(f"roundtrip_tester_error:\n{traceback.format_exc().strip()}") + raise SystemExit(0) From 766cb0d3a34fc309430646e1d9286e137cc36bc6 Mon Sep 17 00:00:00 2001 From: Nikil-Shyamsunder Date: Mon, 16 Feb 2026 18:15:55 -0800 Subject: [PATCH 06/18] updated roundtrip case --- scripts/roundtrip_case.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/scripts/roundtrip_case.py b/scripts/roundtrip_case.py index b0eac822..6c118bbb 100644 --- a/scripts/roundtrip_case.py +++ b/scripts/roundtrip_case.py @@ -268,6 +268,13 @@ def main() -> int: f"{monitor.stdout.strip() if monitor.stdout.strip() else ''}" ) + print(f"trace_block: {trace_idx}") + print("interpreter_trace:") + print(format_trace_block(expected)) + print("") + print("monitor_stdout:") + print(monitor.stdout.strip() if monitor.stdout.strip() else "") + print("") print(f"Roundtrip trace {trace_idx} executed successfully!") if len(generated_fsts) < len(expected_traces): From 3144053329ed410a127880088eaacb9007e2de44 Mon Sep 17 00:00:00 2001 From: Nikil-Shyamsunder Date: Mon, 16 Feb 2026 18:29:03 -0800 Subject: [PATCH 07/18] make the .rt file formatting prettier --- examples/picorv32/unsigned_mul.rt | 7 ++++--- examples/serv/serv_regfile.rt | 7 ++++--- examples/tinyaes128/aes128.rt | 7 ++++--- protocols/tests/adders/adder_d0/add_combinational.rt | 8 ++++++++ protocols/tests/adders/adder_d1/both_threads_pass.rt | 9 +++++++++ protocols/tests/adders/adder_d1/busy_wait_pass.rt | 9 +++++++++ protocols/tests/adders/adder_d1/loop_with_assigns.rt | 9 +++++++++ protocols/tests/adders/adder_d1/nested_busy_wait.rt | 9 +++++++++ .../tests/adders/adder_d1/wait_and_add_correct.rt | 9 +++++++++ protocols/tests/adders/adder_d2/both_threads_pass.rt | 7 ++++--- protocols/tests/alus/alu_d1.rt | 7 ++++--- protocols/tests/alus/alu_d2.rt | 7 ++++--- .../bit_truncation/bit_truncation_fft_fix.rt | 7 ++++--- .../bit_truncation/bit_truncation_sha_fix.rt | 7 ++++--- .../brave_new_world/failure_to_update/ftu_sha_fix.rt | 7 ++++--- .../signal_asynchrony/signal_async_fix.rt | 7 ++++--- .../use_without_valid/use_without_valid_fix.rt | 7 ++++--- protocols/tests/counters/counter.rt | 7 ++++--- protocols/tests/fifo/fifo.rt | 7 ++++--- protocols/tests/fifo/push_pop_identity_ok.rt | 7 +++++-- protocols/tests/fifo/push_pop_loop_empty.rt | 11 +++++++++++ protocols/tests/fifo/push_pop_loop_not_empty.rt | 11 +++++++++++ .../identities/identity_d0/passthrough_combdep.rt | 7 +++++-- protocols/tests/identities/identity_d1/slicing_ok.rt | 7 +++++-- .../identities/identity_d2/single_thread_passes.rt | 7 ++++--- .../identity_d2/two_assignments_same_value.rt | 9 +++++---- protocols/tests/multi/multi0/multi0.rt | 7 ++++--- protocols/tests/multi/multi0keep/multi0keep.rt | 7 ++++--- .../tests/multi/multi0keep2const/multi0keep2const.rt | 7 ++++--- protocols/tests/multi/multi2const/multi2const.rt | 7 ++++--- protocols/tests/multi/multi2multi/multi2multi.rt | 7 ++++--- protocols/tests/multi/multi_data/multi_data.rt | 7 ++++--- .../tests/multipliers/mult_d2/both_threads_pass.rt | 7 ++++--- 33 files changed, 179 insertions(+), 73 deletions(-) diff --git a/examples/picorv32/unsigned_mul.rt b/examples/picorv32/unsigned_mul.rt index 8396d5a4..4eee5fe0 100644 --- a/examples/picorv32/unsigned_mul.rt +++ b/examples/picorv32/unsigned_mul.rt @@ -1,4 +1,6 @@ trace_block: 0 +trace_result: PASS +matched_monitor_trace_index: 0 interpreter_trace: trace { pcpi_mul_reset(); @@ -8,8 +10,8 @@ trace { pcpi_mul(33554483, 200, 2415929304); } -monitor_stdout: -// trace 0 +parsed_monitor_trace_candidates: +candidate_monitor_trace: 0 trace { pcpi_mul_reset(); pcpi_mul(1, 1, 1); @@ -18,4 +20,3 @@ trace { pcpi_mul(33554483, 200, 2415929304); } -Roundtrip trace 0 executed successfully! diff --git a/examples/serv/serv_regfile.rt b/examples/serv/serv_regfile.rt index df19af3c..fbfb87f6 100644 --- a/examples/serv/serv_regfile.rt +++ b/examples/serv/serv_regfile.rt @@ -1,15 +1,16 @@ trace_block: 0 +trace_result: PASS +matched_monitor_trace_index: 0 interpreter_trace: trace { read_write(0, 0, 0, 0, 1, 5, 3735928559); read_write(5, 3735928559, 0, 0, 0, 0, 0); } -monitor_stdout: -// trace 0 +parsed_monitor_trace_candidates: +candidate_monitor_trace: 0 trace { read_write(0, 0, 0, 0, 1, 5, 3735928559); read_write(5, 3735928559, 0, 0, 0, 0, 0); } -Roundtrip trace 0 executed successfully! diff --git a/examples/tinyaes128/aes128.rt b/examples/tinyaes128/aes128.rt index a3da5dd3..a6a84132 100644 --- a/examples/tinyaes128/aes128.rt +++ b/examples/tinyaes128/aes128.rt @@ -1,15 +1,16 @@ trace_block: 0 +trace_result: PASS +matched_monitor_trace_index: 0 interpreter_trace: trace { aes128(5233100606242806050955395731361295, 88962710306127702866241727433142015, 140591190147677442632770771134392354138); aes128(0, 0, 136792598789324718765670228683992083246); } -monitor_stdout: -// trace 0 +parsed_monitor_trace_candidates: +candidate_monitor_trace: 0 trace { aes128(5233100606242806050955395731361295, 88962710306127702866241727433142015, 140591190147677442632770771134392354138); aes128(0, 0, 136792598789324718765670228683992083246); } -Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/adders/adder_d0/add_combinational.rt b/protocols/tests/adders/adder_d0/add_combinational.rt index d68b7705..c9a33e27 100644 --- a/protocols/tests/adders/adder_d0/add_combinational.rt +++ b/protocols/tests/adders/adder_d0/add_combinational.rt @@ -1,6 +1,14 @@ trace_block: 0 +trace_result: FAIL +failure_kind: monitor_error +interpreter_trace: +trace { + add_combinational(100, 200, 300); +} + monitor_error: thread 'main' panicked at monitor/src/interpreter.rs:65:17: Transaction `add_combinational_illegal_observation_in_conditional`, cycle 0: Unable to find value for b (symbol5) in args_mapping, which is { (symbol4) a: 100 (symbol6) s: 300 } note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace + diff --git a/protocols/tests/adders/adder_d1/both_threads_pass.rt b/protocols/tests/adders/adder_d1/both_threads_pass.rt index 1804aed6..ce76cd61 100644 --- a/protocols/tests/adders/adder_d1/both_threads_pass.rt +++ b/protocols/tests/adders/adder_d1/both_threads_pass.rt @@ -1,6 +1,15 @@ trace_block: 0 +trace_result: FAIL +failure_kind: monitor_error +interpreter_trace: +trace { + add(1, 2, 3); + add(4, 5, 9); +} + monitor_error: All schedulers failed: No transactions match the waveform for DUT `Adder` Failure at cycle 1: No transactions match the waveform in `.roundtrip_tmp/adders-adder_d1-both_threads_pass_0.fst`. Possible transactions: [add, add_fork_early, add_doesnt_end_in_step, add_incorrect, add_incorrect_implicit, wait_and_add] Error: Monitor failed + diff --git a/protocols/tests/adders/adder_d1/busy_wait_pass.rt b/protocols/tests/adders/adder_d1/busy_wait_pass.rt index 5f1e646a..575d8181 100644 --- a/protocols/tests/adders/adder_d1/busy_wait_pass.rt +++ b/protocols/tests/adders/adder_d1/busy_wait_pass.rt @@ -1,5 +1,14 @@ trace_block: 0 +trace_result: FAIL +failure_kind: monitor_error +interpreter_trace: +trace { + add_busy_wait(1, 2, 1, 3); + add_busy_wait(4, 5, 3, 9); +} + monitor_error: thread 'main' panicked at monitor/src/interpreter.rs:479:17: not yet implemented: Bounded loops is not yet implemented in the monitor note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace + diff --git a/protocols/tests/adders/adder_d1/loop_with_assigns.rt b/protocols/tests/adders/adder_d1/loop_with_assigns.rt index 5f1e646a..d6971973 100644 --- a/protocols/tests/adders/adder_d1/loop_with_assigns.rt +++ b/protocols/tests/adders/adder_d1/loop_with_assigns.rt @@ -1,5 +1,14 @@ trace_block: 0 +trace_result: FAIL +failure_kind: monitor_error +interpreter_trace: +trace { + loop_add(1, 2, 3, 3); + loop_add(10, 20, 1, 30); +} + monitor_error: thread 'main' panicked at monitor/src/interpreter.rs:479:17: not yet implemented: Bounded loops is not yet implemented in the monitor note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace + diff --git a/protocols/tests/adders/adder_d1/nested_busy_wait.rt b/protocols/tests/adders/adder_d1/nested_busy_wait.rt index 5f1e646a..f5f86b16 100644 --- a/protocols/tests/adders/adder_d1/nested_busy_wait.rt +++ b/protocols/tests/adders/adder_d1/nested_busy_wait.rt @@ -1,5 +1,14 @@ trace_block: 0 +trace_result: FAIL +failure_kind: monitor_error +interpreter_trace: +trace { + nested_busy_wait(1, 2, 2, 3, 3); + nested_busy_wait(10, 20, 3, 2, 30); +} + monitor_error: thread 'main' panicked at monitor/src/interpreter.rs:479:17: not yet implemented: Bounded loops is not yet implemented in the monitor note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace + diff --git a/protocols/tests/adders/adder_d1/wait_and_add_correct.rt b/protocols/tests/adders/adder_d1/wait_and_add_correct.rt index d027ae92..1c23412b 100644 --- a/protocols/tests/adders/adder_d1/wait_and_add_correct.rt +++ b/protocols/tests/adders/adder_d1/wait_and_add_correct.rt @@ -1,6 +1,15 @@ trace_block: 0 +trace_result: FAIL +failure_kind: monitor_error +interpreter_trace: +trace { + wait_and_add(1, 2, 3); + add(4, 5, 9); +} + monitor_error: All schedulers failed: No transactions match the waveform for DUT `Adder` Failure at cycle 1: No transactions match the waveform in `.roundtrip_tmp/adders-adder_d1-wait_and_add_correct_0.fst`. Possible transactions: [add, add_fork_early, add_doesnt_end_in_step, add_incorrect, add_incorrect_implicit, wait_and_add] Error: Monitor failed + diff --git a/protocols/tests/adders/adder_d2/both_threads_pass.rt b/protocols/tests/adders/adder_d2/both_threads_pass.rt index 1422f0b2..5528f243 100644 --- a/protocols/tests/adders/adder_d2/both_threads_pass.rt +++ b/protocols/tests/adders/adder_d2/both_threads_pass.rt @@ -1,15 +1,16 @@ trace_block: 0 +trace_result: PASS +matched_monitor_trace_index: 0 interpreter_trace: trace { add(1, 2, 3); add(4, 5, 9); } -monitor_stdout: -// trace 0 +parsed_monitor_trace_candidates: +candidate_monitor_trace: 0 trace { add(1, 2, 3); add(4, 5, 9); } -Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/alus/alu_d1.rt b/protocols/tests/alus/alu_d1.rt index d548996f..d5dcd0d8 100644 --- a/protocols/tests/alus/alu_d1.rt +++ b/protocols/tests/alus/alu_d1.rt @@ -1,4 +1,6 @@ trace_block: 0 +trace_result: PASS +matched_monitor_trace_index: 0 interpreter_trace: trace { add(1, 2, 3); @@ -8,8 +10,8 @@ trace { or(0, 230, 230); } -monitor_stdout: -// trace 0 +parsed_monitor_trace_candidates: +candidate_monitor_trace: 0 trace { add(1, 2, 3); add(123, 245, 368); @@ -18,4 +20,3 @@ trace { or(0, 230, 230); } -Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/alus/alu_d2.rt b/protocols/tests/alus/alu_d2.rt index d548996f..d5dcd0d8 100644 --- a/protocols/tests/alus/alu_d2.rt +++ b/protocols/tests/alus/alu_d2.rt @@ -1,4 +1,6 @@ trace_block: 0 +trace_result: PASS +matched_monitor_trace_index: 0 interpreter_trace: trace { add(1, 2, 3); @@ -8,8 +10,8 @@ trace { or(0, 230, 230); } -monitor_stdout: -// trace 0 +parsed_monitor_trace_candidates: +candidate_monitor_trace: 0 trace { add(1, 2, 3); add(123, 245, 368); @@ -18,4 +20,3 @@ trace { or(0, 230, 230); } -Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/brave_new_world/bit_truncation/bit_truncation_fft_fix.rt b/protocols/tests/brave_new_world/bit_truncation/bit_truncation_fft_fix.rt index d6582f61..ba2a4639 100644 --- a/protocols/tests/brave_new_world/bit_truncation/bit_truncation_fft_fix.rt +++ b/protocols/tests/brave_new_world/bit_truncation/bit_truncation_fft_fix.rt @@ -1,13 +1,14 @@ trace_block: 0 +trace_result: PASS +matched_monitor_trace_index: 0 interpreter_trace: trace { bit_truncation_fft(8386560, 2047); } -monitor_stdout: -// trace 0 +parsed_monitor_trace_candidates: +candidate_monitor_trace: 0 trace { bit_truncation_fft(8386560, 2047); } -Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/brave_new_world/bit_truncation/bit_truncation_sha_fix.rt b/protocols/tests/brave_new_world/bit_truncation/bit_truncation_sha_fix.rt index c9c3c17a..396fedb5 100644 --- a/protocols/tests/brave_new_world/bit_truncation/bit_truncation_sha_fix.rt +++ b/protocols/tests/brave_new_world/bit_truncation/bit_truncation_sha_fix.rt @@ -1,13 +1,14 @@ trace_block: 0 +trace_result: PASS +matched_monitor_trace_index: 0 interpreter_trace: trace { bit_truncation_sha(4398046511104, 68719476736); } -monitor_stdout: -// trace 0 +parsed_monitor_trace_candidates: +candidate_monitor_trace: 0 trace { bit_truncation_sha(4398046511104, 68719476736); } -Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/brave_new_world/failure_to_update/ftu_sha_fix.rt b/protocols/tests/brave_new_world/failure_to_update/ftu_sha_fix.rt index 6da1773e..43b6d3b2 100644 --- a/protocols/tests/brave_new_world/failure_to_update/ftu_sha_fix.rt +++ b/protocols/tests/brave_new_world/failure_to_update/ftu_sha_fix.rt @@ -1,13 +1,14 @@ trace_block: 0 +trace_result: PASS +matched_monitor_trace_index: 0 interpreter_trace: trace { failure_to_update_sha(); } -monitor_stdout: -// trace 0 +parsed_monitor_trace_candidates: +candidate_monitor_trace: 0 trace { failure_to_update_sha(); } -Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/brave_new_world/signal_asynchrony/signal_async_fix.rt b/protocols/tests/brave_new_world/signal_asynchrony/signal_async_fix.rt index 7ff9e076..828f45bf 100644 --- a/protocols/tests/brave_new_world/signal_asynchrony/signal_async_fix.rt +++ b/protocols/tests/brave_new_world/signal_asynchrony/signal_async_fix.rt @@ -1,13 +1,14 @@ trace_block: 0 +trace_result: PASS +matched_monitor_trace_index: 0 interpreter_trace: trace { signal_async(6, 7); } -monitor_stdout: -// trace 0 +parsed_monitor_trace_candidates: +candidate_monitor_trace: 0 trace { signal_async(6, 7); } -Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/brave_new_world/use_without_valid/use_without_valid_fix.rt b/protocols/tests/brave_new_world/use_without_valid/use_without_valid_fix.rt index 1c6600a9..93c8a6ec 100644 --- a/protocols/tests/brave_new_world/use_without_valid/use_without_valid_fix.rt +++ b/protocols/tests/brave_new_world/use_without_valid/use_without_valid_fix.rt @@ -1,13 +1,14 @@ trace_block: 0 +trace_result: PASS +matched_monitor_trace_index: 0 interpreter_trace: trace { use_without_valid(5, 5); } -monitor_stdout: -// trace 0 +parsed_monitor_trace_candidates: +candidate_monitor_trace: 0 trace { use_without_valid(5, 5); } -Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/counters/counter.rt b/protocols/tests/counters/counter.rt index 7c27d83e..63761847 100644 --- a/protocols/tests/counters/counter.rt +++ b/protocols/tests/counters/counter.rt @@ -1,13 +1,14 @@ trace_block: 0 +trace_result: PASS +matched_monitor_trace_index: 0 interpreter_trace: trace { count_up(10); } -monitor_stdout: -// trace 0 +parsed_monitor_trace_candidates: +candidate_monitor_trace: 0 trace { count_up(10); } -Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/fifo/fifo.rt b/protocols/tests/fifo/fifo.rt index 547bbec0..5700f7a8 100644 --- a/protocols/tests/fifo/fifo.rt +++ b/protocols/tests/fifo/fifo.rt @@ -1,4 +1,6 @@ trace_block: 0 +trace_result: PASS +matched_monitor_trace_index: 0 interpreter_trace: trace { reset(); @@ -9,8 +11,8 @@ trace { pop(4); } -monitor_stdout: -// trace 0 +parsed_monitor_trace_candidates: +candidate_monitor_trace: 0 trace { reset(); push(3); @@ -20,4 +22,3 @@ trace { pop(4); } -Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/fifo/push_pop_identity_ok.rt b/protocols/tests/fifo/push_pop_identity_ok.rt index 16f07b38..16cc7776 100644 --- a/protocols/tests/fifo/push_pop_identity_ok.rt +++ b/protocols/tests/fifo/push_pop_identity_ok.rt @@ -1,4 +1,6 @@ trace_block: 0 +trace_result: FAIL +failure_kind: trace_mismatch interpreter_trace: trace { reset(); @@ -9,10 +11,11 @@ trace { pop(3); } -monitor_stdout: -// trace 0 +parsed_monitor_trace_candidates: +candidate_monitor_trace: 0 trace { reset(); push(2); pop(2); } + diff --git a/protocols/tests/fifo/push_pop_loop_empty.rt b/protocols/tests/fifo/push_pop_loop_empty.rt index 5f1e646a..7dd3e017 100644 --- a/protocols/tests/fifo/push_pop_loop_empty.rt +++ b/protocols/tests/fifo/push_pop_loop_empty.rt @@ -1,5 +1,16 @@ trace_block: 0 +trace_result: FAIL +failure_kind: monitor_error +interpreter_trace: +trace { + reset(); + push_n_times(42, 4); + pop_n_times(42, 4); + check_empty(); +} + monitor_error: thread 'main' panicked at monitor/src/interpreter.rs:479:17: not yet implemented: Bounded loops is not yet implemented in the monitor note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace + diff --git a/protocols/tests/fifo/push_pop_loop_not_empty.rt b/protocols/tests/fifo/push_pop_loop_not_empty.rt index 5f1e646a..4ae1e0af 100644 --- a/protocols/tests/fifo/push_pop_loop_not_empty.rt +++ b/protocols/tests/fifo/push_pop_loop_not_empty.rt @@ -1,5 +1,16 @@ trace_block: 0 +trace_result: FAIL +failure_kind: monitor_error +interpreter_trace: +trace { + reset(); + push_n_times(7, 3); + pop_n_times(7, 2); + check_not_empty(); +} + monitor_error: thread 'main' panicked at monitor/src/interpreter.rs:479:17: not yet implemented: Bounded loops is not yet implemented in the monitor note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace + diff --git a/protocols/tests/identities/identity_d0/passthrough_combdep.rt b/protocols/tests/identities/identity_d0/passthrough_combdep.rt index c1392505..57134e31 100644 --- a/protocols/tests/identities/identity_d0/passthrough_combdep.rt +++ b/protocols/tests/identities/identity_d0/passthrough_combdep.rt @@ -1,12 +1,15 @@ trace_block: 0 +trace_result: FAIL +failure_kind: trace_mismatch interpreter_trace: trace { passthrough(); } -monitor_stdout: -// trace 0 +parsed_monitor_trace_candidates: +candidate_monitor_trace: 0 trace { passthrough(); passthrough(); } + diff --git a/protocols/tests/identities/identity_d1/slicing_ok.rt b/protocols/tests/identities/identity_d1/slicing_ok.rt index 019e2fb7..7e380628 100644 --- a/protocols/tests/identities/identity_d1/slicing_ok.rt +++ b/protocols/tests/identities/identity_d1/slicing_ok.rt @@ -1,11 +1,14 @@ trace_block: 0 +trace_result: FAIL +failure_kind: trace_mismatch interpreter_trace: trace { slicing_ok(1, 1); } -monitor_stdout: -// trace 0 +parsed_monitor_trace_candidates: +candidate_monitor_trace: 0 trace { explicit_fork(1, 1); } + diff --git a/protocols/tests/identities/identity_d2/single_thread_passes.rt b/protocols/tests/identities/identity_d2/single_thread_passes.rt index 25234853..3cc34532 100644 --- a/protocols/tests/identities/identity_d2/single_thread_passes.rt +++ b/protocols/tests/identities/identity_d2/single_thread_passes.rt @@ -1,13 +1,14 @@ trace_block: 0 +trace_result: PASS +matched_monitor_trace_index: 0 interpreter_trace: trace { multiple_assign(1, 1); } -monitor_stdout: -// trace 0 +parsed_monitor_trace_candidates: +candidate_monitor_trace: 0 trace { multiple_assign(1, 1); } -Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/identities/identity_d2/two_assignments_same_value.rt b/protocols/tests/identities/identity_d2/two_assignments_same_value.rt index 810cb3f1..f188a082 100644 --- a/protocols/tests/identities/identity_d2/two_assignments_same_value.rt +++ b/protocols/tests/identities/identity_d2/two_assignments_same_value.rt @@ -1,21 +1,22 @@ trace_block: 0 +trace_result: PASS +matched_monitor_trace_index: 0 interpreter_trace: trace { multiple_assign(1, 1); multiple_assign(1, 1); } -monitor_stdout: -// trace 0 +parsed_monitor_trace_candidates: +candidate_monitor_trace: 0 trace { multiple_assign(1, 1); multiple_assign(1, 1); } -// trace 1 +candidate_monitor_trace: 1 trace { multiple_assign(1, 1); two_fork_err(1, 1); } -Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/multi/multi0/multi0.rt b/protocols/tests/multi/multi0/multi0.rt index 15feaa6f..ce778b6c 100644 --- a/protocols/tests/multi/multi0/multi0.rt +++ b/protocols/tests/multi/multi0/multi0.rt @@ -1,13 +1,14 @@ trace_block: 0 +trace_result: PASS +matched_monitor_trace_index: 0 interpreter_trace: trace { multi(10, 10); } -monitor_stdout: -// trace 0 +parsed_monitor_trace_candidates: +candidate_monitor_trace: 0 trace { multi(10, 10); } -Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/multi/multi0keep/multi0keep.rt b/protocols/tests/multi/multi0keep/multi0keep.rt index 15feaa6f..ce778b6c 100644 --- a/protocols/tests/multi/multi0keep/multi0keep.rt +++ b/protocols/tests/multi/multi0keep/multi0keep.rt @@ -1,13 +1,14 @@ trace_block: 0 +trace_result: PASS +matched_monitor_trace_index: 0 interpreter_trace: trace { multi(10, 10); } -monitor_stdout: -// trace 0 +parsed_monitor_trace_candidates: +candidate_monitor_trace: 0 trace { multi(10, 10); } -Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/multi/multi0keep2const/multi0keep2const.rt b/protocols/tests/multi/multi0keep2const/multi0keep2const.rt index 15feaa6f..ce778b6c 100644 --- a/protocols/tests/multi/multi0keep2const/multi0keep2const.rt +++ b/protocols/tests/multi/multi0keep2const/multi0keep2const.rt @@ -1,13 +1,14 @@ trace_block: 0 +trace_result: PASS +matched_monitor_trace_index: 0 interpreter_trace: trace { multi(10, 10); } -monitor_stdout: -// trace 0 +parsed_monitor_trace_candidates: +candidate_monitor_trace: 0 trace { multi(10, 10); } -Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/multi/multi2const/multi2const.rt b/protocols/tests/multi/multi2const/multi2const.rt index 15feaa6f..ce778b6c 100644 --- a/protocols/tests/multi/multi2const/multi2const.rt +++ b/protocols/tests/multi/multi2const/multi2const.rt @@ -1,13 +1,14 @@ trace_block: 0 +trace_result: PASS +matched_monitor_trace_index: 0 interpreter_trace: trace { multi(10, 10); } -monitor_stdout: -// trace 0 +parsed_monitor_trace_candidates: +candidate_monitor_trace: 0 trace { multi(10, 10); } -Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/multi/multi2multi/multi2multi.rt b/protocols/tests/multi/multi2multi/multi2multi.rt index 15feaa6f..ce778b6c 100644 --- a/protocols/tests/multi/multi2multi/multi2multi.rt +++ b/protocols/tests/multi/multi2multi/multi2multi.rt @@ -1,13 +1,14 @@ trace_block: 0 +trace_result: PASS +matched_monitor_trace_index: 0 interpreter_trace: trace { multi(10, 10); } -monitor_stdout: -// trace 0 +parsed_monitor_trace_candidates: +candidate_monitor_trace: 0 trace { multi(10, 10); } -Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/multi/multi_data/multi_data.rt b/protocols/tests/multi/multi_data/multi_data.rt index 15feaa6f..ce778b6c 100644 --- a/protocols/tests/multi/multi_data/multi_data.rt +++ b/protocols/tests/multi/multi_data/multi_data.rt @@ -1,13 +1,14 @@ trace_block: 0 +trace_result: PASS +matched_monitor_trace_index: 0 interpreter_trace: trace { multi(10, 10); } -monitor_stdout: -// trace 0 +parsed_monitor_trace_candidates: +candidate_monitor_trace: 0 trace { multi(10, 10); } -Roundtrip trace 0 executed successfully! diff --git a/protocols/tests/multipliers/mult_d2/both_threads_pass.rt b/protocols/tests/multipliers/mult_d2/both_threads_pass.rt index bcc7e2c6..537a9166 100644 --- a/protocols/tests/multipliers/mult_d2/both_threads_pass.rt +++ b/protocols/tests/multipliers/mult_d2/both_threads_pass.rt @@ -1,15 +1,16 @@ trace_block: 0 +trace_result: PASS +matched_monitor_trace_index: 0 interpreter_trace: trace { mul(1, 2, 2); mul(6, 8, 48); } -monitor_stdout: -// trace 0 +parsed_monitor_trace_candidates: +candidate_monitor_trace: 0 trace { mul(1, 2, 2); mul(6, 8, 48); } -Roundtrip trace 0 executed successfully! From 358df9cf1fd37a98a3d188407d3c4c68b5b494f2 Mon Sep 17 00:00:00 2001 From: Nikil-Shyamsunder Date: Mon, 16 Feb 2026 18:31:28 -0800 Subject: [PATCH 08/18] modify python script to have prettier .rt outputs --- scripts/roundtrip_case.py | 94 +++++++++++++++++++++++++++++---------- 1 file changed, 70 insertions(+), 24 deletions(-) diff --git a/scripts/roundtrip_case.py b/scripts/roundtrip_case.py index 6c118bbb..28eee40e 100644 --- a/scripts/roundtrip_case.py +++ b/scripts/roundtrip_case.py @@ -153,6 +153,16 @@ def tx_path_to_wave_stem(tx_file: Path, base_dir: Path) -> str: return re.sub(r"[^A-Za-z0-9._-]", "-", stem) +def format_monitor_trace_candidates(traces: list[list[str]]) -> str: + """Format parsed monitor traces as indexed candidates.""" + if not traces: + return "" + chunks = [] + for i, t in enumerate(traces): + chunks.append(f"candidate_monitor_trace: {i}\n{format_trace_block(t)}") + return "\n\n".join(chunks) + + def main() -> int: """Execute one roundtrip check for a single `.tx` file.""" if len(sys.argv) != 2: @@ -229,13 +239,28 @@ def main() -> int: generated_fsts = collect_generated_fsts(fst_path) if not generated_fsts: - return fail("No waveform file generated by interpreter") + return fail("interpreter_error:\nNo waveform file generated by interpreter") + + any_failures = False + printed_blocks = 0 for trace_idx, generated_fst in enumerate(generated_fsts): + if printed_blocks > 0: + print("") + print("---") + print("") + print(f"trace_block: {trace_idx}") + printed_blocks += 1 if trace_idx >= len(expected_traces): - return fail( + any_failures = True + print("trace_result: FAIL") + print("failure_kind: extra_interpreter_trace") + print("message:") + print( f"Interpreter generated unexpected extra trace {trace_idx} for {tx_file}" ) + print("") + continue monitor_cmd = ( "cargo run --quiet --package protocols-monitor -- " @@ -250,38 +275,59 @@ def main() -> int: text=True, ) if monitor.returncode != 0: + any_failures = True output = (monitor.stdout + monitor.stderr).strip() - return fail( - f"trace_block: {trace_idx}\n" - "monitor_error:\n" - f"{output if output else ''}" - ) + print("trace_result: FAIL") + print("failure_kind: monitor_error") + print("interpreter_trace:") + print(format_trace_block(expected_traces[trace_idx])) + print("") + print("monitor_error:") + print(output if output else "") + print("") + continue monitor_traces = parse_trace_blocks(monitor.stdout) expected = expected_traces[trace_idx] - if expected not in monitor_traces: - return fail( - f"trace_block: {trace_idx}\n" - "interpreter_trace:\n" - f"{format_trace_block(expected)}\n\n" - "monitor_stdout:\n" - f"{monitor.stdout.strip() if monitor.stdout.strip() else ''}" - ) - - print(f"trace_block: {trace_idx}") + matched_idx = next( + (i for i, candidate in enumerate(monitor_traces) if candidate == expected), + None, + ) + if matched_idx is None: + any_failures = True + print("trace_result: FAIL") + print("failure_kind: trace_mismatch") + print("interpreter_trace:") + print(format_trace_block(expected)) + print("") + print("parsed_monitor_trace_candidates:") + print(format_monitor_trace_candidates(monitor_traces)) + print("") + continue + + print("trace_result: PASS") + print(f"matched_monitor_trace_index: {matched_idx}") print("interpreter_trace:") print(format_trace_block(expected)) print("") - print("monitor_stdout:") - print(monitor.stdout.strip() if monitor.stdout.strip() else "") + print("parsed_monitor_trace_candidates:") + print(format_monitor_trace_candidates(monitor_traces)) print("") - print(f"Roundtrip trace {trace_idx} executed successfully!") if len(generated_fsts) < len(expected_traces): - return fail( - f"Interpreter generated only {len(generated_fsts)} traces, " - f"but source has {len(expected_traces)}" - ) + any_failures = True + for trace_idx in range(len(generated_fsts), len(expected_traces)): + if printed_blocks > 0: + print("") + print("---") + print("") + print(f"trace_block: {trace_idx}") + printed_blocks += 1 + print("trace_result: FAIL") + print("failure_kind: missing_interpreter_trace") + print("interpreter_trace:") + print(format_trace_block(expected_traces[trace_idx])) + print("") return 0 finally: From f996b8fa4763c392b4c3747516c35c8b0e5d7ed7 Mon Sep 17 00:00:00 2001 From: Nikil-Shyamsunder Date: Mon, 16 Feb 2026 18:39:46 -0800 Subject: [PATCH 09/18] debug: add --diff flag due to divergence in .rt results between ci machine and local --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4a6e5f44..5cb3b641 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -42,7 +42,7 @@ jobs: - uses: actions/checkout@v4 - uses: ./.github/actions/setup-test-environment - name: Run Turnt roundtrip tests - run: turnt --env roundtrip $(find . -type f -name '*.tx') + run: turnt --env roundtrip $(find . -type f -name '*.tx') --diff msrv: name: Check Minimum Rust Version for protocols library From 68a5a2e28171a7a084b8e6019cf458796a78ab6e Mon Sep 17 00:00:00 2001 From: Nikil-Shyamsunder Date: Mon, 16 Feb 2026 18:47:42 -0800 Subject: [PATCH 10/18] normalize panic outputs --- .../tests/adders/adder_d0/add_combinational.rt | 1 - protocols/tests/adders/adder_d1/busy_wait_pass.rt | 1 - .../tests/adders/adder_d1/loop_with_assigns.rt | 1 - .../tests/adders/adder_d1/nested_busy_wait.rt | 1 - protocols/tests/fifo/push_pop_loop_empty.rt | 1 - protocols/tests/fifo/push_pop_loop_not_empty.rt | 1 - scripts/roundtrip_case.py | 15 +++++++++++++-- 7 files changed, 13 insertions(+), 8 deletions(-) diff --git a/protocols/tests/adders/adder_d0/add_combinational.rt b/protocols/tests/adders/adder_d0/add_combinational.rt index c9a33e27..c92ee58d 100644 --- a/protocols/tests/adders/adder_d0/add_combinational.rt +++ b/protocols/tests/adders/adder_d0/add_combinational.rt @@ -7,7 +7,6 @@ trace { } monitor_error: -thread 'main' panicked at monitor/src/interpreter.rs:65:17: Transaction `add_combinational_illegal_observation_in_conditional`, cycle 0: Unable to find value for b (symbol5) in args_mapping, which is { (symbol4) a: 100 (symbol6) s: 300 } note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/protocols/tests/adders/adder_d1/busy_wait_pass.rt b/protocols/tests/adders/adder_d1/busy_wait_pass.rt index 575d8181..983d8a2d 100644 --- a/protocols/tests/adders/adder_d1/busy_wait_pass.rt +++ b/protocols/tests/adders/adder_d1/busy_wait_pass.rt @@ -8,7 +8,6 @@ trace { } monitor_error: -thread 'main' panicked at monitor/src/interpreter.rs:479:17: not yet implemented: Bounded loops is not yet implemented in the monitor note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/protocols/tests/adders/adder_d1/loop_with_assigns.rt b/protocols/tests/adders/adder_d1/loop_with_assigns.rt index d6971973..98e4d94f 100644 --- a/protocols/tests/adders/adder_d1/loop_with_assigns.rt +++ b/protocols/tests/adders/adder_d1/loop_with_assigns.rt @@ -8,7 +8,6 @@ trace { } monitor_error: -thread 'main' panicked at monitor/src/interpreter.rs:479:17: not yet implemented: Bounded loops is not yet implemented in the monitor note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/protocols/tests/adders/adder_d1/nested_busy_wait.rt b/protocols/tests/adders/adder_d1/nested_busy_wait.rt index f5f86b16..d2ee2adb 100644 --- a/protocols/tests/adders/adder_d1/nested_busy_wait.rt +++ b/protocols/tests/adders/adder_d1/nested_busy_wait.rt @@ -8,7 +8,6 @@ trace { } monitor_error: -thread 'main' panicked at monitor/src/interpreter.rs:479:17: not yet implemented: Bounded loops is not yet implemented in the monitor note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/protocols/tests/fifo/push_pop_loop_empty.rt b/protocols/tests/fifo/push_pop_loop_empty.rt index 7dd3e017..230f43de 100644 --- a/protocols/tests/fifo/push_pop_loop_empty.rt +++ b/protocols/tests/fifo/push_pop_loop_empty.rt @@ -10,7 +10,6 @@ trace { } monitor_error: -thread 'main' panicked at monitor/src/interpreter.rs:479:17: not yet implemented: Bounded loops is not yet implemented in the monitor note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/protocols/tests/fifo/push_pop_loop_not_empty.rt b/protocols/tests/fifo/push_pop_loop_not_empty.rt index 4ae1e0af..c02dc659 100644 --- a/protocols/tests/fifo/push_pop_loop_not_empty.rt +++ b/protocols/tests/fifo/push_pop_loop_not_empty.rt @@ -10,7 +10,6 @@ trace { } monitor_error: -thread 'main' panicked at monitor/src/interpreter.rs:479:17: not yet implemented: Bounded loops is not yet implemented in the monitor note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/scripts/roundtrip_case.py b/scripts/roundtrip_case.py index 28eee40e..f860ea5f 100644 --- a/scripts/roundtrip_case.py +++ b/scripts/roundtrip_case.py @@ -27,6 +27,17 @@ def relpath_str(path: Path, base_dir: Path) -> str: return str(path) +def sanitize_error_output(text: str) -> str: + """Remove unstable runtime panic location lines from stderr/stdout text.""" + lines = [] + for line in text.splitlines(): + if "panicked at " in line: + continue + lines.append(line) + sanitized = "\n".join(lines).strip() + return sanitized + + def extract_struct_name(prot_path: Path) -> Optional[str]: """Return the first struct name declared in a .prot file.""" m = re.search(r"^struct\s+([A-Za-z_]\w*)", prot_path.read_text(), re.MULTILINE) @@ -231,7 +242,7 @@ def main() -> int: text=True, ) if interp.returncode != 0: - output = (interp.stdout + interp.stderr).strip() + output = sanitize_error_output((interp.stdout + interp.stderr).strip()) return fail( "interpreter_error:\n" f"{output if output else ''}" @@ -276,7 +287,7 @@ def main() -> int: ) if monitor.returncode != 0: any_failures = True - output = (monitor.stdout + monitor.stderr).strip() + output = sanitize_error_output((monitor.stdout + monitor.stderr).strip()) print("trace_result: FAIL") print("failure_kind: monitor_error") print("interpreter_trace:") From 1ec06795f14e48dbe6a2f64ec2f233435afac820 Mon Sep 17 00:00:00 2001 From: Ernest Ng Date: Wed, 18 Feb 2026 14:56:43 -0500 Subject: [PATCH 11/18] [skip ci] Add TODO for Ernest --- protocols/tests/identities/identity_d1/identity_d1.prot | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/protocols/tests/identities/identity_d1/identity_d1.prot b/protocols/tests/identities/identity_d1/identity_d1.prot index 9293a221..fcaec1ee 100644 --- a/protocols/tests/identities/identity_d1/identity_d1.prot +++ b/protocols/tests/identities/identity_d1/identity_d1.prot @@ -20,8 +20,12 @@ prot slicing_ok(in a: u32, out s: u32) { DUT.a := a; step(); + + assert_eq(s[31:15], DUT.s[31:15]); - assert_eq(s[31:15], DUT.s[31:15]); + // TODO for Ernest: + // uncomment this line and see if it works with the monitor (if the round-trip test passes) + // assert_eq(s[14:0], DUT.s[14:0]); fork(); step(); From d947ec206f8907167e58c488df8da8b90b56a0b4 Mon Sep 17 00:00:00 2001 From: Ernest Ng Date: Thu, 19 Feb 2026 13:46:47 -0500 Subject: [PATCH 12/18] Add extra CLI flag to round-trip testing script to keep intermediate FST file --- scripts/roundtrip_case.py | 41 ++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/scripts/roundtrip_case.py b/scripts/roundtrip_case.py index f860ea5f..5fc29e8d 100644 --- a/scripts/roundtrip_case.py +++ b/scripts/roundtrip_case.py @@ -5,9 +5,9 @@ uv run scripts/roundtrip_case.py path/to/test.tx """ +import argparse import re import subprocess -import sys import traceback from pathlib import Path from typing import Optional @@ -176,11 +176,18 @@ def format_monitor_trace_candidates(traces: list[list[str]]) -> str: def main() -> int: """Execute one roundtrip check for a single `.tx` file.""" - if len(sys.argv) != 2: - print("Usage: roundtrip_case.py ") - return 0 - - tx_file = Path(sys.argv[1]).resolve() + parser = argparse.ArgumentParser( + description="Run one roundtrip check for a single .tx file." + ) + parser.add_argument("tx_file", help="Path to the .tx file to check") + parser.add_argument( + "--keep-fst", + action="store_true", + help="Do not delete the intermediate .fst waveform file after the check", + ) + args_ns = parser.parse_args() + + tx_file = Path(args_ns.tx_file).resolve() if not tx_file.exists(): return fail(f"Missing tx file: {tx_file}") @@ -244,15 +251,13 @@ def main() -> int: if interp.returncode != 0: output = sanitize_error_output((interp.stdout + interp.stderr).strip()) return fail( - "interpreter_error:\n" - f"{output if output else ''}" + f"interpreter_error:\n{output if output else ''}" ) generated_fsts = collect_generated_fsts(fst_path) if not generated_fsts: return fail("interpreter_error:\nNo waveform file generated by interpreter") - any_failures = False printed_blocks = 0 for trace_idx, generated_fst in enumerate(generated_fsts): @@ -261,9 +266,9 @@ def main() -> int: print("---") print("") print(f"trace_block: {trace_idx}") + print(f"fst_file: {relpath_str(generated_fst, base_dir)}") printed_blocks += 1 if trace_idx >= len(expected_traces): - any_failures = True print("trace_result: FAIL") print("failure_kind: extra_interpreter_trace") print("message:") @@ -286,8 +291,9 @@ def main() -> int: text=True, ) if monitor.returncode != 0: - any_failures = True - output = sanitize_error_output((monitor.stdout + monitor.stderr).strip()) + output = sanitize_error_output( + (monitor.stdout + monitor.stderr).strip() + ) print("trace_result: FAIL") print("failure_kind: monitor_error") print("interpreter_trace:") @@ -301,11 +307,14 @@ def main() -> int: monitor_traces = parse_trace_blocks(monitor.stdout) expected = expected_traces[trace_idx] matched_idx = next( - (i for i, candidate in enumerate(monitor_traces) if candidate == expected), + ( + i + for i, candidate in enumerate(monitor_traces) + if candidate == expected + ), None, ) if matched_idx is None: - any_failures = True print("trace_result: FAIL") print("failure_kind: trace_mismatch") print("interpreter_trace:") @@ -326,7 +335,6 @@ def main() -> int: print("") if len(generated_fsts) < len(expected_traces): - any_failures = True for trace_idx in range(len(generated_fsts), len(expected_traces)): if printed_blocks > 0: print("") @@ -342,7 +350,8 @@ def main() -> int: return 0 finally: - cleanup_generated_fsts(fst_path) + if not args_ns.keep_fst: + cleanup_generated_fsts(fst_path) if __name__ == "__main__": From 5c7b9797a8dc635258afd0c22d7ec78daafb2b8c Mon Sep 17 00:00:00 2001 From: Ernest Ng Date: Mon, 23 Feb 2026 14:18:07 -0500 Subject: [PATCH 13/18] Add allowed-to-fail CLI flag to round-tripping script --- interp/src/main.rs | 4 ++++ scripts/roundtrip_case.py | 12 +++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/interp/src/main.rs b/interp/src/main.rs index 4947d11d..9a911848 100644 --- a/interp/src/main.rs +++ b/interp/src/main.rs @@ -54,6 +54,10 @@ struct Cli { /// of cycles specified with this option. #[arg(long)] max_steps: Option, + + /// Mark this test as allowed to fail (ignored by interpreter, used by test harness) + #[arg(long)] + allowed_to_fail: bool, } /// Examples (enables all tracing logs): diff --git a/scripts/roundtrip_case.py b/scripts/roundtrip_case.py index 5fc29e8d..993ecda4 100644 --- a/scripts/roundtrip_case.py +++ b/scripts/roundtrip_case.py @@ -175,7 +175,8 @@ def format_monitor_trace_candidates(traces: list[list[str]]) -> str: def main() -> int: - """Execute one roundtrip check for a single `.tx` file.""" + """Execute one roundtrip check for a single `.tx` file. If the + interpreter fails with a non-zero exit code, the test is skipped.""" parser = argparse.ArgumentParser( description="Run one roundtrip check for a single .tx file." ) @@ -185,8 +186,17 @@ def main() -> int: action="store_true", help="Do not delete the intermediate .fst waveform file after the check", ) + parser.add_argument( + "--allowed-to-fail", + action="store_true", + help="Mark this test as allowed to fail (will be skipped)", + ) args_ns = parser.parse_args() + if args_ns.allowed_to_fail: + print("SKIP: allowed to fail") + return 0 + tx_file = Path(args_ns.tx_file).resolve() if not tx_file.exists(): return fail(f"Missing tx file: {tx_file}") From ef6e46ed613fbd6e5db01c69e949daac138e0486 Mon Sep 17 00:00:00 2001 From: Ernest Ng Date: Mon, 23 Feb 2026 14:23:15 -0500 Subject: [PATCH 14/18] Rename CLI flag to --allow-round-trip-failure, mark all tests with repeat loops as allowed-to-fail for RT --- interp/src/main.rs | 2 +- protocols/tests/adders/adder_d1/busy_wait_fail.tx | 2 +- protocols/tests/adders/adder_d1/busy_wait_pass.tx | 2 +- protocols/tests/adders/adder_d1/loop_with_assigns.tx | 2 +- protocols/tests/adders/adder_d1/nested_busy_wait.tx | 2 +- protocols/tests/fifo/push_pop_loop_empty.tx | 2 +- protocols/tests/fifo/push_pop_loop_not_empty.tx | 2 +- scripts/roundtrip_case.py | 4 ++-- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/interp/src/main.rs b/interp/src/main.rs index 9a911848..f9684762 100644 --- a/interp/src/main.rs +++ b/interp/src/main.rs @@ -57,7 +57,7 @@ struct Cli { /// Mark this test as allowed to fail (ignored by interpreter, used by test harness) #[arg(long)] - allowed_to_fail: bool, + allow_round_trip_failure: bool, } /// Examples (enables all tracing logs): diff --git a/protocols/tests/adders/adder_d1/busy_wait_fail.tx b/protocols/tests/adders/adder_d1/busy_wait_fail.tx index 3024a150..689c0497 100644 --- a/protocols/tests/adders/adder_d1/busy_wait_fail.tx +++ b/protocols/tests/adders/adder_d1/busy_wait_fail.tx @@ -1,4 +1,4 @@ -// ARGS: --verilog adders/adder_d1/add_d1.v --protocol adders/adder_d1/busy_wait.prot +// ARGS: --verilog adders/adder_d1/add_d1.v --protocol adders/adder_d1/busy_wait.prot --allow-round-trip-failure // RETURN: 101 trace { add_busy_wait(1, 2, 2, 999); // Wrong output value, this transaction fails diff --git a/protocols/tests/adders/adder_d1/busy_wait_pass.tx b/protocols/tests/adders/adder_d1/busy_wait_pass.tx index df87db84..4caca794 100644 --- a/protocols/tests/adders/adder_d1/busy_wait_pass.tx +++ b/protocols/tests/adders/adder_d1/busy_wait_pass.tx @@ -1,4 +1,4 @@ -// ARGS: --verilog adders/adder_d1/add_d1.v --protocol adders/adder_d1/busy_wait.prot +// ARGS: --verilog adders/adder_d1/add_d1.v --protocol adders/adder_d1/busy_wait.prot --allow-round-trip-failure trace { add_busy_wait(1, 2, 1, 3); // Runs busy-waiting loop for 1 iteration add_busy_wait(4, 5, 3, 9); // Runs busy-waiting loop for 3 iterations diff --git a/protocols/tests/adders/adder_d1/loop_with_assigns.tx b/protocols/tests/adders/adder_d1/loop_with_assigns.tx index 14ec302a..998b2568 100644 --- a/protocols/tests/adders/adder_d1/loop_with_assigns.tx +++ b/protocols/tests/adders/adder_d1/loop_with_assigns.tx @@ -1,4 +1,4 @@ -// ARGS: --verilog adders/adder_d1/add_d1.v --protocol adders/adder_d1/loop_with_assigns.prot +// ARGS: --verilog adders/adder_d1/add_d1.v --protocol adders/adder_d1/loop_with_assigns.prot --allow-round-trip-failure trace { loop_add(1, 2, 3, 3); // assert 1+2=3 on each of 3 iterations loop_add(10, 20, 1, 30); // assert 10+20=30 on 1 iteration diff --git a/protocols/tests/adders/adder_d1/nested_busy_wait.tx b/protocols/tests/adders/adder_d1/nested_busy_wait.tx index 6315bb9f..d1f304ee 100644 --- a/protocols/tests/adders/adder_d1/nested_busy_wait.tx +++ b/protocols/tests/adders/adder_d1/nested_busy_wait.tx @@ -1,4 +1,4 @@ -// ARGS: --verilog adders/adder_d1/add_d1.v --protocol adders/adder_d1/nested_busy_wait.prot +// ARGS: --verilog adders/adder_d1/add_d1.v --protocol adders/adder_d1/nested_busy_wait.prot --allow-round-trip-failure trace { nested_busy_wait(1, 2, 2, 3, 3); // 6 inner steps + 2 outer steps = 8 cycles nested_busy_wait(10, 20, 3, 2, 30); // 6 inner steps + 3 outer steps = 9 cycles diff --git a/protocols/tests/fifo/push_pop_loop_empty.tx b/protocols/tests/fifo/push_pop_loop_empty.tx index e58825b4..f3d8d51e 100644 --- a/protocols/tests/fifo/push_pop_loop_empty.tx +++ b/protocols/tests/fifo/push_pop_loop_empty.tx @@ -1,4 +1,4 @@ -// ARGS: --verilog fifo/bsg_mem_1rw_sync.v fifo/bsg_mem_1rw_sync_synth.v fifo/bsg_circular_ptr.v fifo/bsg_fifo_1rw_large.v fifo/fifo_wrapper.v --protocol=fifo/fifo_bounded_loop.prot --module fifo_wrapper +// ARGS: --verilog fifo/bsg_mem_1rw_sync.v fifo/bsg_mem_1rw_sync_synth.v fifo/bsg_circular_ptr.v fifo/bsg_fifo_1rw_large.v fifo/fifo_wrapper.v --protocol=fifo/fifo_bounded_loop.prot --module fifo_wrapper --allow-round-trip-failure trace { reset(); push_n_times(42, 4); // Push 42 four times diff --git a/protocols/tests/fifo/push_pop_loop_not_empty.tx b/protocols/tests/fifo/push_pop_loop_not_empty.tx index 91d75f18..bf8f2d9f 100644 --- a/protocols/tests/fifo/push_pop_loop_not_empty.tx +++ b/protocols/tests/fifo/push_pop_loop_not_empty.tx @@ -1,4 +1,4 @@ -// ARGS: --verilog fifo/bsg_mem_1rw_sync.v fifo/bsg_mem_1rw_sync_synth.v fifo/bsg_circular_ptr.v fifo/bsg_fifo_1rw_large.v fifo/fifo_wrapper.v --protocol=fifo/fifo_bounded_loop.prot --module fifo_wrapper +// ARGS: --verilog fifo/bsg_mem_1rw_sync.v fifo/bsg_mem_1rw_sync_synth.v fifo/bsg_circular_ptr.v fifo/bsg_fifo_1rw_large.v fifo/fifo_wrapper.v --protocol=fifo/fifo_bounded_loop.prot --module fifo_wrapper --allow-round-trip-failure trace { reset(); push_n_times(7, 3); diff --git a/scripts/roundtrip_case.py b/scripts/roundtrip_case.py index 993ecda4..ed68a9dc 100644 --- a/scripts/roundtrip_case.py +++ b/scripts/roundtrip_case.py @@ -187,13 +187,13 @@ def main() -> int: help="Do not delete the intermediate .fst waveform file after the check", ) parser.add_argument( - "--allowed-to-fail", + "--allow-round-trip-failure", action="store_true", help="Mark this test as allowed to fail (will be skipped)", ) args_ns = parser.parse_args() - if args_ns.allowed_to_fail: + if args_ns.allow_round_trip_failure: print("SKIP: allowed to fail") return 0 From 48fab65e2f6c3d9a67e7a1f9fcce3029c3356558 Mon Sep 17 00:00:00 2001 From: Ernest Ng Date: Mon, 23 Feb 2026 14:35:58 -0500 Subject: [PATCH 15/18] Bunch of fixes to allow individual tests to be skipped from round-trips, apply to all tests with repeat loops --- examples/turnt.toml | 2 +- interp/src/main.rs | 5 +++-- .../tests/adders/adder_d1/busy_wait_pass.rt | 14 +------------- .../tests/adders/adder_d1/loop_with_assigns.rt | 14 +------------- .../tests/adders/adder_d1/nested_busy_wait.rt | 14 +------------- protocols/tests/fifo/push_pop_loop_empty.rt | 16 +--------------- protocols/tests/fifo/push_pop_loop_not_empty.rt | 16 +--------------- protocols/tests/turnt.toml | 2 +- scripts/roundtrip_case.py | 10 ++++++---- turnt.toml | 2 +- 10 files changed, 17 insertions(+), 78 deletions(-) diff --git a/examples/turnt.toml b/examples/turnt.toml index c3d1ec29..e0d5fd55 100644 --- a/examples/turnt.toml +++ b/examples/turnt.toml @@ -2,6 +2,6 @@ command = "cargo run --package protocols-interp -- --color never --transactions {filename} {args}" [envs.roundtrip] -command = "uv run ../scripts/roundtrip_case.py {filename}" +command = "uv run ../scripts/roundtrip_case.py {filename} {args}" binary = true output.rt = "-" diff --git a/interp/src/main.rs b/interp/src/main.rs index f9684762..a5c3eb5f 100644 --- a/interp/src/main.rs +++ b/interp/src/main.rs @@ -4,7 +4,7 @@ use clap::ColorChoice; use clap::Parser; -use clap_verbosity_flag::{Verbosity, WarnLevel, log::LevelFilter}; +use clap_verbosity_flag::{log::LevelFilter, Verbosity, WarnLevel}; use protocols::diagnostic::DiagnosticHandler; use protocols::ir::{SymbolTable, Transaction}; use protocols::scheduler::Scheduler; @@ -55,7 +55,8 @@ struct Cli { #[arg(long)] max_steps: Option, - /// Mark this test as allowed to fail (ignored by interpreter, used by test harness) + /// Mark this test as allowed to fail (ignored by interpreter, used only + /// round-trip test harness) #[arg(long)] allow_round_trip_failure: bool, } diff --git a/protocols/tests/adders/adder_d1/busy_wait_pass.rt b/protocols/tests/adders/adder_d1/busy_wait_pass.rt index 983d8a2d..e49c98d6 100644 --- a/protocols/tests/adders/adder_d1/busy_wait_pass.rt +++ b/protocols/tests/adders/adder_d1/busy_wait_pass.rt @@ -1,13 +1 @@ -trace_block: 0 -trace_result: FAIL -failure_kind: monitor_error -interpreter_trace: -trace { - add_busy_wait(1, 2, 1, 3); - add_busy_wait(4, 5, 3, 9); -} - -monitor_error: -not yet implemented: Bounded loops is not yet implemented in the monitor -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace - +SKIP: allowed to fail round trip diff --git a/protocols/tests/adders/adder_d1/loop_with_assigns.rt b/protocols/tests/adders/adder_d1/loop_with_assigns.rt index 98e4d94f..e49c98d6 100644 --- a/protocols/tests/adders/adder_d1/loop_with_assigns.rt +++ b/protocols/tests/adders/adder_d1/loop_with_assigns.rt @@ -1,13 +1 @@ -trace_block: 0 -trace_result: FAIL -failure_kind: monitor_error -interpreter_trace: -trace { - loop_add(1, 2, 3, 3); - loop_add(10, 20, 1, 30); -} - -monitor_error: -not yet implemented: Bounded loops is not yet implemented in the monitor -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace - +SKIP: allowed to fail round trip diff --git a/protocols/tests/adders/adder_d1/nested_busy_wait.rt b/protocols/tests/adders/adder_d1/nested_busy_wait.rt index d2ee2adb..e49c98d6 100644 --- a/protocols/tests/adders/adder_d1/nested_busy_wait.rt +++ b/protocols/tests/adders/adder_d1/nested_busy_wait.rt @@ -1,13 +1 @@ -trace_block: 0 -trace_result: FAIL -failure_kind: monitor_error -interpreter_trace: -trace { - nested_busy_wait(1, 2, 2, 3, 3); - nested_busy_wait(10, 20, 3, 2, 30); -} - -monitor_error: -not yet implemented: Bounded loops is not yet implemented in the monitor -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace - +SKIP: allowed to fail round trip diff --git a/protocols/tests/fifo/push_pop_loop_empty.rt b/protocols/tests/fifo/push_pop_loop_empty.rt index 230f43de..e49c98d6 100644 --- a/protocols/tests/fifo/push_pop_loop_empty.rt +++ b/protocols/tests/fifo/push_pop_loop_empty.rt @@ -1,15 +1 @@ -trace_block: 0 -trace_result: FAIL -failure_kind: monitor_error -interpreter_trace: -trace { - reset(); - push_n_times(42, 4); - pop_n_times(42, 4); - check_empty(); -} - -monitor_error: -not yet implemented: Bounded loops is not yet implemented in the monitor -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace - +SKIP: allowed to fail round trip diff --git a/protocols/tests/fifo/push_pop_loop_not_empty.rt b/protocols/tests/fifo/push_pop_loop_not_empty.rt index c02dc659..e49c98d6 100644 --- a/protocols/tests/fifo/push_pop_loop_not_empty.rt +++ b/protocols/tests/fifo/push_pop_loop_not_empty.rt @@ -1,15 +1 @@ -trace_block: 0 -trace_result: FAIL -failure_kind: monitor_error -interpreter_trace: -trace { - reset(); - push_n_times(7, 3); - pop_n_times(7, 2); - check_not_empty(); -} - -monitor_error: -not yet implemented: Bounded loops is not yet implemented in the monitor -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace - +SKIP: allowed to fail round trip diff --git a/protocols/tests/turnt.toml b/protocols/tests/turnt.toml index c57fc6f0..fab701a1 100644 --- a/protocols/tests/turnt.toml +++ b/protocols/tests/turnt.toml @@ -2,6 +2,6 @@ command = "cargo run --package protocols-interp -- --color never --transactions {filename} {args}" [envs.roundtrip] -command = "uv run ../../scripts/roundtrip_case.py {filename}" +command = "uv run ../../scripts/roundtrip_case.py {filename} {args}" binary = true output.rt = "-" diff --git a/scripts/roundtrip_case.py b/scripts/roundtrip_case.py index ed68a9dc..1d1f73bc 100644 --- a/scripts/roundtrip_case.py +++ b/scripts/roundtrip_case.py @@ -7,6 +7,7 @@ import argparse import re +import shlex import subprocess import traceback from pathlib import Path @@ -193,10 +194,6 @@ def main() -> int: ) args_ns = parser.parse_args() - if args_ns.allow_round_trip_failure: - print("SKIP: allowed to fail") - return 0 - tx_file = Path(args_ns.tx_file).resolve() if not tx_file.exists(): return fail(f"Missing tx file: {tx_file}") @@ -208,6 +205,11 @@ def main() -> int: return 0 args = args_match.group(1) + # Check if --allow-round-trip-failure is present in the file's // ARGS line + if "--allow-round-trip-failure" in args: + print("SKIP: allowed to fail round trip") + return 0 + return_match = re.search(r"^// RETURN:\s*(\d+)", tx_text, re.MULTILINE) if return_match and int(return_match.group(1)) != 0: print("SKIP: non-zero // RETURN") diff --git a/turnt.toml b/turnt.toml index 995ecba7..ccf06cff 100644 --- a/turnt.toml +++ b/turnt.toml @@ -1,6 +1,6 @@ command = "cargo run --package protocols-interp -- --color never --transactions {filename} {args}" [envs.roundtrip] -command = "uv run scripts/roundtrip_case.py {filename}" +command = "uv run scripts/roundtrip_case.py {filename} {args}" binary = true output.rt = "-" From 2a4a1a4b680263582ad3ffcf5bca1955d1d7a90a Mon Sep 17 00:00:00 2001 From: Ernest Ng Date: Mon, 23 Feb 2026 14:38:28 -0500 Subject: [PATCH 16/18] Formatting --- interp/src/main.rs | 2 +- scripts/roundtrip_case.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/interp/src/main.rs b/interp/src/main.rs index a5c3eb5f..71c3a6c4 100644 --- a/interp/src/main.rs +++ b/interp/src/main.rs @@ -4,7 +4,7 @@ use clap::ColorChoice; use clap::Parser; -use clap_verbosity_flag::{log::LevelFilter, Verbosity, WarnLevel}; +use clap_verbosity_flag::{Verbosity, WarnLevel, log::LevelFilter}; use protocols::diagnostic::DiagnosticHandler; use protocols::ir::{SymbolTable, Transaction}; use protocols::scheduler::Scheduler; diff --git a/scripts/roundtrip_case.py b/scripts/roundtrip_case.py index 1d1f73bc..76d556b7 100644 --- a/scripts/roundtrip_case.py +++ b/scripts/roundtrip_case.py @@ -7,7 +7,6 @@ import argparse import re -import shlex import subprocess import traceback from pathlib import Path From aa039edc671d30eb98a45b38864783d133af811f Mon Sep 17 00:00:00 2001 From: Ernest Ng Date: Mon, 23 Feb 2026 14:43:39 -0500 Subject: [PATCH 17/18] Only print name of fst file if user explicitly specifies it --- scripts/roundtrip_case.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/roundtrip_case.py b/scripts/roundtrip_case.py index 76d556b7..6dea7c42 100644 --- a/scripts/roundtrip_case.py +++ b/scripts/roundtrip_case.py @@ -277,7 +277,8 @@ def main() -> int: print("---") print("") print(f"trace_block: {trace_idx}") - print(f"fst_file: {relpath_str(generated_fst, base_dir)}") + if args_ns.keep_fst: + print(f"fst_file: {relpath_str(generated_fst, base_dir)}") printed_blocks += 1 if trace_idx >= len(expected_traces): print("trace_result: FAIL") From 374ecedb3f2fd98e89388539510ad9ac6832d187 Mon Sep 17 00:00:00 2001 From: Ernest Ng Date: Mon, 23 Feb 2026 14:46:43 -0500 Subject: [PATCH 18/18] Update another .rt file --- protocols/tests/adders/adder_d1/busy_wait_fail.rt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocols/tests/adders/adder_d1/busy_wait_fail.rt b/protocols/tests/adders/adder_d1/busy_wait_fail.rt index d79ced8c..e49c98d6 100644 --- a/protocols/tests/adders/adder_d1/busy_wait_fail.rt +++ b/protocols/tests/adders/adder_d1/busy_wait_fail.rt @@ -1 +1 @@ -SKIP: non-zero // RETURN +SKIP: allowed to fail round trip