Skip to content

Commit 22656d8

Browse files
committed
Add event reference checking to gpu_sim
Compare GPU UART output against a reference events JSON file (from chipflow-examples) to verify simulation correctness. All 67 reference event payloads match byte-for-byte. Changes: - Add events_reference field to TestbenchConfig - Add Clone/Deserialize to UartEvent for loading reference - gpu_sim: compare payload sequences after simulation, exit(1) on mismatch - sim_config.json: add output_events + events_reference paths - Copy events_reference.json from chipflow-examples/minimal - Fix Python events.py to accept both field name conventions Co-developed-by: Claude Code v2.1.42 (claude-opus-4-6)
1 parent e446784 commit 22656d8

5 files changed

Lines changed: 145 additions & 6 deletions

File tree

scripts/chipflow_harness/src/chipflow_harness/events.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,14 @@ def parse_events_json(path: Path) -> list[Event]:
3131

3232
events = []
3333
for item in data.get("events", []):
34+
# Support both field name conventions:
35+
# "timestamp"/"event" (Rust UartEvent, chipflow-examples reference)
36+
# "time_ps"/"type" (legacy)
3437
events.append(
3538
Event(
36-
time_ps=item.get("time_ps", 0),
39+
time_ps=item.get("timestamp", item.get("time_ps", 0)),
3740
peripheral=item.get("peripheral", ""),
38-
event_type=item.get("type", ""),
41+
event_type=item.get("event", item.get("type", "")),
3942
payload=item.get("payload"),
4043
)
4144
)

src/bin/gpu_sim.rs

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2444,7 +2444,7 @@ fn main() {
24442444
events: Vec<gem::testbench::UartEvent>,
24452445
}
24462446
let output = EventsOutput {
2447-
events: uart_events,
2447+
events: uart_events.clone(),
24482448
};
24492449
let json = serde_json::to_string_pretty(&output).expect("Failed to serialize events");
24502450
let mut file = File::create(output_path).expect("Failed to create events file");
@@ -2454,6 +2454,63 @@ fn main() {
24542454
clilog::info!("Wrote events to {}", output_path);
24552455
}
24562456

2457+
// ── Event reference comparison ───────────────────────────────────────
2458+
2459+
let mut events_passed = true;
2460+
if let Some(ref ref_path) = config.events_reference {
2461+
#[derive(serde::Deserialize)]
2462+
struct EventsFile {
2463+
events: Vec<gem::testbench::UartEvent>,
2464+
}
2465+
let ref_file = std::fs::read_to_string(ref_path)
2466+
.unwrap_or_else(|e| panic!("Failed to read events reference {}: {}", ref_path, e));
2467+
let reference: EventsFile = serde_json::from_str(&ref_file)
2468+
.unwrap_or_else(|e| panic!("Failed to parse events reference {}: {}", ref_path, e));
2469+
2470+
let ref_events = &reference.events;
2471+
let ref_payloads: Vec<u8> = ref_events.iter().map(|e| e.payload).collect();
2472+
let actual_payloads: Vec<u8> = uart_events.iter().map(|e| e.payload).collect();
2473+
2474+
println!();
2475+
println!("=== Event Reference Check ===");
2476+
println!("Reference: {} events from {}", ref_events.len(), ref_path);
2477+
println!("Actual: {} events", uart_events.len());
2478+
2479+
if ref_payloads.len() > actual_payloads.len() {
2480+
println!("FAIL: missing {} events (got {}, expected {})",
2481+
ref_payloads.len() - actual_payloads.len(),
2482+
actual_payloads.len(), ref_payloads.len());
2483+
println!(" Hint: increase --max-cycles (last reference event at timestamp {})",
2484+
ref_events.last().map(|e| e.timestamp).unwrap_or(0));
2485+
events_passed = false;
2486+
} else {
2487+
let mut mismatches = 0;
2488+
for (i, (expected, actual)) in ref_payloads.iter().zip(actual_payloads.iter()).enumerate() {
2489+
if expected != actual {
2490+
if mismatches < 10 {
2491+
let ref_ts = ref_events[i].timestamp;
2492+
let act_ts = uart_events[i].timestamp;
2493+
println!(" MISMATCH event {}: expected 0x{:02X} (ref ts={}), got 0x{:02X} (tick={})",
2494+
i, expected, ref_ts, actual, act_ts);
2495+
}
2496+
mismatches += 1;
2497+
}
2498+
}
2499+
2500+
if mismatches > 0 {
2501+
println!("FAIL: {} payload mismatches out of {} events", mismatches, ref_payloads.len());
2502+
events_passed = false;
2503+
} else {
2504+
// Decode the matched message for display
2505+
let decoded: String = actual_payloads.iter().map(|&b| {
2506+
if b >= 32 && b < 127 { b as char } else { '.' }
2507+
}).collect();
2508+
println!("PASS: all {} event payloads match", ref_payloads.len());
2509+
println!(" Decoded: \"{}\"", decoded);
2510+
}
2511+
}
2512+
}
2513+
24572514
// ── Optional CPU verification ────────────────────────────────────────
24582515

24592516
if args.check_with_cpu {
@@ -2474,5 +2531,10 @@ fn main() {
24742531
}
24752532

24762533
println!();
2477-
println!("SIMULATION: PASSED");
2534+
if events_passed {
2535+
println!("SIMULATION: PASSED");
2536+
} else {
2537+
println!("SIMULATION: FAILED (event mismatch)");
2538+
std::process::exit(1);
2539+
}
24782540
}

src/testbench.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ pub struct TestbenchConfig {
208208
pub gpios: Vec<GpioConfig>,
209209
pub sram_init: Option<SramInitConfig>,
210210
pub output_events: Option<String>,
211+
pub events_reference: Option<String>,
211212
}
212213

213214
#[derive(Debug, Clone, Deserialize)]
@@ -249,7 +250,7 @@ pub enum UartState {
249250
}
250251

251252
/// Decoded UART event.
252-
#[derive(Debug, Serialize)]
253+
#[derive(Debug, Clone, Serialize, Deserialize)]
253254
pub struct UartEvent {
254255
pub timestamp: usize,
255256
pub peripheral: String,
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
{
2+
"events": [
3+
{ "timestamp": 53638, "peripheral": "uart_0", "event": "tx", "payload": 240 },
4+
{ "timestamp": 74102, "peripheral": "uart_0", "event": "tx", "payload": 159 },
5+
{ "timestamp": 94566, "peripheral": "uart_0", "event": "tx", "payload": 144 },
6+
{ "timestamp": 115030, "peripheral": "uart_0", "event": "tx", "payload": 177 },
7+
{ "timestamp": 135494, "peripheral": "uart_0", "event": "tx", "payload": 58 },
8+
{ "timestamp": 155958, "peripheral": "uart_0", "event": "tx", "payload": 32 },
9+
{ "timestamp": 176422, "peripheral": "uart_0", "event": "tx", "payload": 110 },
10+
{ "timestamp": 196886, "peripheral": "uart_0", "event": "tx", "payload": 121 },
11+
{ "timestamp": 217350, "peripheral": "uart_0", "event": "tx", "payload": 97 },
12+
{ "timestamp": 237814, "peripheral": "uart_0", "event": "tx", "payload": 97 },
13+
{ "timestamp": 258278, "peripheral": "uart_0", "event": "tx", "payload": 126 },
14+
{ "timestamp": 278742, "peripheral": "uart_0", "event": "tx", "payload": 33 },
15+
{ "timestamp": 299206, "peripheral": "uart_0", "event": "tx", "payload": 13 },
16+
{ "timestamp": 324428, "peripheral": "uart_0", "event": "tx", "payload": 13 },
17+
{ "timestamp": 332238, "peripheral": "uart_0", "event": "tx", "payload": 10 },
18+
{ "timestamp": 362216, "peripheral": "uart_0", "event": "tx", "payload": 83 },
19+
{ "timestamp": 382680, "peripheral": "uart_0", "event": "tx", "payload": 111 },
20+
{ "timestamp": 403144, "peripheral": "uart_0", "event": "tx", "payload": 67 },
21+
{ "timestamp": 423608, "peripheral": "uart_0", "event": "tx", "payload": 32 },
22+
{ "timestamp": 444072, "peripheral": "uart_0", "event": "tx", "payload": 116 },
23+
{ "timestamp": 464536, "peripheral": "uart_0", "event": "tx", "payload": 121 },
24+
{ "timestamp": 485000, "peripheral": "uart_0", "event": "tx", "payload": 112 },
25+
{ "timestamp": 505464, "peripheral": "uart_0", "event": "tx", "payload": 101 },
26+
{ "timestamp": 525928, "peripheral": "uart_0", "event": "tx", "payload": 58 },
27+
{ "timestamp": 546392, "peripheral": "uart_0", "event": "tx", "payload": 32 },
28+
{ "timestamp": 580032, "peripheral": "uart_0", "event": "tx", "payload": 67 },
29+
{ "timestamp": 607056, "peripheral": "uart_0", "event": "tx", "payload": 65 },
30+
{ "timestamp": 631964, "peripheral": "uart_0", "event": "tx", "payload": 55 },
31+
{ "timestamp": 658988, "peripheral": "uart_0", "event": "tx", "payload": 70 },
32+
{ "timestamp": 683896, "peripheral": "uart_0", "event": "tx", "payload": 49 },
33+
{ "timestamp": 708804, "peripheral": "uart_0", "event": "tx", "payload": 48 },
34+
{ "timestamp": 733712, "peripheral": "uart_0", "event": "tx", "payload": 48 },
35+
{ "timestamp": 760604, "peripheral": "uart_0", "event": "tx", "payload": 70 },
36+
{ "timestamp": 791906, "peripheral": "uart_0", "event": "tx", "payload": 13 },
37+
{ "timestamp": 817128, "peripheral": "uart_0", "event": "tx", "payload": 13 },
38+
{ "timestamp": 824938, "peripheral": "uart_0", "event": "tx", "payload": 10 },
39+
{ "timestamp": 854916, "peripheral": "uart_0", "event": "tx", "payload": 70 },
40+
{ "timestamp": 875380, "peripheral": "uart_0", "event": "tx", "payload": 108 },
41+
{ "timestamp": 895844, "peripheral": "uart_0", "event": "tx", "payload": 97 },
42+
{ "timestamp": 916308, "peripheral": "uart_0", "event": "tx", "payload": 115 },
43+
{ "timestamp": 936772, "peripheral": "uart_0", "event": "tx", "payload": 104 },
44+
{ "timestamp": 957236, "peripheral": "uart_0", "event": "tx", "payload": 32 },
45+
{ "timestamp": 977700, "peripheral": "uart_0", "event": "tx", "payload": 73 },
46+
{ "timestamp": 998164, "peripheral": "uart_0", "event": "tx", "payload": 68 },
47+
{ "timestamp": 1018628, "peripheral": "uart_0", "event": "tx", "payload": 58 },
48+
{ "timestamp": 1039092, "peripheral": "uart_0", "event": "tx", "payload": 32 },
49+
{ "timestamp": 1695416, "peripheral": "uart_0", "event": "tx", "payload": 67 },
50+
{ "timestamp": 1722440, "peripheral": "uart_0", "event": "tx", "payload": 65 },
51+
{ "timestamp": 1747348, "peripheral": "uart_0", "event": "tx", "payload": 55 },
52+
{ "timestamp": 1774372, "peripheral": "uart_0", "event": "tx", "payload": 67 },
53+
{ "timestamp": 1801396, "peripheral": "uart_0", "event": "tx", "payload": 65 },
54+
{ "timestamp": 1826304, "peripheral": "uart_0", "event": "tx", "payload": 55 },
55+
{ "timestamp": 1853328, "peripheral": "uart_0", "event": "tx", "payload": 70 },
56+
{ "timestamp": 1880220, "peripheral": "uart_0", "event": "tx", "payload": 70 },
57+
{ "timestamp": 1916280, "peripheral": "uart_0", "event": "tx", "payload": 13 },
58+
{ "timestamp": 1924090, "peripheral": "uart_0", "event": "tx", "payload": 10 },
59+
{ "timestamp": 3705006, "peripheral": "uart_0", "event": "tx", "payload": 81 },
60+
{ "timestamp": 3714382, "peripheral": "uart_0", "event": "tx", "payload": 117 },
61+
{ "timestamp": 3723758, "peripheral": "uart_0", "event": "tx", "payload": 97 },
62+
{ "timestamp": 3733134, "peripheral": "uart_0", "event": "tx", "payload": 100 },
63+
{ "timestamp": 3742510, "peripheral": "uart_0", "event": "tx", "payload": 32 },
64+
{ "timestamp": 3751886, "peripheral": "uart_0", "event": "tx", "payload": 109 },
65+
{ "timestamp": 3761262, "peripheral": "uart_0", "event": "tx", "payload": 111 },
66+
{ "timestamp": 3770638, "peripheral": "uart_0", "event": "tx", "payload": 100 },
67+
{ "timestamp": 3780014, "peripheral": "uart_0", "event": "tx", "payload": 101 },
68+
{ "timestamp": 3791556, "peripheral": "uart_0", "event": "tx", "payload": 13 },
69+
{ "timestamp": 3797246, "peripheral": "uart_0", "event": "tx", "payload": 10 }
70+
]
71+
}

tests/timing_test/sim_config.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,7 @@
1818
"tx_gpio": 6,
1919
"rx_gpio": 7,
2020
"baud_rate": 115200
21-
}
21+
},
22+
"output_events": "tests/timing_test/gpu_events.json",
23+
"events_reference": "tests/timing_test/events_reference.json"
2224
}

0 commit comments

Comments
 (0)