Create a clean code generation script for littleRISCV called ri5cly-manage.py

This commit is contained in:
Markus Wegmann 2016-12-29 21:41:59 +01:00
parent 7c99161125
commit 00a2c3a8fb
7 changed files with 222 additions and 15 deletions

2
.gitignore vendored
View file

@ -1,3 +1 @@
*.swp

View file

@ -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;

View file

@ -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 ),

View file

@ -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
/////////////////////////////////////////////////////////
// ____ _____ ____ ___ ____ _____ _____ ____ ____ //

View file

@ -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

2
scripts/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
build/
.idea/

195
scripts/ri5cly-manage.py Normal file
View file

@ -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()