Skip to content

Commit

Permalink
[TB] Fast Preload of binary for fast debug
Browse files Browse the repository at this point in the history
In the existing testbench the binary preload takes a lot of time due to JTAG load.
A fast preload of binary is done by forcing the relevant signals in the narrow interconnect
of the memory island. The method still relies on JTAG to halt and unhalt the core whereas the
preload(significant portion) is done through forcing the relevant memory signals.
  • Loading branch information
arpansur committed Dec 9, 2024
1 parent ba901e9 commit 41df520
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 3 deletions.
87 changes: 84 additions & 3 deletions target/sim/src/tb_chimera_soc.sv
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
// Nicole Narr <narrn@student.ethz.ch>
// Christopher Reinwardt <creinwar@student.ethz.ch>

module tb_chimera_soc #(
module tb_chimera_soc
import cheshire_pkg::*;
#(
/// The selected simulation configuration from the `tb_chimera_pkg`.
parameter int unsigned SelectedCfg = 32'd0
);
Expand All @@ -17,11 +19,74 @@ module tb_chimera_soc #(
logic [ 1:0] boot_mode;
logic [ 1:0] preload_mode;
bit [31:0] exit_code;
import "DPI-C" function byte read_elf(input string filename);
import "DPI-C" function byte get_entry(output longint entry);
import "DPI-C" function byte get_section(
output longint address,
output longint len
);
import "DPI-C" context function byte read_section(
input longint address,
inout byte buffer [],
input longint len
);

// Load a binary
task automatic force_write(doub_bt addr, doub_bt data);
static doub_bt write_address;
static doub_bt write_data;
write_address = addr;
write_data = data;
force fix.dut.i_memisland_domain.i_memory_island.i_memory_island.narrow_addr_i[1] = write_address;
force fix.dut.i_memisland_domain.i_memory_island.i_memory_island.narrow_req_i[1] = 1'b1;
force fix.dut.i_memisland_domain.i_memory_island.i_memory_island.narrow_we_i[1] = 1'b1;
force fix.dut.i_memisland_domain.i_memory_island.i_memory_island.narrow_wdata_i[1] = write_data;
force fix.dut.i_memisland_domain.i_memory_island.i_memory_island.narrow_strb_i[1] = 4'hf;
force fix.dut.i_memisland_domain.i_memory_island.i_memory_island.narrow_gnt_o[1] = 1'b0;
force fix.dut.i_memisland_domain.i_memory_island.i_memory_island.narrow_rvalid_o[1] = 1'b0;
endtask


task automatic fast_elf_preload(input string binary);
longint sec_addr, sec_len;
$display("[FAST PRELOAD] Preloading ELF binary: %s", binary);
if (read_elf(binary)) $fatal(1, "[JTAG] Failed to load ELF!");
while (get_section(
sec_addr, sec_len
)) begin
byte bf[] = new[sec_len];
$display("[FAST PRELOAD] Preloading section at 0x%h (%0d bytes)", sec_addr, sec_len);
if (read_section(sec_addr, bf, sec_len)) $fatal(1, "[FAST PRELOAD] Failed to read ELF section!");
@(posedge fix.vip.soc_clk);//
for (longint i = 0; i <= sec_len; i += riscv::XLEN / 8) begin
bit checkpoint = (i != 0 && i % 512 == 0);
if (checkpoint)
$display(
"[FAST PRELOAD] - %0d/%0d bytes (%0d%%)",
i,
sec_len,
i * 100 / (sec_len > 1 ? sec_len - 1 : 1)
);
@(posedge fix.vip.soc_clk);
force_write((sec_addr+i), {bf[i+3], bf[i+2], bf[i+1], bf[i]});
end
end
@(posedge fix.vip.soc_clk);
release fix.dut.i_memisland_domain.i_memory_island.i_memory_island.narrow_addr_i[1];
release fix.dut.i_memisland_domain.i_memory_island.i_memory_island.narrow_req_i[1];
release fix.dut.i_memisland_domain.i_memory_island.i_memory_island.narrow_we_i[1];
release fix.dut.i_memisland_domain.i_memory_island.i_memory_island.narrow_wdata_i[1];
release fix.dut.i_memisland_domain.i_memory_island.i_memory_island.narrow_strb_i[1];
release fix.dut.i_memisland_domain.i_memory_island.i_memory_island.narrow_gnt_o[1];
release fix.dut.i_memisland_domain.i_memory_island.i_memory_island.narrow_rvalid_o[1];
// a few cycles safety margin after the end of transactions
repeat (3) @(posedge fix.vip.soc_clk);
endtask

initial begin
// Fetch plusargs or use safe (fail-fast) defaults
if (!$value$plusargs("BOOTMODE=%d", boot_mode)) boot_mode = 0;
if (!$value$plusargs("PRELMODE=%d", preload_mode)) preload_mode = 0;
if (!$value$plusargs("PRELMODE=%d", preload_mode)) preload_mode = 3;
if (!$value$plusargs("BINARY=%s", preload_elf)) preload_elf = "";
if (!$value$plusargs("IMAGE=%s", boot_hex)) boot_hex = "";

Expand All @@ -45,6 +110,22 @@ module tb_chimera_soc #(
2: begin // UART
fix.vip.uart_debug_elf_run_and_wait(preload_elf, exit_code);
end
3: begin // FAST DEBUG
// Initialize JTAG
fix.vip.jtag_init();
// Halt the core
fix.vip.jtag_elf_halt();
// Preload the binary through FAST PRELOAD
fast_elf_preload(preload_elf);
// Unhalt the core
fix.vip.jtag_elf_unhalt();
fix.dut.i_cluster_domain.gen_clusters[0].i_chimera_cluster.boot_cluster();
fix.dut.i_cluster_domain.gen_clusters[1].i_chimera_cluster.boot_cluster();
fix.dut.i_cluster_domain.gen_clusters[2].i_chimera_cluster.boot_cluster();
fix.dut.i_cluster_domain.gen_clusters[3].i_chimera_cluster.boot_cluster();
fix.dut.i_cluster_domain.gen_clusters[4].i_chimera_cluster.boot_cluster();
fix.vip.jtag_wait_for_eoc(exit_code);
end
default: begin
$fatal(1, "Unsupported preload mode %d (reserved)!", boot_mode);
end
Expand All @@ -63,4 +144,4 @@ module tb_chimera_soc #(
$finish;
end

endmodule
endmodule
28 changes: 28 additions & 0 deletions target/sim/src/vip_chimera_soc.sv
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,34 @@ module vip_chimera_soc
jtag_elf_preload(binary, entry);
endtask

// Halt the core
task automatic jtag_elf_halt();
dm::dmstatus_t status;
// Halt hart 0
jtag_write(dm::DMControl, dm::dmcontrol_t'{haltreq: 1, dmactive: 1, default: '0});
do jtag_dbg.read_dmi_exp_backoff(dm::DMStatus, status); while (~status.allhalted);
repeat (2) @(posedge jtag_tck);
$display("[JTAG] Halted hart 0");
endtask

// Unhalt the core
task automatic jtag_elf_unhalt();
doub_bt entry;
repeat (2) @(posedge jtag_tck);
void'(get_entry(entry));
// Repoint execution
jtag_write(dm::Data1, entry[63:32]);
jtag_write(dm::Data0, entry[31:0]);
if (riscv::XLEN == 64) begin
jtag_write(dm::Command, 32'h0033_07b1, 0, 1);
end else begin
jtag_write(dm::Command, 32'h0023_07b1, 0, 1);
end
// Resume hart 0
jtag_write(dm::DMControl, dm::dmcontrol_t'{resumereq: 1, dmactive: 1, default: '0});
$display("[JTAG] Resumed hart 0 from 0x%h", entry);
endtask

// Run a binary
task automatic jtag_elf_run(input string binary);
doub_bt entry;
Expand Down

0 comments on commit 41df520

Please sign in to comment.