Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
562bfe9
Adding FIFO tracing capabilities in simulation.
preusser May 27, 2026
2ea5192
Merge branch 'dev' into feature.fifo_debug
auphelia May 27, 2026
30f9440
[CustomOp] Select behav sim for rtl eltwise ops with flag
auphelia May 27, 2026
badc3e1
[Builder] Add flag to allow user to use behavioral models for functio…
auphelia May 27, 2026
989ce5c
[Debug FIFO] Logging working for fifo depth simulation with debug_fif…
STFleming May 27, 2026
fe6fc2f
Linting
auphelia May 28, 2026
2104c34
[xsi] Align python xsi with c++ driven simulation
auphelia May 29, 2026
889da60
[Builder] Disable FINN_SIMULATION for rtlsim performance
auphelia May 29, 2026
86892ca
[Debug FIFO] FINN_LOOP prefix was missing from the debug fifo log nam…
STFleming Jun 5, 2026
51c0bac
Merge branch 'dev' into feature.fifo_debug
auphelia Jun 5, 2026
59184ec
Consolidated testbench driving starting a cycle with the active clock…
preusser Jun 9, 2026
b4b1da9
Merge remote-tracking branch 'origin/feature.fifo_debug' into feature…
preusser Jun 9, 2026
05577c4
[Debug FIFO] work around logging crash issue by sending tagged log da…
STFleming Jun 12, 2026
34b8093
Merge remote-tracking branch 'origin/feature.fifo_debug' into feature…
STFleming Jun 12, 2026
8351c0f
[Debug FIFO] fixing minor issue where the sim_finish signal was not a…
STFleming Jun 12, 2026
ae85bdb
[Debug FIFO] pre commit
STFleming Jun 12, 2026
d24bcb1
[FIFO Debug] Added a workaround for the early final block execution
STFleming Jun 12, 2026
55e675c
[Debug FIFO] restoring pre-file logging with phase snapshotting now t…
STFleming Jun 17, 2026
05cfdf5
[Debug FIFO] precommit
STFleming Jun 17, 2026
7e00076
[FIFO Debug] Increase busy loop delay to keep sim alive
STFleming Jun 19, 2026
6e7f30d
Linting.
preusser-amd Jun 19, 2026
27085b6
Merge branch 'dev' into feature.fifo_debug
preusser Jun 19, 2026
44fc768
Prune unused module port.
preusser Jun 19, 2026
2c1e50e
Fixing test.
preusser Jun 19, 2026
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
4 changes: 3 additions & 1 deletion finn-rtllib/eltwise/eltwise_template.v
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ eltwise #(
.PE($PE$),
.OP($OP$),
.B_SCALE($B_SCALE$),
.FORCE_BEHAVIORAL($FORCE_BEHAVIORAL$),
`ifdef FINN_SIMULATION
.FORCE_BEHAVIORAL(1),
`endif
.A_FLOAT($A_FLOAT$),
.B_FLOAT($B_FLOAT$),
.A_WIDTH($A_WIDTH$),
Expand Down
36 changes: 30 additions & 6 deletions finn-rtllib/fifo/hdl/fifo_gauge.sv
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@

module fifo_gauge #(
int unsigned WIDTH,
int unsigned COUNT_WIDTH = 32
int unsigned COUNT_WIDTH = 32,
parameter DATA_LOGFILE = ""
)(
input logic clk,
input logic rst,
Expand All @@ -51,25 +52,48 @@ module fifo_gauge #(
output logic [COUNT_WIDTH-1:0] maxcount
);

//-----------------------------------------------------------------------
// Monitoring & Debug

// Transaction counters
longint unsigned ITxnCnt = 0;
longint unsigned OTxnCnt = 0;
int LogFd = (DATA_LOGFILE != "")? $fopen(DATA_LOGFILE, "w") : 0;

// The internal Queue serving as data buffer and an output register
logic [WIDTH-1:0] Q[$] = {};
logic [COUNT_WIDTH-1:0] Count = 0;
logic [COUNT_WIDTH-1:0] MaxCount = 0;
longint unsigned Count = 0;
longint unsigned MaxCount = 0;

logic OVld = 0;
logic [WIDTH-1:0] ODat = 'x;

final begin
if(LogFd) begin
$fwrite(LogFd, "[%m @%0t] MaxFill: %0d; Transactions: in=%0d out=%0d\n", $time, MaxCount, ITxnCnt, OTxnCnt);
$fclose(LogFd);
end
end

always_ff @(posedge clk) begin
if(rst) begin
Q <= {};
Q = {};
Count <= 0;
MaxCount <= 0;
OVld <= 0;
ODat <= 'x;

ITxnCnt <= 0;
OTxnCnt <= 0;
end
else begin
// Always take input
if(ivld) Q.push_back(idat);
// Always take input and track Transactions
if(ivld) begin
Q.push_back(idat);
if(LogFd) $fwrite(LogFd, "%0x\n", idat);
ITxnCnt <= ITxnCnt + 1;
end
if(OVld && ordy) OTxnCnt <= OTxnCnt + 1;

// Take Count
Count <= Q.size;
Expand Down
5 changes: 4 additions & 1 deletion finn-rtllib/fifo/hdl/fifo_gauge_tb.sv
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ module fifo_gauge_tb;
// Depth Monitoring
uwire count_t maxcount;

fifo_gauge #(.WIDTH(W)) dut (
fifo_gauge #(.WIDTH(W), .DATA_LOGFILE("fifo_trace.log")) dut (
.clk, .rst,
.idat, .ivld, .irdy,
.odat, .ovld, .ordy,
Expand All @@ -70,6 +70,7 @@ module fifo_gauge_tb;
// Stimulus
data_t Q[$] = {};
initial begin
automatic int ref_fd = $fopen("fifo_ref.log", "w");
idat = 'x;
ivld = 0;
@(posedge clk iff !rst);
Expand All @@ -79,10 +80,12 @@ module fifo_gauge_tb;
idat <= data;
ivld <= 1;
Q.push_back(data);
$fwrite(ref_fd, "%0x\n", data);
@(posedge clk);
idat <= 'x;
ivld <= 0;
end
$fclose(ref_fd);
end

//-----------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion finn-rtllib/fifo/hdl/fifo_template.v
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ output $OUT_RANGE$ out0_V_TDATA
);

`ifdef FINN_SIMULATION
fifo_gauge #(.WIDTH($WIDTH$), .COUNT_WIDTH($COUNT_WIDTH$)) fifo (
fifo_gauge #(.WIDTH($WIDTH$), .COUNT_WIDTH($COUNT_WIDTH$), .DATA_LOGFILE("$DATA_LOGFILE$")) fifo (
.clk(ap_clk), .rst(!ap_rst_n),
.idat(in0_V_TDATA), .ivld(in0_V_TVALID), .irdy(in0_V_TREADY),
.odat(out0_V_TDATA), .ovld(out0_V_TVALID), .ordy(out0_V_TREADY),
Expand Down
25 changes: 25 additions & 0 deletions finn-rtllib/fifo/sim.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/bin/bash
##############################################################################
# Copyright Advanced Micro Devices, Inc.
# SPDX-License-Identifier: BSD-3-Clause
#
# @brief FIFO gauge simulation script.
# @author Thomas B. Preußer <thomas.preusser@amd.com>
##############################################################################
set -euo pipefail
cd "$(dirname "$0")"

rm -f fifo_trace.log fifo_ref.log

xvlog -sv hdl/fifo_gauge.sv hdl/fifo_gauge_tb.sv
xelab fifo_gauge_tb -debug off -s sim
xsim sim -runall

echo "---"
if diff -q fifo_ref.log <(grep -v '^\[' fifo_trace.log); then
echo "PASS: trace matches reference ($(wc -l < fifo_ref.log) lines)"
else
echo "FAIL: trace mismatch"
diff fifo_ref.log fifo_trace_data.log | head -20
exit 1
fi
15 changes: 15 additions & 0 deletions finn-rtllib/sim/hdl/sim_ctrl.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/****************************************************************************
* Copyright Advanced Micro Devices, Inc.
* SPDX-License-Identifier: BSD-3-Clause
*
* @brief Simulation control triggering $finish upon asserting sim_finish.
* @author Shane T. Fleming <shane.fleming@amd.com>
***************************************************************************/
module sim_ctrl(input ap_clk, input sim_finish);
`ifdef FINN_SIMULATION
initial @(posedge sim_finish) $finish;
// This ensures there is always a pending #delay in the event queue,
// preventing the kernel from concluding that the simulation is ending.
initial forever #1_000_000_000;
`endif
endmodule
4 changes: 4 additions & 0 deletions finn_xsi/finn_xsi/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,10 @@ def reset_rtlsim(


def close_rtlsim(sim):
sim_finish = sim.top.getPort("sim_finish")
if sim_finish is not None:
sim_finish.set(1).write_back()
sim.cycle({})
del sim


Expand Down
31 changes: 11 additions & 20 deletions finn_xsi/finn_xsi/sim_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,30 +24,21 @@ def __init__(self, kernel, design, log=None, wdb=None):
if p.isInput():
p.clear().write_back()

def cycle(updates):
# Rising Edge
clk.set(1).write_back()
def half_cycle(up):
clk.set(up).write_back()
if clk2x is not None:
clk2x.set(1).write_back()
# Updates after Active Edge
top.run(1)
top.run(25)
clk2x.set(0).write_back()
top.run(25)
else:
top.run(50)

def cycle(updates):
half_cycle(1)
for port, update in updates.items():
port.set_hexstr(update).write_back()

# Edges inactive on interface & finish Cycle
if clk2x is None:
top.run(4999)
clk.set(0).write_back()
top.run(5000)
else:
top.run(2499)
clk2x.set(0).write_back()
top.run(2500)
clk.set(0).write_back()
clk2x.set(1).write_back()
top.run(2500)
clk2x.set(0).write_back()
top.run(2500)
half_cycle(0)

self.top = top
self.cycle = cycle
Expand Down
85 changes: 50 additions & 35 deletions finn_xsi/rtlsim_xsi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,15 @@
#include <sstream>
#include <fstream>
#include <chrono>
#include <map>
#include <vector>
#include <tuple>
#include <functional>

#include "xsi_finn.hpp"
#include "rtlsim_config.hpp"

int main(int argc, char *argv[]) {
int main(int const argc, char const *const argv[]) {

// Load Kernel and Design
xsi::Kernel kernel(kernel_libname);
Expand All @@ -34,6 +35,7 @@ int main(int argc, char *argv[]) {

// Ultimate Simulation Summary
std::string synopsis;
std::map<std::string, unsigned> maxcounts;

{ // RTL Simulation

Expand All @@ -54,11 +56,11 @@ int main(int argc, char *argv[]) {
size_t job_size;
size_t job_txns; // [0:job_size]
size_t total_txns;
size_t first_complete; // First completion timestamp

union {
// Input Stream
struct {
size_t first_complete; // First completion timestamp
size_t job_ticks; // throttle if job_size < job_ticks
size_t await_iter; // iteration allowing start of next job
};
Expand Down Expand Up @@ -94,7 +96,8 @@ int main(int argc, char *argv[]) {
}

// Find Global Control & Run Startup Sequence
std::function<void(bool)> cycle;
std::function<void(std::vector<std::reference_wrapper<Port>>&)> cycle;
std::vector<std::reference_wrapper<Port>> to_write;
{
Port *const clk = top.getPort("ap_clk");
Port *const clk2x = top.getPort("ap_clk2x");
Expand All @@ -103,50 +106,52 @@ int main(int argc, char *argv[]) {
std::cerr << "No clock found on the design." << std::endl;
return 1;
}
cycle = clk2x?
std::function<void(bool)>([&top, clk, clk2x](bool const up) mutable {
cycle = [half = clk2x?
std::function<void(bool)>([&top, clk, clk2x](bool const up) {
clk->set(up).write_back();
clk2x->set(1).write_back();
top.run(5);
top.run(25);
clk2x->set(0).write_back();
top.run(5);
top.run(25);
}) :
std::function<void(bool)>([&top, clk](bool const up) mutable {
std::function<void(bool)>([&top, clk](bool const up) {
clk->set(up).write_back();
top.run(5);
});
top.run(50);
})
](std::vector<std::reference_wrapper<Port>> &to_write) {
half(1);
for(Port &p : to_write) p.write_back();
to_write.clear();
half(0);
};

// Reset all Inputs, Wait for Reset Period
for(Port &p : top.ports()) { if(p.isInput()) p.clear().write_back(); };
if(rst_n) {
for(unsigned i = 0; i < 16; i++) { cycle(0); cycle(1); }
rst_n->set(1).write_back();
for(unsigned i = 0; i < 16; i++) cycle(to_write);
to_write.emplace_back(rst_n->set(1));
}
}

// Start Stream Feed and Capture
std::cout << "Starting data feed with idle-output timeout of " << max_iters << " cycles ...\n" << std::endl;

// Make all Inputs valid & all Outputs ready
for(auto &s : istreams) s.port_vld.set(1).write_back();
for(auto &s : ostreams) s.port_rdy.set(1).write_back();
for(auto &s : istreams) to_write.emplace_back(s.port_vld.set(1));
for(auto &s : ostreams) to_write.emplace_back(s.port_rdy.set(1));
cycle(to_write); // flush & settle before first read

// Enter Simulation Loop and track Progress
auto const begin = std::chrono::steady_clock::now();
std::vector<std::reference_wrapper<Port>> to_write;
while(true) {

//-------------------------------------------------------------------
// Clock down - then read signal updates from design
cycle(0);

// check for transactions on input streams
for(auto &s : istreams) {
bool const vld = s.port_vld[0];
bool const rdy = s.port_rdy.read()[0];
if(vld && !rdy) continue;

// Track successgul Transactions
// Track successful Transactions
if(vld) {
s.job_txns++;
if(++s.total_txns == s.job_size * n_inferences) itodo--;
Expand Down Expand Up @@ -194,12 +199,8 @@ int main(int argc, char *argv[]) {
}

//-------------------------------------------------------------------
// Clock up - then write signal updates back to design
cycle(1);

// Write back Ports with registered updates
for(Port &p : to_write) p.write_back();
to_write.clear();
// Advance clock: rise, write back, fall
cycle(to_write);

// Show a progress message once in a while
if(++iters % 10000 == 0) {
Expand Down Expand Up @@ -245,27 +246,41 @@ int main(int argc, char *argv[]) {
"RUNTIME_S\t" << std::chrono::duration_cast<std::chrono::seconds>(std::chrono::steady_clock::now() - begin).count();
synopsis = bld.str();

// Read maxcount ports before $finish tears down the design
for(Port &p : top.ports()) {
if(p.isOutput()) {
char const *const name = p.name();
if(std::strncmp(name, "maxcount", 8) == 0) {
p.read();
maxcounts[name] = p.as_unsigned();
}
}
}

} // done simulation

// Dump Simulation Statistics to stdout and results.txt
std::cout << '\n' << synopsis << std::endl;

{ // Log error info to file
// Trigger $finish so that final blocks execute
{
Port *const sim_finish = top.getPort("sim_finish");
if(sim_finish) {
sim_finish->set(1).write_back();
top.run(1);
}
}

{ // Log error info to file (includes final block output)
std::ofstream error_file("fifosim.err", std::ios::out | std::ios::trunc);
error_file << top.get_error_info();
}

{ // Synopsis and `max_count` readings to results file
std::ofstream results_file("results.txt", std::ios::out | std::ios::trunc);
results_file << synopsis << std::endl;
for(Port &p : top.ports()) {
if(p.isOutput()) {
char const *const name = p.name();
if(std::strncmp(name, "maxcount", 8) == 0) {
p.read();
results_file << name << '\t' << p.as_unsigned() << std::endl;
}
}
for(auto const &[name, val] : maxcounts) {
results_file << name << '\t' << val << std::endl;
}
}

Expand Down
Loading
Loading