Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 36 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,44 @@

A CHI-protocol cache-coherent SoC simulator built with simcpp20 coroutines.

The simulator is loosely based on SystemC TLM-2.0 conventions — modules communicate via ports with on-receive callbacks, payloads carry protocol-specific extensions, and a discrete-event scheduler advances simulation time. The substantive departure is using C++20 coroutines rather than SystemC processes, which allows each transaction to be modeled as a top-to-bottom protocol flow rather than a distributed state machine.
The simulator is loosely based on SystemC TLM-2.0 conventions — modules communicate via ports with on-receive callbacks,
payloads carry protocol-specific extensions, and a discrete-event scheduler advances simulation time. The substantive
departure is using C++20 coroutines rather than SystemC processes, which allows each transaction to be modeled as a
top-to-bottom protocol flow rather than a distributed state machine.

## What it models

- An **initiator** that issues ReadShared and WriteUniqueFull transactions on a cycle-driven schedule.
- A **home agent** with a metadata-only cache, handling reads (forward to target on miss, direct response on hit) and writes (absorb locally, install line on data arrival). Each transaction runs as its own coroutine; address serialization is enforced by a TransactionQueue.
- A **home agent** with a metadata-only cache, handling reads (forward to target on miss, direct response on hit) and
writes (absorb locally, install line on data arrival). Each transaction runs as its own coroutine; address
serialization is enforced by a TransactionQueue.
- A **target** that services read requests with a configurable latency.
- An **interconnect** that routes flits between modules by target id.

CHI transactions terminate correctly: reads via CompAck, writes via combined CompDBIDResp + NCBWrData.

## Approach

The simulator uses a **coroutine-per-transaction** model in the home agent. Each incoming REQ spawns a coroutine that runs the full protocol flow top-to-bottom — cache lookup, optional refill, response, completion wait — with `co_await` at each protocol pause. Address-serialization is enforced by a TransactionQueue: transactions acquire a slot at coroutine entry, and same-address transactions queue behind the active head.
The simulator uses a **coroutine-per-transaction** model in the home agent. Each incoming REQ spawns a coroutine that
runs the full protocol flow top-to-bottom — cache lookup, optional refill, response, completion wait — with `co_await`
at each protocol pause. Address-serialization is enforced by a TransactionQueue: transactions acquire a slot at
coroutine entry, and same-address transactions queue behind the active head.

This makes the protocol logic read as the protocol it models, rather than being distributed across callbacks and state-machine maps.
This makes the protocol logic read as the protocol it models, rather than being distributed across callbacks and
state-machine maps.

## Topology and configuration

The SoC layout is described by a JSON topology file. Each module declares its name, type, id, neighbors, and per-module configuration values. The topology loader constructs modules, applies their config, and wires ports based on the neighbor lists.
The SoC layout is described by a JSON topology file. Each module declares its name, type, id, neighbors, and per-module
configuration values. The topology loader constructs modules, applies their config, and wires ports based on the
neighbor lists.

```bash
./coroutine_sim --topology example/topology.json
```

Per-module parameters (clock period, latencies, queue capacities, etc.) are exposed as knobs and can be overridden from the command line or a separate config file:
Per-module parameters (clock period, latencies, queue capacities, etc.) are exposed as knobs and can be overridden from
the command line or a separate config file:

```bash
./coroutine_sim --topology example/topology.json --ha0.cache_hit_latency_cycles 5
Expand All @@ -41,15 +53,24 @@ Per-module parameters (clock period, latencies, queue capacities, etc.) are expo

The example topology under `example/topology.json` shows a minimal initiator → interconnect → home agent → target chain.

To experiment with config overrides:

```bash
# Use the example config as a starting point
./coroutine_sim --topology example/topology.json --json example/default_config.json
```

## Tracing

The simulator emits structured events to `trace.jsonl` (one JSON event per line, crash-safe) and a human-readable `trace.txt`. The JSONL output is convertible to Chrome Trace format for visualization in Perfetto:
The simulator emits structured events to `trace.jsonl` (one JSON event per line, crash-safe) and a human-readable
`trace.txt`. The JSONL output is convertible to Chrome Trace format for visualization in Perfetto:

```bash
python3 scripts/jsonl_to_perfetto.py trace.jsonl trace.json
```

Open `trace.json` in https://ui.perfetto.dev. Each transaction appears as a track; per-flit events appear as rows within the track.
Open `trace.json` in https://ui.perfetto.dev. Each transaction appears as a track; per-flit events appear as rows within
the track.

## Project layout

Expand Down Expand Up @@ -87,7 +108,8 @@ Dependencies (simcpp20, magic_enum, nlohmann/json, googletest) are fetched autom

## Code style

The project follows the rules in `.clang-format`. CI verifies formatting using **clang-format 18**; using a matching version locally is recommended to avoid spurious diffs.
The project follows the rules in `.clang-format`. CI verifies formatting using **clang-format 18**; using a matching
version locally is recommended to avoid spurious diffs.

To check formatting locally:

Expand All @@ -103,6 +125,9 @@ find include src test -type f \( -name "*.cpp" -o -name "*.h" -o -name "*.hpp" \

## Status

Functional for ReadShared and WriteUniqueFull with JSON-driven topology, per-module knob configuration, and TransactionQueue-based address hazard handling.
Functional for ReadShared and WriteUniqueFull with JSON-driven topology, per-module knob configuration, and
TransactionQueue-based address hazard handling.

Planned: multiple initiators, ReadUnique / MakeUnique opcodes, snoop modeling (with structured per-peer expectations), DMT (Direct Memory Transfer) variants, eviction modeling, statistics infrastructure, and System Address Map for routing by address across multiple HNs.
Planned: multiple initiators, ReadUnique / MakeUnique opcodes, snoop modeling (with structured per-peer expectations),
DMT (Direct Memory Transfer) variants, eviction modeling, statistics infrastructure, and System Address Map for routing
by address across multiple HNs.
20 changes: 20 additions & 0 deletions example/default_config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"global": {
"output_dir": "output"
},
"ha0": {
"cache_hit_latency_cycles": 3,
"clock_period_ps": 1000,
"downstream_target_id": 2,
"pipeline_latency_cycles": 5,
"tq_capacity": 8
},
"init0": {
"clock_period_ps": 1000,
"home_id": 1
},
"tgt0": {
"clock_period_ps": 1000,
"data_latency_cycles": 50
}
}
51 changes: 51 additions & 0 deletions example/default_config.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Configuration file generated by csim::config
# Usage: ./program --config output/config_used.txt

# Module: global
# ----------------------------------------------------------------------
# Directory for trace and config outputs
# Type: string
global.output_dir = output

# Module: init0
# ----------------------------------------------------------------------
# Clock period in picoseconds
# Type: int
init0.clock_period_ps = 1000

# Home agent ID for transactions
# Type: int
init0.home_id = 1

# Module: ha0
# ----------------------------------------------------------------------
# Clock period in picoseconds
# Type: int
ha0.clock_period_ps = 1000

# Target agent ID for transactions
# Type: int
ha0.downstream_target_id = 2

# Cache hit latency in cycles
# Type: int
ha0.cache_hit_latency_cycles = 3

# Pipeline latency in cycles
# Type: int
ha0.pipeline_latency_cycles = 5

# Number of TQ entries
# Type: int
ha0.tq_capacity = 8

# Module: tgt0
# ----------------------------------------------------------------------
# Clock period in picoseconds
# Type: int
tgt0.clock_period_ps = 1000

# Data response latency in cycles
# Type: int
tgt0.data_latency_cycles = 50

Loading