diff --git a/cheshire.mk b/cheshire.mk index 8dbbe10f..03f5e492 100644 --- a/cheshire.mk +++ b/cheshire.mk @@ -7,6 +7,7 @@ # Paul Scheffler BENDER ?= bender +MORTY ?= morty VLOG_ARGS ?= -suppress 2583 -suppress 13314 VSIM ?= vsim @@ -163,6 +164,17 @@ $(CHS_ROOT)/target/xilinx/scripts/add_sources.tcl: Bender.yml CHS_XILINX_ALL += $(CHS_ROOT)/target/xilinx/scripts/add_sources.tcl +############# +# Pickle # +############# + +$(CHS_ROOT)/target/pickle/sources.json: Bender.yml Bender.lock + $(BENDER) sources -t fpga -t cv64a6_imafdcsclic_sv39 -t cva6 -f > $@ + +$(CHS_ROOT)/target/pickle/%.sv: $(CHS_ROOT)/target/pickle/sources.json + $(MORTY) -f $^ --top $* -i --sequential --propagate_defines -o $@ + + ################################# # Phonies (KEEP AT END OF FILE) # ################################# diff --git a/docs/tg/sim.md b/docs/tg/sim.md index 169690b4..18d4aa44 100644 --- a/docs/tg/sim.md +++ b/docs/tg/sim.md @@ -28,6 +28,8 @@ The `SELCFG` parameter selects the simulation configuration specified in the `tb | 0 | Default configuration from `cheshire_pkg` | | 1 | AXI-RT-enabled configuration | +Defining `PRTCFG` and setting its value to 1 prints the Cheshire and its derived configuration structs at `t=0`. + For simulation of Cheshire in other designs, we provide the module `cheshire_vip` encapsulating all verification IPs and their interfaces. For details, see [Verifying Cheshire In-System](integr.md#verifying-cheshire-in-system). ## QuestaSim diff --git a/hw/cheshire_pkg.sv b/hw/cheshire_pkg.sv index 014f4ab3..4bef752e 100644 --- a/hw/cheshire_pkg.sv +++ b/hw/cheshire_pkg.sv @@ -604,4 +604,132 @@ package cheshire_pkg; default: '0 }; + + //////////////////////////// + // Configuration Printer // + //////////////////////////// + + function automatic string format_config ( + string cfg_str, + int unsigned int_hex_split, + int unsigned param_name_width + ); + + // determine length of the string + automatic int unsigned cfg_len = cfg_str.len(); + + // temp variables + automatic string cfg_item = ""; + automatic bit array_active = 0; + automatic bit unnamed_array = 0; + automatic bit was_closed = 0; + automatic int unsigned unnamed_idx = 0; + automatic string padding = ""; + + // overwrite closing bracket to terminate config string + cfg_str.putc(cfg_len-1, ","); + + // parse each character individually, start from index 2 to omit the "'{" + for (int i = 2; i < cfg_len; i++) begin + // go through the characters individually. The default case is to accumulate them in the + // `cfg_item` buffer. + + // colon denotes the separation between named value and value + // Goal: print the padded key of a named value + if (cfg_str[i] == ":") begin + + // decide if we are in array mode: print an indentation + if (array_active) begin + for (int p = 0; p < param_name_width - cfg_item.len() - 4; p++) begin + padding = {padding, " "}; + end + format_config = {format_config, $sformatf(" %s:%s", cfg_item, padding)}; + // print no indentation + end else begin + for (int p = 0; p < param_name_width - cfg_item.len(); p++) begin + padding = {padding, " "}; + end + format_config = {format_config, $sformatf("%s:%s", cfg_item, padding)}; + end + + // reset accumulator and padding + padding = ""; + cfg_item = ""; + + // we found a named key: we thus don't have an array of unnamed values + if (array_active) begin + unnamed_array = 0; + end + + // comma: finishes an entry. We print the value. In the case of unnamed values we add an + // increasing key. + end else if (cfg_str[i] == ",") begin + automatic longint unsigned value = cfg_item.atoi(); + automatic string unnamed_idx_str = $sformatf("%-0d", unnamed_idx); + automatic string padding = ""; + + // we print the unnamed array index and the corresponding padding + if (array_active & unnamed_array) begin + for (int p = 0; p < param_name_width - unnamed_idx_str.len() - 4; p++) begin + padding = {padding, " "}; + end + format_config = {format_config, $sformatf(" %s:%s", unnamed_idx_str, padding)}; + end + + // we print a value: use a defined threshold to differentiate between unsigned and + // hex values + if (value < int_hex_split) begin + format_config = {format_config, $sformatf(" %d", value)}; + end else begin + // some hex formatting increasing legibility + automatic string hex_val = $sformatf("%h", value); + format_config = {format_config, "0x"}; + for (int h = 0; h < hex_val.len(); h++) begin + if (h % 4 == 0 && h > 0) begin + format_config = {format_config, "_"}; + end + format_config = {format_config, $sformatf("%s", hex_val[h])}; + end + end + + // reset accumulator and padding + padding = ""; + cfg_item = ""; + + // array bookkeeping + unnamed_idx = unnamed_idx + 1; + if (was_closed) begin + was_closed = 0; + array_active = 0; + end + + // finish entry + format_config = {format_config, "\n"}; + + // space: ignore + end else if (cfg_str[i] == " ") begin + continue; + + // ': ignore + end else if (cfg_str[i] == "'") begin + continue; + + // }: close the bracket + end else if (cfg_str[i] == "}") begin + was_closed = 1; + + // {: begin array + end else if (cfg_str[i] == "{") begin + array_active = 1; + unnamed_array = 1; + unnamed_idx = 0; + format_config = {format_config, "\n"}; + + // default: append char to accumulator + end else begin + cfg_item = {cfg_item, cfg_str[i]}; + end + end + endfunction + endpackage diff --git a/target/pickle/.gitignore b/target/pickle/.gitignore new file mode 100644 index 00000000..2a390c97 --- /dev/null +++ b/target/pickle/.gitignore @@ -0,0 +1,2 @@ +sources.json +*.sv diff --git a/target/pickle/get_config.py b/target/pickle/get_config.py new file mode 100644 index 00000000..59b85c08 --- /dev/null +++ b/target/pickle/get_config.py @@ -0,0 +1,34 @@ +import sys +import time +from pyslang import * + +class ModuleVisitor: + def __init__(self, file_in: str): + self.tree = SyntaxTree.fromText(file_in) + self.comp = Compilation() + self.comp.addSyntaxTree(self.tree) + # Analysis results; contains per-transform dicts indexed by *syntax source start offsets*! + # self.compinfo = defaultdict(dict) + # self.compinfo['__eval'] = EvalContext(self.comp) + # self.compinfo['__iterate'] = self._iterate_member + + def traverse(self) -> str: + # Analyze compilation first and collect info + self.comp.getRoot().visit(self._comp_visit) + #return self._rewrite_member(self.tree.root) + + def _comp_visit(self, sym): + print(sym) + #if isinstance(sym, AssignmentExpression): + # analyze_assignment(self.compinfo, sym) + #elif isinstance(sym, Expression): + # analyze_expression(self.compinfo, sym) + +def main(file_in: str, top_module: str): + ModuleVisitor(file_in).traverse() + + + +# TODO: cmdline parser! +if __name__ == '__main__': + sys.exit(main('cheshire_soc.sv', 'cheshire_soc')) diff --git a/target/sim/src/fixture_cheshire_soc.sv b/target/sim/src/fixture_cheshire_soc.sv index 00f0c493..61a01123 100644 --- a/target/sim/src/fixture_cheshire_soc.sv +++ b/target/sim/src/fixture_cheshire_soc.sv @@ -8,7 +8,9 @@ module fixture_cheshire_soc #( /// The selected simulation configuration from the `tb_cheshire_pkg`. - parameter int unsigned SelectedCfg = 32'd0 + parameter int unsigned SelectedCfg = 32'd0, + /// Print the Cheshire config at launch + parameter bit PrintCfg = 1'b0 ); `include "cheshire/typedef.svh" @@ -18,8 +20,33 @@ module fixture_cheshire_soc #( localparam cheshire_cfg_t DutCfg = TbCheshireConfigs[SelectedCfg]; + // print the configs + initial begin + if (PrintCfg) begin : gen_print_cfg + $display("\n\nAXI In Config"); + $display("----------------------------------------------"); + $display("%s", format_config($sformatf("%p", gen_axi_in(DutCfg)), 4096, 24)); + $display("\n\nAXI Out Config"); + $display("----------------------------------------------"); + $display("%s", format_config($sformatf("%p", gen_axi_out(DutCfg)), 4096, 24)); + $display("\n\nRegbus In Config"); + $display("----------------------------------------------"); + $display("%s", format_config($sformatf("%p", gen_reg_out(DutCfg)), 4096, 24)); + $display("\n\nCVA6 ID Map"); + $display("----------------------------------------------"); + $display("%s", format_config($sformatf("%p", gen_cva6_id_map(DutCfg)), 4096, 24)); + $display("\n\nCVA6 Config"); + $display("----------------------------------------------"); + $display("%s", format_config($sformatf("%p", gen_cva6_cfg(DutCfg)), 4096, 24)); + $display("\n\nCheshire Config"); + $display("----------------------------------------------"); + $display("%s", format_config($sformatf("%p", DutCfg), 4096, 24)); + end + end + `CHESHIRE_TYPEDEF_ALL(, DutCfg) + /////////// // DUT // /////////// diff --git a/target/sim/src/tb_cfg_printer.sv b/target/sim/src/tb_cfg_printer.sv new file mode 100644 index 00000000..c5327ccd --- /dev/null +++ b/target/sim/src/tb_cfg_printer.sv @@ -0,0 +1,139 @@ +module tb_cfg_printer #( + /// The selected simulation configuration from the `tb_cheshire_pkg`. + parameter int unsigned SelectedCfg = 32'd0 +); + import cheshire_pkg::*; + import tb_cheshire_pkg::*; + localparam cheshire_cfg_t DutCfg = TbCheshireConfigs[SelectedCfg]; + // import "DPI-C" function void format_cfg(input string cfg_str, input int length); + // + // initial begin + // static string cfg_str = $sformatf("%p", DutCfg); + // format_cfg(cfg_str, cfg_str.len()); + // end + + + initial begin + // constants + static int unsigned int_hex_split = 4096; + static int unsigned param_name_width = 24; + + // get the string + static string cfg_str = $sformatf("%p", DutCfg); + static integer cfg_len = cfg_str.len(); + + // temp variables + static string cfg_item = ""; + static bit array_active = 0; + static bit unnamed_array = 0; + static bit was_closed = 0; + static int unsigned unnamed_idx = 0; + static string padding = ""; + + // overwrite closing bracket to terminate config string + cfg_str.putc(cfg_len-1, ","); + + // parse each character individually, start from index 2 to omit the "'{" + for (int i = 2; i < cfg_len; i++) begin + // go through the characters individually. The default case is to accumulate them in the + // `cfg_item` buffer. + + // colon denotes the separation between named value and value + // Goal: print the padded key of a named value + if (cfg_str[i] == ":") begin + + // decide if we are in array mode: print an indentation + if (array_active) begin + for (int p = 0; p < param_name_width - cfg_item.len() - 4; p++) begin + padding = {padding, " "}; + end + $write(" %s:%s", cfg_item, padding); + // print no indentation + end else begin + for (int p = 0; p < param_name_width - cfg_item.len(); p++) begin + padding = {padding, " "}; + end + $write("%s:%s", cfg_item, padding); + end + + // reset accumulator and padding + padding = ""; + cfg_item = ""; + + // we found a named key: we thus don't have an array of unnamed values + if (array_active) begin + unnamed_array = 0; + end + + // comma: finishes an entry. We print the value. In the case of unnamed values we add an + // increasing key. + end else if (cfg_str[i] == ",") begin + automatic longint unsigned value = cfg_item.atoi(); + automatic string unnamed_idx_str = $sformatf("%-0d", unnamed_idx); + automatic string padding = ""; + + // we print the unnamed array index and the corresponding padding + if (array_active & unnamed_array) begin + for (int p = 0; p < param_name_width - unnamed_idx_str.len() - 4; p++) begin + padding = {padding, " "}; + end + $write(" %s:%s", unnamed_idx_str, padding); + end + + // we print a value: use a defined threshold to differentiate between unsigned and + // hex values + if (value < int_hex_split) begin + $write(" %d", value); + end else begin + // some hex formatting increasing legibility + automatic string hex_val = $sformatf("%h", value); + $write("0x"); + for (int h = 0; h < hex_val.len(); h++) begin + if (h % 4 == 0 && h > 0) begin + $write("_"); + end + $write("%s", hex_val[h]); + end + end + + // reset accumulator and padding + padding = ""; + cfg_item = ""; + + // array bookkeeping + unnamed_idx = unnamed_idx + 1; + if (was_closed) begin + was_closed = 0; + array_active = 0; + end + + // finish entry + $write("\n"); + + // space: ignore + end else if (cfg_str[i] == " ") begin + continue; + + // ': ignore + end else if (cfg_str[i] == "'") begin + continue; + + // }: close the bracket + end else if (cfg_str[i] == "}") begin + was_closed = 1; + + // {: begin array + end else if (cfg_str[i] == "{") begin + array_active = 1; + unnamed_array = 1; + unnamed_idx = 0; + $write("\n"); + + // default: append char to accumulator + end else begin + cfg_item = {cfg_item, cfg_str[i]}; + end + end + end + +endmodule diff --git a/target/sim/src/tb_cheshire_soc.sv b/target/sim/src/tb_cheshire_soc.sv index 3e426c3f..664bed07 100644 --- a/target/sim/src/tb_cheshire_soc.sv +++ b/target/sim/src/tb_cheshire_soc.sv @@ -7,10 +7,15 @@ module tb_cheshire_soc #( /// The selected simulation configuration from the `tb_cheshire_pkg`. - parameter int unsigned SelectedCfg = 32'd0 + parameter int unsigned SelectedCfg = 32'd0, + /// Print the Cheshire config at launch + parameter bit PrintCfg = 1'b0 ); - fixture_cheshire_soc #(.SelectedCfg(SelectedCfg)) fix(); + fixture_cheshire_soc #( + .SelectedCfg ( SelectedCfg ), + .PrintCfg ( PrintCfg ) + ) fix(); string preload_elf; string boot_hex; diff --git a/target/sim/vsim/start.cheshire_soc.tcl b/target/sim/vsim/start.cheshire_soc.tcl index f9d6cad2..3e6bf855 100644 --- a/target/sim/vsim/start.cheshire_soc.tcl +++ b/target/sim/vsim/start.cheshire_soc.tcl @@ -17,6 +17,7 @@ if {![info exists VOPTARGS]} { set flags "-permissive -suppress 3009 -suppress 8386 -error 7 " if {[info exists SELCFG]} { append flags "-GSelectedCfg=${SELCFG} " } +if {[info exists PRTCFG]} { append flags "-GPrintCfg=${PRTCFG} " } set pargs "" if {[info exists BOOTMODE]} { append pargs "+BOOTMODE=${BOOTMODE} " }