From d7f3c330d4c4049177a0a2ece4edca0301c20ff1 Mon Sep 17 00:00:00 2001 From: Thomas Benz Date: Fri, 22 Sep 2023 15:33:12 +0200 Subject: [PATCH 1/5] Initial work towards a config printer --- cheshire.mk | 1 + target/sim/src/cfg_format.c | 121 +++++++++++++++++++++++++ target/sim/src/fixture_cheshire_soc.sv | 8 ++ 3 files changed, 130 insertions(+) create mode 100644 target/sim/src/cfg_format.c diff --git a/cheshire.mk b/cheshire.mk index 8dbbe10f..17894074 100644 --- a/cheshire.mk +++ b/cheshire.mk @@ -135,6 +135,7 @@ CHS_BOOTROM_ALL += $(CHS_ROOT)/hw/bootrom/cheshire_bootrom.sv $(CHS_ROOT)/hw/boo $(CHS_ROOT)/target/sim/vsim/compile.cheshire_soc.tcl: Bender.yml $(BENDER) script vsim -t sim -t cv64a6_imafdcsclic_sv39 -t test -t cva6 -t rtl --vlog-arg="$(VLOG_ARGS)" > $@ echo 'vlog "$(CURDIR)/$(CHS_ROOT)/target/sim/src/elfloader.cpp" -ccflags "-std=c++11"' >> $@ + echo 'vlog "$(CURDIR)/$(CHS_ROOT)/target/sim/src/cfg_format.c"' >> $@ $(CHS_ROOT)/target/sim/models: mkdir -p $@ diff --git a/target/sim/src/cfg_format.c b/target/sim/src/cfg_format.c new file mode 100644 index 00000000..31e95e7c --- /dev/null +++ b/target/sim/src/cfg_format.c @@ -0,0 +1,121 @@ +// Copyright 2022 ETH Zurich and University of Bologna. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// With a fuction copies from stackoverflow +// (https://stackoverflow.com/questions/8044081/how-to-do-regex-string-replacements-in-pure-c) +// +// Thomas Benz + + +#include +#include +#include +#include + +// replacement patterns +const char *NEWLINE_MATCH = ", ([A-Z])"; +const char *NEWLINE_REPLACE = "\n \1"; + +const char *COLON_MATCH = ":"; +const char *COLON_REPLACE = ": "; + + +int regex_replace(char **str, const char *pattern, const char *replace) { + // https://stackoverflow.com/questions/8044081/how-to-do-regex-string-replacements-in-pure-c + // replaces regex in pattern with replacement observing capture groups + // *str MUST be free-able, i.e. obtained by strdup, malloc, ... + // back references are indicated by char codes 1-31 and none of those chars can be used in the + // replacement string such as a tab. will not search for matches within replaced text, this + // will begin searching for the next match after the end of prev match + // returns: + // -1 if pattern cannot be compiled + // -2 if count of back references and capture groups don't match + // otherwise returns number of matches that were found and replaced + // + regex_t reg; + unsigned int replacements = 0; + // if regex can't commpile pattern, do nothing + if(!regcomp(®, pattern, REG_EXTENDED)) { + size_t nmatch = reg.re_nsub; + regmatch_t m[nmatch + 1]; + const char *rpl, *p; + // count back references in replace + int br = 0; + p = replace; + while(1) { + while(*++p > 31); + if(*p) br++; + else break; + } // if br is not equal to nmatch, leave + if(br != nmatch) { + regfree(®); + return -2; + } + // look for matches and replace + char *new; + char *search_start = *str; + while(!regexec(®, search_start, nmatch + 1, m, REG_NOTBOL)) { + // make enough room + new = (char *)malloc(strlen(*str) + strlen(replace)); + if(!new) exit(EXIT_FAILURE); + *new = '\0'; + strncat(new, *str, search_start - *str); + p = rpl = replace; + int c; + strncat(new, search_start, m[0].rm_so); // test before pattern + for(int k=0; k 31); // skip printable char + c = *p; // back reference (e.g. \1, \2, ...) + strncat(new, rpl, p - rpl); // add head of rpl + // concat match + strncat(new, search_start + m[c].rm_so, m[c].rm_eo - m[c].rm_so); + rpl = p++; // skip back reference, next match + } + strcat(new, p ); // trailing of rpl + unsigned int new_start_offset = strlen(new); + strcat(new, search_start + m[0].rm_eo); // trailing text in *str + free(*str); + *str = (char *)malloc(strlen(new)+1); + strcpy(*str,new); + search_start = *str + new_start_offset; + free(new); + replacements++; + } + regfree(®); + // ajust size + *str = (char *)realloc(*str, strlen(*str) + 1); + return replacements; + } else { + return -1; + } +} + + +// pretty printer +extern void format_cfg(char *cfg_str, int length) { + + // cut curly brackets away + char *cgf_str_cut = cfg_str + 2; + cgf_str_cut[length-3] = "\0"; + + // function works on a copy of the string + char *tmp = (char *)malloc(length + 1 - 4); + strcpy(tmp, cgf_str_cut); + + // infer newlines and fix colons + regex_replace(&tmp, NEWLINE_MATCH, NEWLINE_REPLACE); + regex_replace(&tmp, COLON_MATCH, COLON_REPLACE); + + // format numbers + regex_t find_num_pat; + size_t num_matches = 256; + regmatch_t match_array[256]; + regcomp(&find_num_pat, "[0-9]+", REG_EXTENDED); + regexec(&find_num_pat, tmp, num_matches, match_array, 0); + + // printf("%d", match_array[0].rm_eo); + + // print to questa terminal + printf("\nCheshire Configuration\n----------------------\n\n %s\n", tmp); +} diff --git a/target/sim/src/fixture_cheshire_soc.sv b/target/sim/src/fixture_cheshire_soc.sv index 00f0c493..4c519d77 100644 --- a/target/sim/src/fixture_cheshire_soc.sv +++ b/target/sim/src/fixture_cheshire_soc.sv @@ -20,6 +20,14 @@ module fixture_cheshire_soc #( `CHESHIRE_TYPEDEF_ALL(, DutCfg) + 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 + + /////////// // DUT // /////////// From 6c5fd5d5afd845308a8be820e8d58359109bbede Mon Sep 17 00:00:00 2001 From: Thomas Benz Date: Mon, 25 Sep 2023 17:30:41 +0200 Subject: [PATCH 2/5] Finish cfg printer prototype --- target/sim/src/fixture_cheshire_soc.sv | 7 -- target/sim/src/tb_cfg_printer.sv | 127 +++++++++++++++++++++++++ 2 files changed, 127 insertions(+), 7 deletions(-) create mode 100644 target/sim/src/tb_cfg_printer.sv diff --git a/target/sim/src/fixture_cheshire_soc.sv b/target/sim/src/fixture_cheshire_soc.sv index 4c519d77..96bdfd7f 100644 --- a/target/sim/src/fixture_cheshire_soc.sv +++ b/target/sim/src/fixture_cheshire_soc.sv @@ -20,13 +20,6 @@ module fixture_cheshire_soc #( `CHESHIRE_TYPEDEF_ALL(, DutCfg) - 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 - /////////// // 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..54330db3 --- /dev/null +++ b/target/sim/src/tb_cfg_printer.sv @@ -0,0 +1,127 @@ +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; + + // terminate config string + cfg_str.putc(cfg_len-1, ","); + + // parse each character individually + for (int i = 2; i < cfg_len; i++) begin + + // colon + if (cfg_str[i] == ":") begin + // we print a key + automatic string padding = ""; + + // decide if we are in array mode + 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); + 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 + cfg_item = ""; + + // differentiate between unnamed and named arrays + if (array_active) begin + unnamed_array = 0; + end + + // comma + 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 + 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 + if (value < int_hex_split) begin + $write(" %d", value); + end else begin + 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 + 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; + + // }: ignore + 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"); + + // append key or value + end else begin + cfg_item = {cfg_item, cfg_str[i]}; + end + end + end + +endmodule From 4e601033e8af19c2ce6d7591c4ef1c084c4e0697 Mon Sep 17 00:00:00 2001 From: Thomas Benz Date: Tue, 26 Sep 2023 10:44:00 +0200 Subject: [PATCH 3/5] Integrate printer --- cheshire.mk | 1 - hw/cheshire_pkg.sv | 128 +++++++++++++++++++++++++ target/sim/src/cfg_format.c | 121 ----------------------- target/sim/src/fixture_cheshire_soc.sv | 28 +++++- target/sim/src/tb_cfg_printer.sv | 38 +++++--- target/sim/src/tb_cheshire_soc.sv | 9 +- target/sim/vsim/start.cheshire_soc.tcl | 1 + 7 files changed, 188 insertions(+), 138 deletions(-) delete mode 100644 target/sim/src/cfg_format.c diff --git a/cheshire.mk b/cheshire.mk index 17894074..8dbbe10f 100644 --- a/cheshire.mk +++ b/cheshire.mk @@ -135,7 +135,6 @@ CHS_BOOTROM_ALL += $(CHS_ROOT)/hw/bootrom/cheshire_bootrom.sv $(CHS_ROOT)/hw/boo $(CHS_ROOT)/target/sim/vsim/compile.cheshire_soc.tcl: Bender.yml $(BENDER) script vsim -t sim -t cv64a6_imafdcsclic_sv39 -t test -t cva6 -t rtl --vlog-arg="$(VLOG_ARGS)" > $@ echo 'vlog "$(CURDIR)/$(CHS_ROOT)/target/sim/src/elfloader.cpp" -ccflags "-std=c++11"' >> $@ - echo 'vlog "$(CURDIR)/$(CHS_ROOT)/target/sim/src/cfg_format.c"' >> $@ $(CHS_ROOT)/target/sim/models: mkdir -p $@ 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/sim/src/cfg_format.c b/target/sim/src/cfg_format.c deleted file mode 100644 index 31e95e7c..00000000 --- a/target/sim/src/cfg_format.c +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2022 ETH Zurich and University of Bologna. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 -// -// With a fuction copies from stackoverflow -// (https://stackoverflow.com/questions/8044081/how-to-do-regex-string-replacements-in-pure-c) -// -// Thomas Benz - - -#include -#include -#include -#include - -// replacement patterns -const char *NEWLINE_MATCH = ", ([A-Z])"; -const char *NEWLINE_REPLACE = "\n \1"; - -const char *COLON_MATCH = ":"; -const char *COLON_REPLACE = ": "; - - -int regex_replace(char **str, const char *pattern, const char *replace) { - // https://stackoverflow.com/questions/8044081/how-to-do-regex-string-replacements-in-pure-c - // replaces regex in pattern with replacement observing capture groups - // *str MUST be free-able, i.e. obtained by strdup, malloc, ... - // back references are indicated by char codes 1-31 and none of those chars can be used in the - // replacement string such as a tab. will not search for matches within replaced text, this - // will begin searching for the next match after the end of prev match - // returns: - // -1 if pattern cannot be compiled - // -2 if count of back references and capture groups don't match - // otherwise returns number of matches that were found and replaced - // - regex_t reg; - unsigned int replacements = 0; - // if regex can't commpile pattern, do nothing - if(!regcomp(®, pattern, REG_EXTENDED)) { - size_t nmatch = reg.re_nsub; - regmatch_t m[nmatch + 1]; - const char *rpl, *p; - // count back references in replace - int br = 0; - p = replace; - while(1) { - while(*++p > 31); - if(*p) br++; - else break; - } // if br is not equal to nmatch, leave - if(br != nmatch) { - regfree(®); - return -2; - } - // look for matches and replace - char *new; - char *search_start = *str; - while(!regexec(®, search_start, nmatch + 1, m, REG_NOTBOL)) { - // make enough room - new = (char *)malloc(strlen(*str) + strlen(replace)); - if(!new) exit(EXIT_FAILURE); - *new = '\0'; - strncat(new, *str, search_start - *str); - p = rpl = replace; - int c; - strncat(new, search_start, m[0].rm_so); // test before pattern - for(int k=0; k 31); // skip printable char - c = *p; // back reference (e.g. \1, \2, ...) - strncat(new, rpl, p - rpl); // add head of rpl - // concat match - strncat(new, search_start + m[c].rm_so, m[c].rm_eo - m[c].rm_so); - rpl = p++; // skip back reference, next match - } - strcat(new, p ); // trailing of rpl - unsigned int new_start_offset = strlen(new); - strcat(new, search_start + m[0].rm_eo); // trailing text in *str - free(*str); - *str = (char *)malloc(strlen(new)+1); - strcpy(*str,new); - search_start = *str + new_start_offset; - free(new); - replacements++; - } - regfree(®); - // ajust size - *str = (char *)realloc(*str, strlen(*str) + 1); - return replacements; - } else { - return -1; - } -} - - -// pretty printer -extern void format_cfg(char *cfg_str, int length) { - - // cut curly brackets away - char *cgf_str_cut = cfg_str + 2; - cgf_str_cut[length-3] = "\0"; - - // function works on a copy of the string - char *tmp = (char *)malloc(length + 1 - 4); - strcpy(tmp, cgf_str_cut); - - // infer newlines and fix colons - regex_replace(&tmp, NEWLINE_MATCH, NEWLINE_REPLACE); - regex_replace(&tmp, COLON_MATCH, COLON_REPLACE); - - // format numbers - regex_t find_num_pat; - size_t num_matches = 256; - regmatch_t match_array[256]; - regcomp(&find_num_pat, "[0-9]+", REG_EXTENDED); - regexec(&find_num_pat, tmp, num_matches, match_array, 0); - - // printf("%d", match_array[0].rm_eo); - - // print to questa terminal - printf("\nCheshire Configuration\n----------------------\n\n %s\n", tmp); -} diff --git a/target/sim/src/fixture_cheshire_soc.sv b/target/sim/src/fixture_cheshire_soc.sv index 96bdfd7f..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,6 +20,30 @@ 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) diff --git a/target/sim/src/tb_cfg_printer.sv b/target/sim/src/tb_cfg_printer.sv index 54330db3..c5327ccd 100644 --- a/target/sim/src/tb_cfg_printer.sv +++ b/target/sim/src/tb_cfg_printer.sv @@ -19,7 +19,7 @@ module tb_cfg_printer #( static int unsigned param_name_width = 24; // get the string - static string cfg_str = $sformatf("%p", DutCfg); + static string cfg_str = $sformatf("%p", DutCfg); static integer cfg_len = cfg_str.len(); // temp variables @@ -28,44 +28,51 @@ module tb_cfg_printer #( static bit unnamed_array = 0; static bit was_closed = 0; static int unsigned unnamed_idx = 0; + static string padding = ""; - // terminate config string + // overwrite closing bracket to terminate config string cfg_str.putc(cfg_len-1, ","); - // parse each character individually + // 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 + // colon denotes the separation between named value and value + // Goal: print the padded key of a named value if (cfg_str[i] == ":") begin - // we print a key - automatic string padding = ""; - // decide if we are in array mode + // 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 = ""; - // differentiate between unnamed and named arrays + // we found a named key: we thus don't have an array of unnamed values if (array_active) begin unnamed_array = 0; end - // comma + // 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 + // 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, " "}; @@ -73,10 +80,12 @@ module tb_cfg_printer #( $write(" %s:%s", unnamed_idx_str, padding); end - // we print a value + // 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 @@ -86,6 +95,9 @@ module tb_cfg_printer #( $write("%s", hex_val[h]); end end + + // reset accumulator and padding + padding = ""; cfg_item = ""; // array bookkeeping @@ -106,7 +118,7 @@ module tb_cfg_printer #( end else if (cfg_str[i] == "'") begin continue; - // }: ignore + // }: close the bracket end else if (cfg_str[i] == "}") begin was_closed = 1; @@ -117,7 +129,7 @@ module tb_cfg_printer #( unnamed_idx = 0; $write("\n"); - // append key or value + // default: append char to accumulator end else begin cfg_item = {cfg_item, cfg_str[i]}; end 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} " } From 20ef96d7710e1dbac955e4d2623cdf51560b23ba Mon Sep 17 00:00:00 2001 From: Thomas Benz Date: Tue, 26 Sep 2023 10:46:07 +0200 Subject: [PATCH 4/5] Update doc --- docs/tg/sim.md | 2 ++ 1 file changed, 2 insertions(+) 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 From e13749b240aa66f9d672afa43e2db3d8d99151c2 Mon Sep 17 00:00:00 2001 From: Thomas Benz Date: Tue, 26 Sep 2023 18:08:31 +0200 Subject: [PATCH 5/5] Add pickle target --- cheshire.mk | 12 ++++++++++++ target/pickle/.gitignore | 2 ++ target/pickle/get_config.py | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+) create mode 100644 target/pickle/.gitignore create mode 100644 target/pickle/get_config.py 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/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'))