From 4e7d4e3d2abfcffbf4cfb4e1af7ff13652744649 Mon Sep 17 00:00:00 2001 From: Zachary Ankenman Date: Sat, 23 May 2026 15:17:30 -0700 Subject: [PATCH 1/4] Add JSON topology loading MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduces TopologyLoader to construct and wire SoC modules from a JSON file, replacing the hardcoded topology in main.cpp. Topology file format: - modules: array of {name, type, id, neighbors, config} - module types: initiator, home_agent, target, interconnect - neighbors: list of module names this module connects to (symmetric; loader dedupes when the same edge appears in both endpoints' lists) - config: per-module knob overrides The loader: - Parses JSON, validates schema and module types - Constructs each module via a type-specific factory method - Applies per-module config blocks to the knob system - Wires neighbors by allocating ports keyed by neighbor id and binding the resulting port pairs Module refactoring for topology-driven construction: - Initiator, HomeAgent, Target: constructor takes only (sim, sys, id, name); previously type-specific args like clock_period_ps, home_id, downstream_target_id, and data_latency_cycles. These are now knobs, captured in elaborate(). - WorkQueues and TransactionQueue (which depend on clock_period_ps or tq_capacity) become unique_ptr members, constructed in elaborate() after knobs are finalized. - Port management moves to Module base: each module owns a port_map keyed by neighbor id, via add_port(neighbor_id) and get_port(...). Single-port agents use single_port() helper. - Callback registration (on_receive) moves to elaborate(), running after the loader has allocated ports. - Interconnect's attach() removed; the loader's wire_neighbors handles what attach used to do. Port: store peer as a pointer instead of snapshotting the callback at bind time. This allows on_receive to be registered after bind, which the new construction order requires. Main.cpp: phases reduced to parse_command_line (non-strict) → loader.load(topology_file) → check_for_help → parse_command_line (strict) → elaborate_all → tracer setup → start_all → run. Adds --topology command-line flag handled in csim::config alongside --config and --json. Tests: topology_loader_test covers smoke, construction, config block application, neighbor wiring, and error cases (duplicate names, unknown types, unknown neighbors). --- example/topology.json | 43 ++++++ include/csim/config/config.h | 1 + include/csim/config/topology_loader.h | 38 ++++++ include/csim/core/module.h | 8 ++ include/csim/core/port.h | 25 ++-- include/models/home_agent.h | 39 +++--- include/models/initiator.h | 14 +- include/models/interconnect.h | 11 +- include/models/target.h | 21 ++- src/CMakeLists.txt | 1 + src/csim/config/config.cpp | 23 +++- src/csim/config/topology_loader.cpp | 180 ++++++++++++++++++++++++++ src/csim/core/system.cpp | 20 +++ src/main.cpp | 46 +++---- src/models/home_agent.cpp | 64 +++++---- src/models/initiator.cpp | 37 ++++-- src/models/interconnect.cpp | 24 ++-- src/models/target.cpp | 29 +++-- test/CMakeLists.txt | 1 + test/topology_loader_test.cpp | 167 ++++++++++++++++++++++++ 20 files changed, 662 insertions(+), 130 deletions(-) create mode 100644 example/topology.json create mode 100644 include/csim/config/topology_loader.h create mode 100644 src/csim/config/topology_loader.cpp create mode 100644 test/topology_loader_test.cpp diff --git a/example/topology.json b/example/topology.json new file mode 100644 index 0000000..d41e0b4 --- /dev/null +++ b/example/topology.json @@ -0,0 +1,43 @@ +{ + "modules": [ + { + "name": "init0", + "type": "initiator", + "id": 0, + "neighbors": ["ic0"], + "config": { + "clock_period_ps": 1000, + "home_id": 1 + } + }, + { + "name": "ic0", + "type": "interconnect", + "id": 100, + "neighbors": ["init0", "ha0", "tgt0"] + }, + { + "name": "ha0", + "type": "home_agent", + "id": 1, + "neighbors": ["ic0"], + "config": { + "clock_period_ps": 1000, + "downstream_target_id": 2, + "cache_hit_latency_cycles": 3, + "pipeline_latency_cycles": 5, + "tq_capacity": 8 + } + }, + { + "name": "tgt0", + "type": "target", + "id": 2, + "neighbors": ["ic0"], + "config": { + "clock_period_ps": 1000, + "data_latency_cycles": 50 + } + } + ] +} \ No newline at end of file diff --git a/include/csim/config/config.h b/include/csim/config/config.h index 2f5258d..c1c39d6 100644 --- a/include/csim/config/config.h +++ b/include/csim/config/config.h @@ -25,6 +25,7 @@ auto write_json_file(const std::string& filename) -> void; auto print_help() -> void; auto check_for_help(int argc, char* argv[]) -> void; auto get_knob(const std::string& full_name) -> KnobBase*; +auto get_topology_file() -> std::string; // Lifecycle auto reset_all() -> void; diff --git a/include/csim/config/topology_loader.h b/include/csim/config/topology_loader.h new file mode 100644 index 0000000..1d4e798 --- /dev/null +++ b/include/csim/config/topology_loader.h @@ -0,0 +1,38 @@ +#pragma once + +#include "csim/core/module.h" +#include "csim/core/sim_types.h" +#include "csim/core/system.h" + +#include + +#include +#include +#include + +namespace csim { + +class TopologyLoader { +public: + TopologyLoader(sim_t& sim, System& sys); + + auto load(const std::string& filename) -> void; + auto get_module(const std::string& name) const -> Module*; + +private: + sim_t& sim; + System& sys; + + std::unordered_map> modules; + + auto construct_module(const nlohmann::json& spec) -> void; + auto construct_initiator(const nlohmann::json& spec) -> std::unique_ptr; + auto construct_home_agent(const nlohmann::json& spec) -> std::unique_ptr; + auto construct_target(const nlohmann::json& spec) -> std::unique_ptr; + auto construct_interconnect(const nlohmann::json& spec) -> std::unique_ptr; + auto apply_module_config(const std::string& name, const nlohmann::json& config) -> void; + auto wire_neighbors(const nlohmann::json& spec, + std::set>& seen) -> void; +}; + +} // namespace csim diff --git a/include/csim/core/module.h b/include/csim/core/module.h index e820e9d..95a776b 100644 --- a/include/csim/core/module.h +++ b/include/csim/core/module.h @@ -5,6 +5,7 @@ #include "sim_types.h" #include "csim/tracing/tracer.h" +#include "csim/core/port.h" namespace csim { @@ -24,6 +25,9 @@ class Module { [[nodiscard]] auto id() const -> uint32_t { return stored_id; } + auto add_port(uint32_t neighbor_id) -> Port&; + auto get_port(uint32_t neighbor_id) -> Port&; + sim_t& sim; const std::string name; @@ -33,6 +37,10 @@ class Module { protected: tracing::Tracer& tracer = tracing::Tracer::instance(); + std::unordered_map> port_map; + + auto single_port() const -> Port&; + private: uint32_t stored_id; }; diff --git a/include/csim/core/port.h b/include/csim/core/port.h index 5b2019a..452802e 100644 --- a/include/csim/core/port.h +++ b/include/csim/core/port.h @@ -1,35 +1,38 @@ #pragma once #include -#include #include "csim/core/sim_types.h" #include "payload.h" namespace csim { + class Port { public: using callback_t = std::function; - template auto on_receive(Self* self, void (Self::*method)(payload_ptr)) -> void + template + auto on_receive(Self* self, void (Self::*method)(payload_ptr)) -> void { rx_ = [self, method](payload_ptr p) -> auto { (self->*method)(std::move(p)); }; } - auto send(payload_ptr p) -> void { peer_rx_(std::move(p)); } - - [[nodiscard]] auto rx() const -> callback_t { return rx_; } + auto send(payload_ptr p) -> void { + peer_->rx_(std::move(p)); + } - auto set_peer(callback_t peer_rx) -> void { peer_rx_ = std::move(peer_rx); } + auto set_peer(Port* peer) -> void { peer_ = peer; } private: callback_t rx_; - callback_t peer_rx_; + Port* peer_ = nullptr; + + friend auto bind(Port& a, Port& b) -> void; }; -inline auto -bind(Port& a, Port& b) -> void +inline auto bind(Port& a, Port& b) -> void { - a.set_peer(b.rx()); - b.set_peer(a.rx()); + a.peer_ = &b; + b.peer_ = &a; } + } // namespace csim \ No newline at end of file diff --git a/include/models/home_agent.h b/include/models/home_agent.h index fb5af0e..d06b0fc 100644 --- a/include/models/home_agent.h +++ b/include/models/home_agent.h @@ -10,6 +10,7 @@ #include "csim/core/sim_types.h" #include "csim/utilities/work_queue.h" #include "csim/utilities/cache.h" +#include "csim/config/knob_system.h" #include "models/transaction_inbox.h" #include "models/transaction_queue.h" @@ -17,11 +18,9 @@ namespace csim { class HomeAgent : public Module { public: - Port port; - - HomeAgent(sim_t& sim, System& sys, uint32_t id, std::string name, uint32_t downstream_target_id, - time_ps clock_period_ps); + HomeAgent(sim_t& sim, System& sys, uint32_t id, std::string name); + auto elaborate() -> void override; auto start() -> void override; private: @@ -31,18 +30,32 @@ class HomeAgent : public Module { ~InboxGuard() { ha.inboxes.erase(txn_uid); } }; - uint32_t downstream_target_id; + KnobList& knob_list; + Knob& clock_period_ps_knob = + knob_list.add_knob("clock_period_ps", "Clock period in picoseconds", 1000); + Knob& downstream_target_id_knob = + knob_list.add_knob("downstream_target_id", "Target agent ID for transactions", 1); + Knob& cache_hit_latency_cycles_knob = + knob_list.add_knob("cache_hit_latency_cycles", "Cache hit latency in cycles", 3); + Knob& pipeline_latency_cycles_knob = + knob_list.add_knob("pipeline_latency_cycles", "Pipeline latency in cycles", 5); + Knob& tq_capacity_knob = + knob_list.add_knob("tq_capacity", "Number of TQ entries", 16); + + // Captured at elaborate: time_ps clock_period_ps; + uint32_t downstream_target_id; + uint32_t cache_hit_latency_cycles; + uint32_t pipeline_latency_cycles; - // Outbound channel queues. - WorkQueue outbound_req; - WorkQueue outbound_dat; - WorkQueue outbound_crsp; + // Constructed at elaborate: + std::unique_ptr outbound_req; + std::unique_ptr outbound_dat; + std::unique_ptr outbound_crsp; + std::unique_ptr tq; Cache cache; - TransactionQueue tq; - // Service coroutines. auto service_req_queue() -> proc_t; auto service_dat_queue() -> proc_t; @@ -72,10 +85,6 @@ class HomeAgent : public Module { // Generic helpers auto should_use_dmt(const Payload& req) -> bool; - - // Defaults — future config will override. - uint32_t cache_hit_latency_cycles = 3; - uint32_t pipeline_latency_cycles = 5; }; } // namespace csim \ No newline at end of file diff --git a/include/models/initiator.h b/include/models/initiator.h index ee59e8e..168dfef 100644 --- a/include/models/initiator.h +++ b/include/models/initiator.h @@ -11,16 +11,15 @@ #include "csim/core/port.h" #include "csim/core/sim_types.h" #include "protocols/chi.h" +#include "csim/config/knob_system.h" namespace csim { class Initiator : public Module { public: - Port port; - - Initiator(sim_t& sim, System& sys, uint32_t id, std::string name, uint32_t home_id, - time_ps clock_period_ps); + Initiator(sim_t& sim, System& sys, uint32_t id, std::string name); + auto elaborate() -> void override; auto start() -> void override; private: @@ -32,8 +31,15 @@ class Initiator : public Module { auto handle_crsp(payload_ptr response) -> void; auto get_next_txn_id() -> uint32_t { return next_txn_id++; } + KnobList& knob_list; + Knob& clock_period_ps_knob = + knob_list.add_knob("clock_period_ps", "Clock period in picoseconds", 1000); + Knob& home_id_knob = + knob_list.add_knob("home_id", "Home agent ID for transactions", 1); + time_ps clock_period_ps; uint32_t home_id; + uint32_t next_txn_id = 0; DelayChannel outbound_req; diff --git a/include/models/interconnect.h b/include/models/interconnect.h index 71cf3d1..97e2ce2 100644 --- a/include/models/interconnect.h +++ b/include/models/interconnect.h @@ -2,11 +2,9 @@ #include #include -#include #include "csim/core/module.h" #include "csim/core/payload.h" -#include "csim/core/port.h" #include "csim/core/sim_types.h" namespace csim { @@ -15,18 +13,11 @@ class Interconnect : public Module { public: Interconnect(sim_t& sim, System& sys, uint32_t id, std::string name); + auto elaborate() -> void override; auto start() -> void override; - // Wire up an agent. Agent's port becomes bound to one of our internal - // ports; we record the mapping so we can route flits with tgt_id - // matching the agent's id. - auto attach(Module& m, Port& agent_port) -> void; - private: auto handle_incoming(payload_ptr payload) -> void; - - // One per attached agent. Owned by us; bound to the agent's port. - std::unordered_map> ports; }; } // namespace csim \ No newline at end of file diff --git a/include/models/target.h b/include/models/target.h index edf48a9..3a95f90 100644 --- a/include/models/target.h +++ b/include/models/target.h @@ -1,11 +1,12 @@ #pragma once #include +#include #include +#include "csim/config/knob_system.h" #include "csim/core/module.h" #include "csim/core/payload.h" -#include "csim/core/port.h" #include "csim/core/sim_types.h" #include "csim/utilities/work_queue.h" #include "protocols/chi.h" @@ -14,18 +15,24 @@ namespace csim { class Target : public Module { public: - Port port; - - Target(sim_t& sim, System& sys, uint32_t id, std::string name, time_ps clock_period_ps); + Target(sim_t& sim, System& sys, uint32_t id, std::string name); + auto elaborate() -> void override; auto start() -> void override; private: + KnobList& knob_list; + Knob& clock_period_ps_knob = + knob_list.add_knob("clock_period_ps", "Clock period in picoseconds", 1000); + Knob& data_latency_cycles_knob = + knob_list.add_knob("data_latency_cycles", "Data response latency in cycles", 50); + + // Captured at elaborate: time_ps clock_period_ps; - uint32_t data_latency_cycles = 50; - uint32_t response_latency_cycles = 1; + uint32_t data_latency_cycles; - WorkQueue outbound_data; + // Constructed at elaborate: + std::unique_ptr outbound_data; auto handle_request(payload_ptr payload) -> void; auto service_data_queue() -> proc_t; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f74da85..626c0d3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -9,6 +9,7 @@ add_library(csim_infra STATIC csim/tracing/tracer.cpp csim/config/config.cpp csim/config/knob_list.cpp + csim/config/topology_loader.cpp ) target_include_directories(csim_infra PUBLIC ${CMAKE_SOURCE_DIR}/include) target_link_libraries(csim_infra PUBLIC fschuetz04::simcpp20 magic_enum::magic_enum nlohmann_json::nlohmann_json) diff --git a/src/csim/config/config.cpp b/src/csim/config/config.cpp index 993eb41..c4ba692 100644 --- a/src/csim/config/config.cpp +++ b/src/csim/config/config.cpp @@ -16,6 +16,7 @@ std::unordered_map> module_knob_lists; std::unordered_map all_knobs; std::vector module_order; bool current_strict = true; +std::string topology_file; auto set_knob_value(const std::string& key, const std::string& value) -> void @@ -65,6 +66,19 @@ parse_command_line(int argc, char* argv[], bool strict) -> void current_strict = strict; + // Find topology file + for (int i = 1; i < argc; ++i) { + std::string arg = argv[i]; + if (arg == "--topology") { + if (i + 1 < argc) { + topology_file = argv[++i]; + } + else { + std::cerr << "Error: --topology requires a filename\n"; + } + } + } + // Load JSON file first (lowest priority) for (int i = 1; i < argc; ++i) { std::string arg = argv[i]; @@ -109,7 +123,7 @@ parse_command_line(int argc, char* argv[], bool strict) -> void continue; } - if (arg == "--json" || arg == "--config") { + if (arg == "--json" || arg == "--config" || arg == "--topology") { if (i + 1 < argc) ++i; continue; @@ -392,6 +406,12 @@ get_knob(const std::string& full_name) -> KnobBase* return (it != all_knobs.end()) ? it->second : nullptr; } +auto +get_topology_file() -> std::string +{ + return topology_file; +} + auto reset_all() -> void { @@ -406,6 +426,7 @@ clear() -> void all_knobs.clear(); module_knob_lists.clear(); module_order.clear(); + topology_file.clear(); } auto diff --git a/src/csim/config/topology_loader.cpp b/src/csim/config/topology_loader.cpp new file mode 100644 index 0000000..4b3d496 --- /dev/null +++ b/src/csim/config/topology_loader.cpp @@ -0,0 +1,180 @@ +#include "csim/config/topology_loader.h" +#include "models/home_agent.h" +#include "models/initiator.h" +#include "models/target.h" +#include "models/interconnect.h" + +#include +#include +#include + +namespace csim { + +TopologyLoader::TopologyLoader(sim_t& sim, System& sys) : sim(sim), sys(sys) {} + +auto +TopologyLoader::load(const std::string& filename) -> void +{ + std::ifstream file(filename); + if (!file.is_open()) { + throw std::runtime_error("Failed to open topology file: " + filename); + } + + nlohmann::json topology; + try { + file >> topology; + } + catch (const nlohmann::json::parse_error& e) { + throw std::runtime_error("Failed to parse topology JSON: " + std::string(e.what())); + } + + // Phase 1: construct modules. + if (topology.contains("modules")) { + for (const auto& spec : topology["modules"]) { + construct_module(spec); + } + } + + // Phase 2: wire neighbors. + if (topology.contains("modules")) { + std::set> seen; + for (const auto& spec : topology["modules"]) { + wire_neighbors(spec, seen); + } + } +} + +auto +TopologyLoader::get_module(const std::string& name) const -> Module* +{ + auto it = modules.find(name); + return (it != modules.end()) ? it->second.get() : nullptr; +} + +auto +TopologyLoader::construct_module(const nlohmann::json& spec) -> void +{ + const std::string name = spec["name"]; + const std::string type = spec["type"]; + + if (modules.find(name) != modules.end()) { + throw std::runtime_error("Duplicate module name: " + name); + } + + std::unique_ptr module; + if (type == "initiator") { + module = construct_initiator(spec); + } + else if (type == "home_agent") { + module = construct_home_agent(spec); + } + else if (type == "target") { + module = construct_target(spec); + } + else if (type == "interconnect") { + module = construct_interconnect(spec); + } + else { + throw std::runtime_error("Unknown module type: " + type); + } + + modules[name] = std::move(module); + + if (spec.contains("config")) { + apply_module_config(name, spec["config"]); + } +} + +auto +TopologyLoader::construct_initiator(const nlohmann::json& spec) -> std::unique_ptr +{ + const std::string name = spec["name"]; + const uint32_t id = spec["id"]; + + return std::make_unique(sim, sys, id, name); +} + +auto +TopologyLoader::construct_home_agent(const nlohmann::json& spec) -> std::unique_ptr +{ + const std::string name = spec["name"]; + const uint32_t id = spec["id"]; + + return std::make_unique(sim, sys, id, name); +} +auto +TopologyLoader::construct_target(const nlohmann::json& spec) -> std::unique_ptr +{ + const std::string name = spec["name"]; + const uint32_t id = spec["id"]; + + return std::make_unique(sim, sys, id, name); +} +auto +TopologyLoader::construct_interconnect(const nlohmann::json& spec) -> std::unique_ptr +{ + const std::string name = spec["name"]; + const uint32_t id = spec["id"]; + + return std::make_unique(sim, sys, id, name); +} +auto +TopologyLoader::apply_module_config(const std::string& name, const nlohmann::json& config) -> void +{ + for (const auto& [key, value] : config.items()) { + const std::string full_key = name + "." + key; + auto* knob = csim::config::get_knob(full_key); + if (knob == nullptr) { + throw std::runtime_error("Unknown knob '" + full_key + "' in config block"); + } + + std::string val_str; + if (value.is_string()) { + val_str = value.get(); + } + else { + val_str = value.dump(); + } + + knob->set_from_string(val_str); + } +} + +auto +TopologyLoader::wire_neighbors(const nlohmann::json& spec, + std::set>& seen) -> void +{ + if (!spec.contains("neighbors")) { + return; + } + + const std::string self_name = spec["name"]; + + for (const auto& neighbor_item : spec["neighbors"]) { + const std::string neighbor_name = neighbor_item; + + auto neighbor_it = modules.find(neighbor_name); + if (neighbor_it == modules.end()) { + throw std::runtime_error("Unknown neighbor '" + neighbor_name + "' for module '" + + self_name + "'"); + } + + // Canonical edge key — dedupes when the neighbors list is symmetric. + auto key = + std::make_pair(std::min(self_name, neighbor_name), std::max(self_name, neighbor_name)); + if (seen.contains(key)) { + continue; + } + seen.insert(key); + + Module* self = modules.at(self_name).get(); + Module* neighbor = neighbor_it->second.get(); + + Port& self_port = self->add_port(neighbor->id()); + Port& neighbor_port = neighbor->add_port(self->id()); + + bind(self_port, neighbor_port); + } +} + +} // namespace csim diff --git a/src/csim/core/system.cpp b/src/csim/core/system.cpp index 951bd39..1264ad9 100644 --- a/src/csim/core/system.cpp +++ b/src/csim/core/system.cpp @@ -26,4 +26,24 @@ System::start_all() -> void m->start(); } +auto +Module::add_port(uint32_t neighbor_id) -> Port& +{ + auto [it, inserted] = port_map.emplace(neighbor_id, std::make_unique()); + assert(inserted && "duplicate port for neighbor id"); + return *it->second; +} + +auto +Module::get_port(uint32_t neighbor_id) -> Port& +{ + return *port_map.at(neighbor_id); +} +auto +Module::single_port() const -> Port& +{ + assert(port_map.size() == 1 && "single_port() requires exactly one port"); + return *port_map.begin()->second; +} + } // namespace csim \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 0b14a25..731cded 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,43 +1,43 @@ #include "csim/core/port.h" #include -#include -#include #include "csim/core/sim_types.h" #include "csim/core/system.h" - -#include "models/initiator.h" -#include "models/target.h" -#include "models/interconnect.h" -#include "models/home_agent.h" +#include "csim/config/topology_loader.h" +#include "csim/config/knob_system.h" using namespace csim; auto -main() -> int +main(int argc, char* argv[]) -> int { - sim_t sim; - csim::System sys{sim}; + sim_t sim; + System sys{sim}; - tracing::Tracer::instance().open("trace.jsonl", "trace.txt", sim); - tracing::Tracer::instance().enable(); + // Phase 1: get the topology file from CLI (and any non-strict knob parsing). + config::parse_command_line(argc, argv, /*strict=*/false); - constexpr time_ps clock_period_ps = 1000; + // Phase 2: load topology, which constructs modules and applies their config. + TopologyLoader loader(sim, sys); + const std::string topo_file = config::get_topology_file(); + if (topo_file.empty()) { + std::cerr << "Error: --topology is required\n"; + return 1; + } + loader.load(topo_file); - Interconnect ic(sim, sys, /*id=*/2, "interconnect"); - Initiator i(sim, sys, /*id=*/0, "initiator", /*target_id=*/3, clock_period_ps); - HomeAgent ha(sim, sys, /*id=*/3, "ha", /*downstream_target_id=*/1, clock_period_ps); - Target t(sim, sys, /*id=*/1, "target", clock_period_ps); + // Phase 3: now all knobs are registered. Re-parse strictly, plus help. + csim::config::check_for_help(argc, argv); + csim::config::parse_command_line(argc, argv, /*strict=*/true); - sys.elaborate_all(); + auto& tracer = tracing::Tracer::instance(); + tracer.open("trace.jsonl", "trace.txt", sim); + tracer.enable(); - ic.attach(i, i.port); - ic.attach(ha, ha.port); - ic.attach(t, t.port); + sys.elaborate_all(); sys.start_all(); sim.run_until(10'000_ns); - - tracing::Tracer::instance().close(); + tracer.close(); return 0; } diff --git a/src/models/home_agent.cpp b/src/models/home_agent.cpp index 7e365f5..89688a0 100644 --- a/src/models/home_agent.cpp +++ b/src/models/home_agent.cpp @@ -6,19 +6,31 @@ #include "protocols/chi.h" +#include + namespace csim { -HomeAgent::HomeAgent(sim_t& sim, System& sys, uint32_t id, std::string name, - uint32_t downstream_target_id, time_ps clock_period_ps) - : Module(sim, sys, id, std::move(name)), - downstream_target_id(downstream_target_id), - clock_period_ps(clock_period_ps), - outbound_req(sim, clock_period_ps), - outbound_dat(sim, clock_period_ps), - outbound_crsp(sim, clock_period_ps), - tq(sim, 8) +HomeAgent::HomeAgent(sim_t& sim, System& sys, uint32_t id, std::string name) + : Module(sim, sys, id, std::move(name)), knob_list(config::get_or_create(this->name)) +{ +} + +auto +HomeAgent::elaborate() -> void { - port.on_receive(this, &HomeAgent::handle_incoming); + clock_period_ps = static_cast(clock_period_ps_knob.get()); + downstream_target_id = static_cast(downstream_target_id_knob.get()); + cache_hit_latency_cycles = static_cast(cache_hit_latency_cycles_knob.get()); + pipeline_latency_cycles = static_cast(pipeline_latency_cycles_knob.get()); + + outbound_req = std::make_unique(sim, clock_period_ps); + outbound_dat = std::make_unique(sim, clock_period_ps); + outbound_crsp = std::make_unique(sim, clock_period_ps); + tq = std::make_unique(sim, tq_capacity_knob.get()); + + for (auto& port_ptr : port_map | std::views::values) { + port_ptr->on_receive(this, &HomeAgent::handle_incoming); + } } auto @@ -63,7 +75,7 @@ HomeAgent::handle_read_transaction(payload_ptr req) -> proc_t const auto& chi_in = req->require_as(); const addr_t address = chi_in.address; - TQEntry tq_entry{tq, req}; + TQEntry tq_entry{*tq, req}; tracer.instant(name, "tq waiting for grant", req->txn_uid, req->flit_id, address); co_await tq_entry.wait_for_grant(); tracer.instant(name, "tq_granted - entering pipeline", req->txn_uid, req->flit_id, address); @@ -112,7 +124,7 @@ HomeAgent::read_miss_non_dmt(payload_ptr req) -> proc_t // Forward REQ to target. auto forward_req = create_req(*req, chi::ReqOpcode::ReadNoSnp, downstream_target_id); const time_ps fwd_offset = static_cast(pipeline_latency_cycles) * clock_period_ps; - outbound_req.push(fwd_offset, std::move(forward_req)); + outbound_req->push(fwd_offset, std::move(forward_req)); // Wait for RDAT from target. inbox.expect_data_chunks(1); @@ -131,7 +143,7 @@ HomeAgent::read_miss_non_dmt(payload_ptr req) -> proc_t // Build and queue CompData to requester. auto data_return = create_dat(*req, chi::DatOpcode::CompData, chi_in.req.src_id); const time_ps dat_offset = static_cast(pipeline_latency_cycles) * clock_period_ps; - outbound_dat.push(dat_offset, std::move(data_return)); + outbound_dat->push(dat_offset, std::move(data_return)); } auto @@ -144,7 +156,7 @@ HomeAgent::read_miss_dmt(payload_ptr req) -> proc_t // For now, this is the same as non-DMT forward. auto forward_req = create_req(*req, chi::ReqOpcode::ReadNoSnp, downstream_target_id); const time_ps fwd_offset = static_cast(pipeline_latency_cycles) * clock_period_ps; - outbound_req.push(fwd_offset, std::move(forward_req)); + outbound_req->push(fwd_offset, std::move(forward_req)); // Wait for Comp from target (no data — data went directly to requester). // TODO: distinguish Comp vs CompData. For now, target sends CompData; assume it. @@ -168,7 +180,7 @@ HomeAgent::read_hit(payload_ptr req) -> proc_t auto data_return = create_dat(*req, chi::DatOpcode::CompData, chi_in.req.src_id); const time_ps dat_offset = static_cast(cache_hit_latency_cycles) * clock_period_ps; - outbound_dat.push(dat_offset, std::move(data_return)); + outbound_dat->push(dat_offset, std::move(data_return)); co_return; } @@ -179,7 +191,7 @@ HomeAgent::handle_write_transaction(payload_ptr req) -> proc_t const auto& chi_in = req->require_as(); const auto address = chi_in.address; - TQEntry tq_entry{tq, req}; + TQEntry tq_entry{*tq, req}; tracer.instant(name, "tq_acquired", req->txn_uid, req->flit_id, address); co_await tq_entry.wait_for_grant(); tracer.instant(name, "tq_granted", req->txn_uid, req->flit_id, address); @@ -195,7 +207,7 @@ HomeAgent::handle_write_transaction(payload_ptr req) -> proc_t auto comp_dbid = create_rsp(*req, chi::RspOpcode::CompDBIDResp, chi_in.req.src_id, dbid); const time_ps offset = static_cast(pipeline_latency_cycles) * clock_period_ps; - outbound_crsp.push(offset, std::move(comp_dbid)); + outbound_crsp->push(offset, std::move(comp_dbid)); inbox.expect_data_chunks(1); co_await inbox.all_data_chunks_received(); @@ -218,15 +230,15 @@ auto HomeAgent::service_req_queue() -> proc_t { while (true) { - co_await outbound_req.wait(); - auto payload = outbound_req.pop(); + co_await outbound_req->wait(); + auto payload = outbound_req->pop(); const auto& chi = payload->require_as(); tracer.instant(name, "sending_req", payload->txn_uid, payload->flit_id, chi.address, {{"opcode", std::string(name_of(chi.req.opcode))}, {"tgt_id", std::to_string(chi.req.tgt_id)}}); - port.send(std::move(payload)); + single_port().send(std::move(payload)); } } @@ -234,23 +246,23 @@ auto HomeAgent::service_dat_queue() -> proc_t { while (true) { - co_await outbound_dat.wait(); - auto payload = outbound_dat.pop(); + co_await outbound_dat->wait(); + auto payload = outbound_dat->pop(); const auto& chi = payload->require_as(); tracer.instant(name, "sending_rdat", payload->txn_uid, payload->flit_id, chi.address, {{"opcode", std::string(name_of(chi.dat.opcode))}, {"tgt_id", std::to_string(chi.dat.tgt_id)}}); - port.send(std::move(payload)); + single_port().send(std::move(payload)); } } auto HomeAgent::service_crsp_queue() -> proc_t { while (true) { - co_await outbound_crsp.wait(); - auto payload = outbound_crsp.pop(); + co_await outbound_crsp->wait(); + auto payload = outbound_crsp->pop(); const auto& chi = payload->require_as(); tracer.instant(name, "sending_crsp", payload->txn_uid, payload->flit_id, chi.address, @@ -258,7 +270,7 @@ HomeAgent::service_crsp_queue() -> proc_t {"tgt_id", std::to_string(chi.rsp.tgt_id)}, {"dbid", std::to_string(chi.rsp.dbid)}}); - port.send(std::move(payload)); + single_port().send(std::move(payload)); } } diff --git a/src/models/initiator.cpp b/src/models/initiator.cpp index 3e8f656..e4a5a96 100644 --- a/src/models/initiator.cpp +++ b/src/models/initiator.cpp @@ -3,18 +3,17 @@ #include #include #include +#include +#include namespace csim { -Initiator::Initiator(sim_t& sim, System& sys, uint32_t id, std::string name, uint32_t home_id, - time_ps clock_period_ps) +Initiator::Initiator(sim_t& sim, System& sys, uint32_t id, std::string name) : Module(sim, sys, id, std::move(name)), - clock_period_ps(clock_period_ps), - home_id(home_id), + knob_list(csim::config::get_or_create(this->name)), outbound_req(sim), outbound_wdat(sim), outbound_srsp(sim) { - port.on_receive(this, &Initiator::handle_incoming); } auto @@ -49,6 +48,17 @@ Initiator::workload() -> proc_t co_await sim.timeout(clock_period_ps * 100); issue_req(0x2000ull, chi::ReqOpcode::ReadShared); } +auto +Initiator::elaborate() -> void +{ + clock_period_ps = static_cast(clock_period_ps_knob.get()); + home_id = static_cast(home_id_knob.get()); + + for (auto& port_ptr : port_map | std::views::values) { + port_ptr->on_receive(this, &Initiator::handle_incoming); + } +} + auto Initiator::start() -> void { @@ -59,16 +69,27 @@ Initiator::start() -> void auto Initiator::tick_clock() -> proc_t { + std::cerr << "tick_clock starting, sim.now()=" << sim.now() << "\n"; co_await sim.timeout(0); + std::cerr << "after timeout(0)\n"; while (true) { + std::cerr << "loop iter, sim.now()=" << sim.now() + << ", port_map.size()=" << port_map.size() << "\n"; if (outbound_req.has_ready_payload()) { auto payload = outbound_req.pop(); payload->start_time = sim.now(); const auto& chi = payload->require_as(); tracer.instant(name, "sending_req", payload->txn_uid, payload->flit_id, chi.address, {{"opcode", std::string(name_of(chi.req.opcode))}}); - port.send(std::move(payload)); + std::cerr << "req ready, port_map.size()=" << port_map.size() << "\n"; + if (port_map.size() != 1) { + std::cerr << "PROBLEM: expected 1 port, have " << port_map.size() << "\n"; + } + Port& p = single_port(); + std::cerr << "got single port\n"; + p.send(std::move(payload)); + // single_port().send(std::move(payload)); } if (outbound_wdat.has_ready_payload()) { auto payload = outbound_wdat.pop(); @@ -77,7 +98,7 @@ Initiator::tick_clock() -> proc_t {{"opcode", std::string(name_of(chi.dat.opcode))}, {"dbid", std::to_string(chi.dat.dbid)}}); outstanding_txns.erase(payload->txn_uid); - port.send(std::move(payload)); + single_port().send(std::move(payload)); } if (outbound_srsp.has_ready_payload()) { auto payload = outbound_srsp.pop(); @@ -85,7 +106,7 @@ Initiator::tick_clock() -> proc_t tracer.instant(name, "sending_srsp", payload->txn_uid, payload->flit_id, chi.address, {{"opcode", std::string(name_of(chi.rsp.opcode))}}); outstanding_txns.erase(payload->txn_uid); - port.send(std::move(payload)); + single_port().send(std::move(payload)); } co_await sim.timeout(clock_period_ps); } diff --git a/src/models/interconnect.cpp b/src/models/interconnect.cpp index 497b728..fd8cff1 100644 --- a/src/models/interconnect.cpp +++ b/src/models/interconnect.cpp @@ -1,9 +1,7 @@ #include "models/interconnect.h" #include -#include -#include -#include +#include #include "protocols/chi.h" @@ -15,20 +13,17 @@ Interconnect::Interconnect(sim_t& sim, System& sys, uint32_t id, std::string nam } auto -Interconnect::start() -> void +Interconnect::elaborate() -> void { - // No coroutines yet — interconnect is purely synchronous. + for (auto& port_ptr : port_map | std::views::values) { + port_ptr->on_receive(this, &Interconnect::handle_incoming); + } } auto -Interconnect::attach(Module& m, Port& agent_port) -> void +Interconnect::start() -> void { - assert(ports.find(m.id()) == ports.end() && "duplicate node_id on interconnect"); - - auto p = std::make_unique(); - p->on_receive(this, &Interconnect::handle_incoming); - bind(*p, agent_port); - ports[m.id()] = std::move(p); + // No coroutines — interconnect is purely synchronous. } auto @@ -56,10 +51,7 @@ Interconnect::handle_incoming(payload_ptr payload) -> void assert(false && "unhandled channel in interconnect routing"); } - auto it = ports.find(tgt_id); - assert(it != ports.end() && "tgt_id not attached to interconnect"); - - it->second->send(std::move(payload)); + get_port(tgt_id).send(std::move(payload)); } } // namespace csim \ No newline at end of file diff --git a/src/models/target.cpp b/src/models/target.cpp index 01a4008..0a7824d 100644 --- a/src/models/target.cpp +++ b/src/models/target.cpp @@ -1,16 +1,27 @@ #include "models/target.h" #include +#include #include namespace csim { -Target::Target(sim_t& sim, System& sys, uint32_t id, std::string name, time_ps clock_period_ps) - : Module(sim, sys, id, std::move(name)), - clock_period_ps(clock_period_ps), - outbound_data(sim, clock_period_ps) +Target::Target(sim_t& sim, System& sys, uint32_t id, std::string name) + : Module(sim, sys, id, std::move(name)), knob_list(config::get_or_create(this->name)) { - port.on_receive(this, &Target::handle_request); +} + +auto +Target::elaborate() -> void +{ + clock_period_ps = static_cast(clock_period_ps_knob.get()); + data_latency_cycles = static_cast(data_latency_cycles_knob.get()); + + outbound_data = std::make_unique(sim, clock_period_ps); + + for (auto& port_ptr : port_map | std::views::values) { + port_ptr->on_receive(this, &Target::handle_request); + } } auto @@ -32,22 +43,22 @@ Target::handle_request(payload_ptr payload) -> void const time_ps offset_ps = static_cast(data_latency_cycles) * clock_period_ps; - outbound_data.push(offset_ps, std::move(response)); + outbound_data->push(offset_ps, std::move(response)); } auto Target::service_data_queue() -> proc_t { while (true) { - co_await outbound_data.wait(); - auto payload = outbound_data.pop(); + co_await outbound_data->wait(); + auto payload = outbound_data->pop(); const auto& chi_pl = payload->require_as(); tracer.instant(name, "sending_rdat", payload->txn_uid, payload->flit_id, chi_pl.address, {{"opcode", std::string(name_of(chi_pl.dat.opcode))}, {"txn_id", std::to_string(chi_pl.txn_id)}}); - port.send(std::move(payload)); + single_port().send(std::move(payload)); } } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 91a84df..5c3f5eb 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -5,6 +5,7 @@ set(tests transaction_inbox_test.cpp transaction_queue_test.cpp config_test.cpp + topology_loader_test.cpp ) foreach(test ${tests}) diff --git a/test/topology_loader_test.cpp b/test/topology_loader_test.cpp new file mode 100644 index 0000000..c4de8ed --- /dev/null +++ b/test/topology_loader_test.cpp @@ -0,0 +1,167 @@ +#include "csim/config/topology_loader.h" +#include "csim/config/config.h" +#include "csim/core/system.h" + +#include + +#include +#include +#include + +namespace csim::test { + +class TopologyLoaderTest : public ::testing::Test { +public: + sim_t sim; + System sys{sim}; + std::filesystem::path test_file = "test_topology.json"; + + void SetUp() override + { + csim::config::clear(); + } + + void TearDown() override + { + csim::config::clear(); + std::filesystem::remove(test_file); + } + + auto write_json(const std::string& content) -> void + { + std::ofstream f(test_file); + f << content; + } +}; + +// ===== Smoke tests ===== + +TEST_F(TopologyLoaderTest, EmptyTopologyLoadsSuccessfully) +{ + write_json(R"({"modules": [], "connections": []})"); + + TopologyLoader loader(sim, sys); + EXPECT_NO_THROW(loader.load(test_file.string())); +} + +TEST_F(TopologyLoaderTest, MalformedJsonThrows) +{ + write_json("not valid json"); + + TopologyLoader loader(sim, sys); + EXPECT_THROW(loader.load(test_file.string()), std::runtime_error); +} + +TEST_F(TopologyLoaderTest, MissingFileThrows) +{ + TopologyLoader loader(sim, sys); + EXPECT_THROW(loader.load("does_not_exist.json"), std::runtime_error); +} + +// ===== Single-module construction ===== + +TEST_F(TopologyLoaderTest, ConstructsSingleInitiator) +{ + write_json(R"({ + "modules": [ + {"name": "init0", "type": "initiator", "id": 0, "config": {"home_id": 1}} + ], + "connections": [] + })"); + + TopologyLoader loader(sim, sys); + loader.load(test_file.string()); + + EXPECT_NE(loader.get_module("init0"), nullptr); +} + +TEST_F(TopologyLoaderTest, UnknownTypeThrows) +{ + write_json(R"({ + "modules": [ + {"name": "x", "type": "unknown_type", "id": 0} + ], + "connections": [] + })"); + + TopologyLoader loader(sim, sys); + EXPECT_THROW(loader.load(test_file.string()), std::runtime_error); +} + +TEST_F(TopologyLoaderTest, DuplicateNameThrows) +{ + write_json(R"({ + "modules": [ + {"name": "init0", "type": "initiator", "id": 0, "home_id": 1}, + {"name": "init0", "type": "initiator", "id": 1, "home_id": 1} + ], + "connections": [] + })"); + + TopologyLoader loader(sim, sys); + EXPECT_THROW(loader.load(test_file.string()), std::runtime_error); +} + +// ===== Knob value application ===== + +TEST_F(TopologyLoaderTest, AppliesPerModuleConfigToKnobs) +{ + write_json(R"({ + "modules": [ + { + "name": "ha0", + "type": "home_agent", + "id": 1, + "downstream_target_id": 2, + "config": { + "tq_capacity": 16, + "cache_hit_latency_cycles": 7 + } + } + ], + "connections": [] + })"); + + TopologyLoader loader(sim, sys); + loader.load(test_file.string()); + + auto* tq_knob = csim::config::get_knob("ha0.tq_capacity"); + ASSERT_NE(tq_knob, nullptr); + EXPECT_EQ(tq_knob->to_string(), "16"); + + auto* lat_knob = csim::config::get_knob("ha0.cache_hit_latency_cycles"); + ASSERT_NE(lat_knob, nullptr); + EXPECT_EQ(lat_knob->to_string(), "7"); +} + +// ===== Connections ===== + +TEST_F(TopologyLoaderTest, ConnectsTwoModules) +{ + write_json(R"({ + "modules": [ + {"name": "init0", "type": "initiator", "id": 0, "neighbors": ["ha0"], + "config": {"home_id": 1}}, + {"name": "ha0", "type": "home_agent", "id": 1, "neighbors": ["init0"], + "config": {"downstream_target_id": 2}} + ] + })"); + + TopologyLoader loader(sim, sys); + EXPECT_NO_THROW(loader.load(test_file.string())); +} + +TEST_F(TopologyLoaderTest, ConnectionWithUnknownNameThrows) +{ + write_json(R"({ + "modules": [ + {"name": "init0", "type": "initiator", "id": 0, "neighbors": ["ghost"], + "config": {"home_id": 1}} + ] + })"); + + TopologyLoader loader(sim, sys); + EXPECT_THROW(loader.load(test_file.string()), std::runtime_error); +} + +} // namespace csim::test \ No newline at end of file From 6d4234a12bd847719e7b4775d68069fb47f6942d Mon Sep 17 00:00:00 2001 From: Zachary Ankenman Date: Sat, 23 May 2026 16:09:24 -0700 Subject: [PATCH 2/4] Remove excessive debug logging from Initiator::tick_clock and clean up unused code. --- src/models/initiator.cpp | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/models/initiator.cpp b/src/models/initiator.cpp index e4a5a96..36602ef 100644 --- a/src/models/initiator.cpp +++ b/src/models/initiator.cpp @@ -69,27 +69,16 @@ Initiator::start() -> void auto Initiator::tick_clock() -> proc_t { - std::cerr << "tick_clock starting, sim.now()=" << sim.now() << "\n"; co_await sim.timeout(0); - std::cerr << "after timeout(0)\n"; while (true) { - std::cerr << "loop iter, sim.now()=" << sim.now() - << ", port_map.size()=" << port_map.size() << "\n"; if (outbound_req.has_ready_payload()) { auto payload = outbound_req.pop(); payload->start_time = sim.now(); const auto& chi = payload->require_as(); tracer.instant(name, "sending_req", payload->txn_uid, payload->flit_id, chi.address, {{"opcode", std::string(name_of(chi.req.opcode))}}); - std::cerr << "req ready, port_map.size()=" << port_map.size() << "\n"; - if (port_map.size() != 1) { - std::cerr << "PROBLEM: expected 1 port, have " << port_map.size() << "\n"; - } - Port& p = single_port(); - std::cerr << "got single port\n"; - p.send(std::move(payload)); - // single_port().send(std::move(payload)); + single_port().send(std::move(payload)); } if (outbound_wdat.has_ready_payload()) { auto payload = outbound_wdat.pop(); @@ -135,7 +124,7 @@ Initiator::handle_rdat(payload_ptr response) -> void auto it = outstanding_txns.find(response->txn_uid); assert(it != outstanding_txns.end() && "received response for unknown txn_uid"); - const auto& original_request = it->second.request; // .request, was bare payload_ptr + const auto& original_request = it->second.request; const auto latency = sim.now() - original_request->start_time; tracer.instant( From 85be89bd8806ac344ff841aa33cbd80114d57864 Mon Sep 17 00:00:00 2001 From: Zachary Ankenman Date: Sat, 23 May 2026 16:20:07 -0700 Subject: [PATCH 3/4] Fix formatting and move topology to models --- include/csim/core/port.h | 10 ++++------ include/{csim/config => models}/topology_loader.h | 0 src/CMakeLists.txt | 2 +- src/main.cpp | 2 +- src/models/initiator.cpp | 2 +- src/{csim/config => models}/topology_loader.cpp | 2 +- test/topology_loader_test.cpp | 2 +- 7 files changed, 9 insertions(+), 11 deletions(-) rename include/{csim/config => models}/topology_loader.h (100%) rename src/{csim/config => models}/topology_loader.cpp (99%) diff --git a/include/csim/core/port.h b/include/csim/core/port.h index 452802e..33de418 100644 --- a/include/csim/core/port.h +++ b/include/csim/core/port.h @@ -10,15 +10,12 @@ class Port { public: using callback_t = std::function; - template - auto on_receive(Self* self, void (Self::*method)(payload_ptr)) -> void + template auto on_receive(Self* self, void (Self::*method)(payload_ptr)) -> void { rx_ = [self, method](payload_ptr p) -> auto { (self->*method)(std::move(p)); }; } - auto send(payload_ptr p) -> void { - peer_->rx_(std::move(p)); - } + auto send(payload_ptr p) -> void { peer_->rx_(std::move(p)); } auto set_peer(Port* peer) -> void { peer_ = peer; } @@ -29,7 +26,8 @@ class Port { friend auto bind(Port& a, Port& b) -> void; }; -inline auto bind(Port& a, Port& b) -> void +inline auto +bind(Port& a, Port& b) -> void { a.peer_ = &b; b.peer_ = &a; diff --git a/include/csim/config/topology_loader.h b/include/models/topology_loader.h similarity index 100% rename from include/csim/config/topology_loader.h rename to include/models/topology_loader.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 626c0d3..977c7f7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -9,7 +9,6 @@ add_library(csim_infra STATIC csim/tracing/tracer.cpp csim/config/config.cpp csim/config/knob_list.cpp - csim/config/topology_loader.cpp ) target_include_directories(csim_infra PUBLIC ${CMAKE_SOURCE_DIR}/include) target_link_libraries(csim_infra PUBLIC fschuetz04::simcpp20 magic_enum::magic_enum nlohmann_json::nlohmann_json) @@ -22,6 +21,7 @@ add_library(csim_models STATIC models/home_agent.cpp models/transaction_inbox.cpp models/transaction_queue.cpp + models/topology_loader.cpp ) target_link_libraries(csim_models PUBLIC csim_infra) target_include_directories(csim_models PUBLIC ../include) diff --git a/src/main.cpp b/src/main.cpp index 731cded..f6cee57 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,7 +2,7 @@ #include #include "csim/core/sim_types.h" #include "csim/core/system.h" -#include "csim/config/topology_loader.h" +#include "models/topology_loader.h" #include "csim/config/knob_system.h" using namespace csim; diff --git a/src/models/initiator.cpp b/src/models/initiator.cpp index 36602ef..6fee623 100644 --- a/src/models/initiator.cpp +++ b/src/models/initiator.cpp @@ -124,7 +124,7 @@ Initiator::handle_rdat(payload_ptr response) -> void auto it = outstanding_txns.find(response->txn_uid); assert(it != outstanding_txns.end() && "received response for unknown txn_uid"); - const auto& original_request = it->second.request; + const auto& original_request = it->second.request; const auto latency = sim.now() - original_request->start_time; tracer.instant( diff --git a/src/csim/config/topology_loader.cpp b/src/models/topology_loader.cpp similarity index 99% rename from src/csim/config/topology_loader.cpp rename to src/models/topology_loader.cpp index 4b3d496..ffc418d 100644 --- a/src/csim/config/topology_loader.cpp +++ b/src/models/topology_loader.cpp @@ -1,4 +1,4 @@ -#include "csim/config/topology_loader.h" +#include "models/topology_loader.h" #include "models/home_agent.h" #include "models/initiator.h" #include "models/target.h" diff --git a/test/topology_loader_test.cpp b/test/topology_loader_test.cpp index c4de8ed..d48c37e 100644 --- a/test/topology_loader_test.cpp +++ b/test/topology_loader_test.cpp @@ -1,4 +1,4 @@ -#include "csim/config/topology_loader.h" +#include "models/topology_loader.h" #include "csim/config/config.h" #include "csim/core/system.h" From 10a009ffdcbe67cdf120d73c0642c29eafd2378b Mon Sep 17 00:00:00 2001 From: Zachary Ankenman Date: Sat, 23 May 2026 16:21:31 -0700 Subject: [PATCH 4/4] Fix formatting --- test/topology_loader_test.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/test/topology_loader_test.cpp b/test/topology_loader_test.cpp index d48c37e..0a01ea2 100644 --- a/test/topology_loader_test.cpp +++ b/test/topology_loader_test.cpp @@ -12,14 +12,11 @@ namespace csim::test { class TopologyLoaderTest : public ::testing::Test { public: - sim_t sim; - System sys{sim}; + sim_t sim; + System sys{sim}; std::filesystem::path test_file = "test_topology.json"; - void SetUp() override - { - csim::config::clear(); - } + void SetUp() override { csim::config::clear(); } void TearDown() override {