From 41df520642e9c4198dc7a14def225ae7b884ac70 Mon Sep 17 00:00:00 2001 From: Arpan Suravi Prasad Date: Mon, 9 Dec 2024 09:54:09 +0100 Subject: [PATCH] [TB] Fast Preload of binary for fast debug 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. --- target/sim/src/tb_chimera_soc.sv | 87 +++++++++++++++++++++++++++++-- target/sim/src/vip_chimera_soc.sv | 28 ++++++++++ 2 files changed, 112 insertions(+), 3 deletions(-) diff --git a/target/sim/src/tb_chimera_soc.sv b/target/sim/src/tb_chimera_soc.sv index c35548a..3a61566 100644 --- a/target/sim/src/tb_chimera_soc.sv +++ b/target/sim/src/tb_chimera_soc.sv @@ -5,7 +5,9 @@ // Nicole Narr // Christopher Reinwardt -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 ); @@ -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 = ""; @@ -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 @@ -63,4 +144,4 @@ module tb_chimera_soc #( $finish; end -endmodule +endmodule \ No newline at end of file diff --git a/target/sim/src/vip_chimera_soc.sv b/target/sim/src/vip_chimera_soc.sv index 973c618..2339fa5 100644 --- a/target/sim/src/vip_chimera_soc.sv +++ b/target/sim/src/vip_chimera_soc.sv @@ -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;