diff --git a/.gitignore b/.gitignore index 0314eef2..1377554e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1 @@ *.swp - - diff --git a/decoder.sv b/decoder.sv index 8e386b73..45e818fc 100644 --- a/decoder.sv +++ b/decoder.sv @@ -602,7 +602,6 @@ module riscv_decoder {6'b00_0000, 3'b101}: alu_operator_o = ALU_SRL; // Shift Right Logical {6'b10_0000, 3'b101}: alu_operator_o = ALU_SRA; // Shift Right Arithmetic - // CONFIG_REGION: MUL_SUPPORT `ifdef MUL_SUPPORT // supported RV32M instructions @@ -1096,6 +1095,9 @@ module riscv_decoder end + // CONFIG_REGION: HWL_SUPPORT + `ifdef HWL_SUPPORT + /////////////////////////////////////////////// // _ ___ ___ ___ ___ ____ // // | | | \ \ / / | / _ \ / _ \| _ \ // @@ -1105,8 +1107,7 @@ module riscv_decoder // // /////////////////////////////////////////////// - // CONFIG_REGION: HWL_SUPPORT - `ifdef HWL_SUPPORT + OPCODE_HWLOOP: begin hwloop_target_mux_sel_o = 1'b0; diff --git a/ex_stage.sv b/ex_stage.sv index 5a45d8ac..383f0021 100644 --- a/ex_stage.sv +++ b/ex_stage.sv @@ -231,6 +231,9 @@ module riscv_ex_stage `endif // SIMPLE_ALU + // CONFIG_REGION: MUL_SUPPORT + `ifdef MUL_SUPPORT + //////////////////////////////////////////////////////////////// // __ __ _ _ _ _____ ___ ____ _ ___ _____ ____ // // | \/ | | | | | |_ _|_ _| _ \| | |_ _| ____| _ \ // @@ -240,8 +243,7 @@ module riscv_ex_stage // // //////////////////////////////////////////////////////////////// - // CONFIG_REGION: MUL_SUPPORT - `ifdef MUL_SUPPORT + riscv_mult mult_i ( .clk ( clk ), diff --git a/id_stage.sv b/id_stage.sv index d7d2ae97..6e258fdf 100644 --- a/id_stage.sv +++ b/id_stage.sv @@ -82,7 +82,6 @@ module riscv_id_stage input logic [31:0] instr_rdata_i, // comes from pipeline of IF stage output logic instr_req_o, - // Jumps and branches output logic branch_in_ex_o, input logic branch_decision_i, @@ -126,7 +125,7 @@ module riscv_id_stage output logic [ 4:0] bmask_b_ex_o, `endif // BIT_SUPPORT - // CONFIG_REGION: VEC_SUPPORT + // CONFIG_REGION: VEC_SUPPORT `ifdef VEC_SUPPORT output logic [ 1:0] imm_vec_ext_ex_o, output logic [ 1:0] alu_vec_mode_ex_o, @@ -141,7 +140,6 @@ module riscv_id_stage // ALU output logic [ALU_OP_WIDTH-1:0] alu_operator_ex_o, - // CONFIG_REGION: MUL_SUPPORT `ifdef MUL_SUPPORT // MUL @@ -583,6 +581,10 @@ module riscv_id_stage assign mult_en = mult_int_en | mult_dot_en; `endif // MUL_SUPPORT + + // CONFIG_REGION: HWL_SUPPORT + `ifdef HWL_SUPPORT + /////////////////////////////////////////////// // _ ___ ___ ___ ___ ____ // // | | | \ \ / / | / _ \ / _ \| _ \ // @@ -592,8 +594,7 @@ module riscv_id_stage // // /////////////////////////////////////////////// - // CONFIG_REGION: HWL_SUPPORT - `ifdef HWL_SUPPORT + // hwloop register id assign hwloop_regid_int = instr[7]; // rd contains hwloop register id @@ -914,7 +915,7 @@ module riscv_id_stage default: mult_imm_id = '0; endcase end - `endif // MUL_SUPPORT + `endif // MUL_SUPPORT ///////////////////////////////////////////////////////// // ____ _____ ____ ___ ____ _____ _____ ____ ____ // diff --git a/include/riscv_config.sv b/include/riscv_config.sv index fdc94d56..b312f20e 100644 --- a/include/riscv_config.sv +++ b/include/riscv_config.sv @@ -32,7 +32,15 @@ `endif -// littleRISCV configuration. Decomment to enable. +// littleRISCV configuration. + +// Decomment to enable. + +// The format should be strictly followed so the ri5cly-manage tool can parse the configuration +// A CONFIG section declares a config definition, a CONFIG_REGION enables the tool to remove disabled code +// for export. See the ri5cly-manage.py tool help and source code in the /scripts folder for more information. + + // CONFIG: MUL_SUPPORT // will enable RISCV32M support for multiplication, division, MAC operations. Uses a lot of multiplications @@ -73,6 +81,7 @@ // Dependent definitions +// CONFIG: THREE_PORT_REG_FILE // enables 3r2w reg file (rather than 2r1w) //`define THREE_PORT_REG_FILE @@ -96,7 +105,6 @@ // will reduce the register file to 16 words `define RV32E - `endif `endif `endif diff --git a/scripts/.gitignore b/scripts/.gitignore new file mode 100644 index 00000000..a83bb874 --- /dev/null +++ b/scripts/.gitignore @@ -0,0 +1,2 @@ +build/ +.idea/ diff --git a/scripts/ri5cly-manage.py b/scripts/ri5cly-manage.py new file mode 100644 index 00000000..e0fd4678 --- /dev/null +++ b/scripts/ri5cly-manage.py @@ -0,0 +1,195 @@ +#!/bin/python3 + +import os +import shutil +import argparse + +import re + + + +def main(): + littleRISCV_path = os.path.abspath(os.path.dirname(os.path.realpath(__file__)) + "/..") # Path to littleRISCV folder + print(littleRISCV_path) + + parser = argparse.ArgumentParser(description="Can overwrite config and export clean version of littleRISCV") + parser.add_argument('-i', dest="new_riscv_config", metavar='.../new_riscv_config.sv', + help='path to a new config file to overwrite littleRISCV config') + parser.add_argument('-o', dest='build_folder_path', metavar='.../build_folder_path', + help='path to a folder to export clean version of littleRISCV without preprocessor switches') + parser.add_argument('-z', dest='zip', action='store_true', + help='zip the export into a tar.gz') + args = parser.parse_args() + + action_taken = False + + if args.new_riscv_config is not None: + overwriteConfig(args["new_riscv_config.sv"], littleRISCV_path) + action_taken = True + + if args.build_folder_path is not None: + exportCleanVersion(args.build_folder_path, littleRISCV_path, zip=args.zip) + action_taken = True + + if action_taken == False: + print("No action taken. Please see the help below for more information:") + parser.print_help() + + + + + +def overwriteConfig(new_config_path, littleRISCV_path): + print("Overwriting current config (include/riscv_config.sv) with new one.") + shutil.move(os.path.abspath(littleRISCV_path + "/include/riscv_config.sv"), os.path.abspath(littleRISCV_path + "/include/riscv_config.sv.bak")) # Backup + shutil.copy(os.path.abspath(new_config_path), os.path.abspath(littleRISCV_path + "/include/riscv_config.sv")) # Copy new config to littleRISCV + + +def parseConfig(littleRISCV_path): + print("Trying to parse configuration.") + definitions = [] + config = os.path.abspath(littleRISCV_path + "/include/riscv_config.sv") + + with open(config, encoding="utf8") as f: + nesting_counter = 0 # If we enter a not-enabled section, keep track when we leave the section again + + content = f.readlines() + while len(content) > 0: + line = content.pop(0) + + config_pattern = re.compile("^//.*CONFIG:\s(\w*)$") # Test for config declaration + m = config_pattern.match(line) + if m is not None and nesting_counter == 0: + content.pop(0) # Pop description + line = content.pop(0) + + config_value_pattern = re.compile("^`define\s(\w*)$") # Check if config enabled and extract name + m = config_value_pattern.match(line) + if m is not None: + definitions.append(m.group(1)) + else: + ifdef_pattern = re.compile("^`ifdef\s(\w*)$") # Check if we have a dependant config + m = ifdef_pattern.match(line) + if m is not None: + if m.group(1) in definitions: + pass + else: + nesting_counter += 1 + + ifndef_pattern = re.compile("^`ifndef\s(\w*)$") # Check if we have a dependant config + m = ifndef_pattern.match(line) + if m is not None: + if not (m.group(1) in definitions): + pass + else: + nesting_counter += 1 + + endif_pattern = re.compile("^`endif.*$") # Check if we ended a block + m = endif_pattern.match(line) + if m is not None: + nesting_counter -= 1 + if nesting_counter < 0: + nesting_counter = 0 + + print("Enabled CONFIG definitions: {}".format(definitions)) + return definitions + +def processSystemVerilog(filename, folderpath, definitions): + print("Processing: {}".format(filename)) + + content = [] + new_content = [] + + with open(os.path.abspath(folderpath+"/"+filename), encoding="utf8") as f: + content = f.readlines() + + nesting_counter = 0 # If we enter a not-enabled section, keep track when we leave the section again + is_else_true = False # at first occurence of missing declarations + + while len(content) > 0: + is_codeline = True + line = content.pop(0) + + config_pattern = re.compile("^\s*//.*CONFIG_REGION:\s(\w*)$") # Test for config region declaration + m = config_pattern.match(line) + if m is not None: + is_codeline = False + line = content.pop(0) + + ifdef_pattern = re.compile("^\s*`ifdef\s(\w*)$") # Check if we have an ifdef + m = ifdef_pattern.match(line) + if m is not None: + if m.group(1) in definitions: + if nesting_counter == 0: + is_else_true = False + else: + nesting_counter += 1 + else: + if nesting_counter == 0: + is_else_true = True + nesting_counter += 1 + + + ifndef_pattern = re.compile("^\s*`ifndef\s(\w*)$") # Check if we have an ifndef + m = ifndef_pattern.match(line) + if m is not None: + if not (m.group(1) in definitions): + if nesting_counter == 0: + is_else_true = False + else: + nesting_counter += 1 + else: + if nesting_counter == 0: + is_else_true = True + nesting_counter += 1 + + else_pattern = re.compile("^\s*`else.*$") # Check if we have an else + m = else_pattern.match(line) + if m is not None: + is_codeline = False + if nesting_counter == 1 and is_else_true: + nesting_counter -= 1 + if (not is_else_true) and nesting_counter == 0: + nesting_counter += 1 + + endif_pattern = re.compile("^\s*`endif.*$") # Check if we have an endif + m = endif_pattern.match(line) + if m is not None: + is_codeline = False + nesting_counter -= 1 + if nesting_counter < 0: + nesting_counter = 0 + + if is_codeline and nesting_counter == 0: + new_content.append(line) + + os.remove(os.path.abspath(folderpath+"/"+filename)) + + with open(os.path.abspath(folderpath+"/"+filename), 'w', encoding="utf8") as f: + f.writelines(new_content) + + +def exportCleanVersion(build_path, littleRISCV_path, zip=False): + print("Exporting clean version of littleRISCV without preprocessor switches to defined output folder.") + definitions = parseConfig(littleRISCV_path) + + shutil.rmtree(os.path.abspath(build_path), ignore_errors=True) + shutil.copytree(os.path.abspath(littleRISCV_path), os.path.abspath(build_path), ignore=shutil.ignore_patterns("*.git", "scripts", "docs")) + + + for filename in os.listdir(os.path.abspath(build_path)): + sv_p = re.compile("^.*\.sv") + m = sv_p.match(filename) + if m is not None: + processSystemVerilog(filename, build_path, definitions) + + with open(os.path.abspath(build_path+"/THIS_CORE_IS_AUTOMATICALLY_GENERATATED!!!.txt"), 'w', encoding="utf8") as f: + f.write("This core export was automatically generated by ri5cly-manage.py\n\n") + f.write("Following settings were enabled: {}".format(definitions)) + + + + + +if __name__ == "__main__": + main() \ No newline at end of file