mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-22 04:47:25 -04:00
[dv] Enable use of ibex configs in DV
This commit is contained in:
parent
00b46d9abe
commit
10bc77ddcc
4 changed files with 292 additions and 69 deletions
|
@ -65,22 +65,14 @@ PMP_REGIONS := 16
|
|||
# PMP Granularity
|
||||
PMP_GRANULARITY := 0
|
||||
|
||||
IBEX_CONFIG := experimental-maxperf-pmp-bm
|
||||
|
||||
# TODO(udinator) - might need options for SAIL/Whisper/Spike
|
||||
ifeq (${ISS},ovpsim)
|
||||
ISS_OPTS += --override riscvOVPsim/cpu/PMP_registers=${PMP_REGIONS}
|
||||
ISS_OPTS += --override riscvOVPsim/cpu/PMP_grain=${PMP_GRANULARITY}
|
||||
endif
|
||||
|
||||
# Check which simulator is being used and add correct compile options
|
||||
ifeq (${SIMULATOR},vcs)
|
||||
COMPILE_OPTS += -pvalue+core_ibex_tb_top.dut.PMPNumRegions=${PMP_REGIONS}
|
||||
COMPILE_OPTS += -pvalue+core_ibex_tb_top.dut.PMPGranularity=${PMP_GRANULARITY}
|
||||
else ifeq (&{SIMULATOR},riviera)
|
||||
SIM_OPTS +=-g/core_ibex_tb_top/dut/PMPNumRegions=${PMP_REGIONS}
|
||||
SIM_OPTS +=-g/core_ibex_tb_top/dut/PMPGranularity=${PMP_GRANULARITY}
|
||||
# TODO(udinator) - support dsim
|
||||
endif
|
||||
|
||||
# This expands to '@' if VERBOSE is 0 or not set, and to the empty
|
||||
# string otherwise. Prefix commands with it in order that they only
|
||||
# get printed when VERBOSE.
|
||||
|
@ -132,6 +124,31 @@ gen-dirs := $(OUT) $(OUT-SEED) $(metadata) $(OUT)/rtl_sim
|
|||
$(gen-dirs): %:
|
||||
mkdir -p $@
|
||||
|
||||
# sim-cfg-mk is a makefile fragment that sets-up anything simulator specific, it
|
||||
# is generated by sim_makefrag_gen.py
|
||||
sim-cfg-mk = $(OUT)/.sim-cfg.mk
|
||||
|
||||
# The include of $(sim-cfg-mk) below tells Make that it should ensure the file
|
||||
# exists. This rule tells Make how to build it. We also want to ensure it's
|
||||
# built on every run. Declaring the rule to be .PHONY doesn't work because it
|
||||
# causes Make to no longer think the rule actually generates the file. If you
|
||||
# do that, the file gets re-built, but Make doesn't read the new contents. So
|
||||
# instead we depend on FORCE (a phony target). This ensures a rebuild, but also
|
||||
# causes an infinite recursion: when we re-read this file to include the new
|
||||
# contents of $(sim-cfg-mk), we run the rule again. To avoid that, we check for
|
||||
# MAKE_RESTARTS, which is defined on re-runs. Phew!
|
||||
ifndef MAKE_RESTARTS
|
||||
$(sim-cfg-mk): FORCE | $(OUT)
|
||||
@./sim_makefrag_gen.py $(SIMULATOR) $(IBEX_CONFIG) $(PRJ_DIR)/ibex $@
|
||||
endif
|
||||
|
||||
include $(sim-cfg-mk)
|
||||
|
||||
.PHONY: test-cfg
|
||||
test-cfg:
|
||||
@echo "COMPILE_OPTS" $(COMPILE_OPTS)
|
||||
@echo "SIM_OPTS" $(SIM_OPTS)
|
||||
|
||||
###############################################################################
|
||||
# Utility functions.
|
||||
#
|
||||
|
|
108
dv/uvm/core_ibex/sim_makefrag_gen.py
Executable file
108
dv/uvm/core_ibex/sim_makefrag_gen.py
Executable file
|
@ -0,0 +1,108 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright lowRISC contributors.
|
||||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import argparse
|
||||
import os.path
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
ibex_config_path = ''
|
||||
ibex_config_name = ''
|
||||
ibex_config_filename = ''
|
||||
|
||||
|
||||
class GenError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def run_ibex_config(output_type, extra_args=None):
|
||||
ibex_config_cmd = [
|
||||
ibex_config_path,
|
||||
ibex_config_name,
|
||||
'--config_filename', ibex_config_filename,
|
||||
output_type
|
||||
]
|
||||
|
||||
if extra_args:
|
||||
ibex_config_cmd += extra_args
|
||||
|
||||
result = subprocess.run(ibex_config_cmd,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
|
||||
if result.returncode != 0:
|
||||
raise GenError("Error running {0} got:\n{1}\n{2}".format(
|
||||
ibex_config_path, str(result.stdout, 'utf-8'),
|
||||
str(result.stderr, 'utf-8')))
|
||||
|
||||
return str(result.stdout, 'utf-8')
|
||||
|
||||
|
||||
def gen_vcs_makefrag():
|
||||
vcs_compile_opts = run_ibex_config('vcs_opts', [
|
||||
'--ins_hier_path', 'core_ibex_tb_top',
|
||||
'--string_define_prefix', 'IBEX_CFG_'
|
||||
])
|
||||
|
||||
return 'COMPILE_OPTS += {0}'.format(vcs_compile_opts)
|
||||
|
||||
|
||||
def gen_riviera_makefrag():
|
||||
riviera_compile_opts = run_ibex_config('riviera_compile_opts', [
|
||||
'--ins_hier_path', 'core_ibex_tb_top',
|
||||
'--string_define_prefix', 'IBEX_CFG_'
|
||||
])
|
||||
|
||||
riviera_sim_opts = run_ibex_config('riviera_sim_opts', [
|
||||
'--ins_hier_path', 'core_ibex_tb_top',
|
||||
'--string_define_prefix', 'IBEX_CFG_'
|
||||
])
|
||||
|
||||
return ('COMPILE_OPTS += {0}'
|
||||
'SIM_OPTS += {1}').format(riviera_compile_opts, riviera_sim_opts)
|
||||
|
||||
|
||||
def main():
|
||||
argparser = argparse.ArgumentParser(description=(
|
||||
'Generates a makefile fragment for use with the Ibex DV makefile that '
|
||||
'sets up sim specific variables'))
|
||||
|
||||
sim_fns = {'vcs': gen_vcs_makefrag, 'riviera': gen_riviera_makefrag}
|
||||
|
||||
argparser.add_argument('sim',
|
||||
help='Name of the simulator',
|
||||
choices=sim_fns.keys())
|
||||
|
||||
argparser.add_argument(
|
||||
'config', help='Ibex config to generate makefile fragment for')
|
||||
|
||||
argparser.add_argument('ibex_top',
|
||||
help='Path to the top of an ibex repository')
|
||||
|
||||
argparser.add_argument('makefrag_name',
|
||||
help='Filename of the makefile fragment to write')
|
||||
|
||||
args = argparser.parse_args()
|
||||
|
||||
global ibex_config_path
|
||||
global ibex_config_name
|
||||
global ibex_config_filename
|
||||
|
||||
ibex_config_path = os.path.join(args.ibex_top, 'util/ibex_config.py')
|
||||
ibex_config_name = args.config
|
||||
ibex_config_filename = os.path.join(args.ibex_top, 'ibex_configs.yaml')
|
||||
|
||||
try:
|
||||
with open(args.makefrag_name, 'w') as makefrag:
|
||||
makefrag.write(sim_fns[args.sim]())
|
||||
except GenError as e:
|
||||
print('Failure generating simulation options for', args.sim)
|
||||
print(e)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -26,42 +26,63 @@ module core_ibex_tb_top;
|
|||
// CSR access interface
|
||||
core_ibex_csr_if csr_if(.clk(clk));
|
||||
|
||||
// You cannot override string parameters in VCS via the command line so a `define is used instead
|
||||
// that can be set from the command line. If no value has been specified this gives a default.
|
||||
`ifndef IBEX_MULTIPLIER_IMPLEMENTATION
|
||||
`define IBEX_MULTIPLIER_IMPLEMENTATION fast
|
||||
`endif
|
||||
|
||||
parameter bit PMPEnable = 1'b0;
|
||||
parameter int unsigned PMPGranularity = 0;
|
||||
parameter int unsigned PMPNumRegions = 4;
|
||||
parameter bit RV32E = 1'b0;
|
||||
parameter bit RV32M = 1'b1;
|
||||
parameter bit RV32B = 1'b0;
|
||||
parameter bit BranchTargetALU = 1'b0;
|
||||
parameter bit WritebackStage = 1'b0;
|
||||
parameter MultiplierImplementation = `"`IBEX_CFG_MultiplierImplementation`";
|
||||
|
||||
ibex_core_tracing #(
|
||||
.DmHaltAddr(`BOOT_ADDR + 'h0),
|
||||
.DmExceptionAddr(`BOOT_ADDR + 'h4),
|
||||
.PMPEnable(1'b1),
|
||||
.BranchTargetALU(1'b1),
|
||||
.WritebackStage(1'b1),
|
||||
.RV32B(1'b1)
|
||||
.DmHaltAddr (`BOOT_ADDR + 'h0 ),
|
||||
.DmExceptionAddr (`BOOT_ADDR + 'h4 ),
|
||||
.PMPEnable (PMPEnable ),
|
||||
.PMPGranularity (PMPGranularity ),
|
||||
.PMPNumRegions (PMPNumRegions ),
|
||||
.RV32E (RV32E ),
|
||||
.RV32M (RV32M ),
|
||||
.RV32B (RV32B ),
|
||||
.BranchTargetALU (BranchTargetALU ),
|
||||
.WritebackStage (WritebackStage ),
|
||||
.MultiplierImplementation (MultiplierImplementation)
|
||||
) dut (
|
||||
.clk_i(clk),
|
||||
.rst_ni(rst_n),
|
||||
.test_en_i(1'b1),
|
||||
.hart_id_i(32'b0),
|
||||
.boot_addr_i(`BOOT_ADDR), // align with spike boot address
|
||||
.irq_software_i(irq_vif.irq_software),
|
||||
.irq_timer_i(irq_vif.irq_timer),
|
||||
.irq_external_i(irq_vif.irq_external),
|
||||
.irq_fast_i(irq_vif.irq_fast),
|
||||
.irq_nm_i(irq_vif.irq_nm),
|
||||
.fetch_enable_i(dut_if.fetch_enable),
|
||||
.debug_req_i(dut_if.debug_req),
|
||||
.data_req_o(data_mem_vif.request),
|
||||
.data_gnt_i(data_mem_vif.grant),
|
||||
.data_rvalid_i(data_mem_vif.rvalid),
|
||||
.data_addr_o(data_mem_vif.addr),
|
||||
.data_we_o(data_mem_vif.we),
|
||||
.data_be_o(data_mem_vif.be),
|
||||
.data_rdata_i(data_mem_vif.rdata),
|
||||
.data_wdata_o(data_mem_vif.wdata),
|
||||
.data_err_i(data_mem_vif.error),
|
||||
.instr_req_o(instr_mem_vif.request),
|
||||
.instr_gnt_i(instr_mem_vif.grant),
|
||||
.instr_rvalid_i(instr_mem_vif.rvalid),
|
||||
.instr_addr_o(instr_mem_vif.addr),
|
||||
.instr_rdata_i(instr_mem_vif.rdata),
|
||||
.instr_err_i(instr_mem_vif.error),
|
||||
.core_sleep_o(dut_if.core_sleep)
|
||||
.clk_i (clk ),
|
||||
.rst_ni (rst_n ),
|
||||
.test_en_i (1'b1 ),
|
||||
.hart_id_i (32'b0 ),
|
||||
.boot_addr_i (`BOOT_ADDR ), // align with spike boot address
|
||||
.irq_software_i (irq_vif.irq_software ),
|
||||
.irq_timer_i (irq_vif.irq_timer ),
|
||||
.irq_external_i (irq_vif.irq_external ),
|
||||
.irq_fast_i (irq_vif.irq_fast ),
|
||||
.irq_nm_i (irq_vif.irq_nm ),
|
||||
.fetch_enable_i (dut_if.fetch_enable ),
|
||||
.debug_req_i (dut_if.debug_req ),
|
||||
.data_req_o (data_mem_vif.request ),
|
||||
.data_gnt_i (data_mem_vif.grant ),
|
||||
.data_rvalid_i (data_mem_vif.rvalid ),
|
||||
.data_addr_o (data_mem_vif.addr ),
|
||||
.data_we_o (data_mem_vif.we ),
|
||||
.data_be_o (data_mem_vif.be ),
|
||||
.data_rdata_i (data_mem_vif.rdata ),
|
||||
.data_wdata_o (data_mem_vif.wdata ),
|
||||
.data_err_i (data_mem_vif.error ),
|
||||
.instr_req_o (instr_mem_vif.request),
|
||||
.instr_gnt_i (instr_mem_vif.grant ),
|
||||
.instr_rvalid_i (instr_mem_vif.rvalid ),
|
||||
.instr_addr_o (instr_mem_vif.addr ),
|
||||
.instr_rdata_i (instr_mem_vif.rdata ),
|
||||
.instr_err_i (instr_mem_vif.error ),
|
||||
.core_sleep_o (dut_if.core_sleep )
|
||||
);
|
||||
|
||||
// Data load/store vif connection
|
||||
|
|
|
@ -127,19 +127,82 @@ def get_config_dicts(config_file):
|
|||
return config_yaml
|
||||
|
||||
|
||||
def _config_dict_to_fusesoc_opts(config_dict):
|
||||
fusesoc_cmd = []
|
||||
for parameter, value in config_dict.items():
|
||||
if isinstance(value, bool):
|
||||
# For fusesoc boolean parameter are set to true if given on the
|
||||
# command line otherwise false, it doesn't support an explicit
|
||||
# --param=True style
|
||||
if value:
|
||||
fusesoc_cmd.append(shlex.quote('--' + parameter))
|
||||
else:
|
||||
fusesoc_cmd.append(shlex.quote('--' + parameter + '=' + str(value)))
|
||||
class FusesocOpts:
|
||||
def setup_args(self, arg_subparser):
|
||||
output_argparser = arg_subparser.add_parser(
|
||||
'fusesoc_opts', help=('Outputs options for fusesoc'))
|
||||
output_argparser.set_defaults(output_fn=self.output)
|
||||
|
||||
return ' '.join(fusesoc_cmd)
|
||||
def output(self, config_dict, args):
|
||||
fusesoc_cmd = []
|
||||
for parameter, value in config_dict.items():
|
||||
if isinstance(value, bool):
|
||||
# For fusesoc boolean parameters are set to true if given on the
|
||||
# command line otherwise false. It doesn't support an explicit
|
||||
# --param=True style
|
||||
if value:
|
||||
fusesoc_cmd.append(shlex.quote('--' + parameter))
|
||||
else:
|
||||
fusesoc_cmd.append(
|
||||
shlex.quote('--' + parameter + '=' + str(value)))
|
||||
|
||||
return ' '.join(fusesoc_cmd)
|
||||
|
||||
|
||||
class SimOpts:
|
||||
def __init__(self, cmd_name, description, param_set_fn, define_set_fn,
|
||||
hierarchy_sep):
|
||||
self.cmd_name = cmd_name
|
||||
self.description = description
|
||||
self.param_set_fn = param_set_fn
|
||||
self.define_set_fn = define_set_fn
|
||||
self.hierarchy_sep = hierarchy_sep
|
||||
|
||||
def setup_args(self, arg_subparser):
|
||||
output_argparser = arg_subparser.add_parser(
|
||||
self.cmd_name,
|
||||
help=('Outputs options for {0}'.format(self.description)))
|
||||
|
||||
output_argparser.add_argument(
|
||||
'--ins_hier_path',
|
||||
help=('Hierarchical path to the instance to set '
|
||||
'configuration parameters on'),
|
||||
default='')
|
||||
output_argparser.add_argument(
|
||||
'--string_define_prefix',
|
||||
help=('Prefix to add to defines that are used to '
|
||||
'pass string parameters'),
|
||||
default='')
|
||||
output_argparser.set_defaults(output_fn=self.output)
|
||||
|
||||
def output(self, config_dict, args):
|
||||
if (args.ins_hier_path != ''):
|
||||
ins_hier_path = args.ins_hier_path + self.hierarchy_sep
|
||||
else:
|
||||
ins_hier_path = ''
|
||||
|
||||
sim_opts = []
|
||||
|
||||
for parameter, value in config_dict.items():
|
||||
if isinstance(value, str):
|
||||
parameter_define = args.string_define_prefix + parameter
|
||||
define_set_str = self.define_set_fn(parameter_define, value)
|
||||
|
||||
if define_set_str:
|
||||
sim_opts.append(shlex.quote(define_set_str))
|
||||
else:
|
||||
if isinstance(value, bool):
|
||||
val_str = '1' if value else '0'
|
||||
else:
|
||||
val_str = str(value)
|
||||
|
||||
param_set_str = self.param_set_fn(ins_hier_path + parameter,
|
||||
val_str)
|
||||
|
||||
if param_set_str:
|
||||
sim_opts.append(shlex.quote(param_set_str))
|
||||
|
||||
return ' '.join(sim_opts)
|
||||
|
||||
|
||||
def get_config_file_location():
|
||||
|
@ -152,28 +215,42 @@ def get_config_file_location():
|
|||
|
||||
|
||||
def main():
|
||||
config_outputs = {'fusesoc_opts': _config_dict_to_fusesoc_opts}
|
||||
outputters = [
|
||||
FusesocOpts(),
|
||||
SimOpts('vcs_opts', 'VCS compile',
|
||||
lambda p, v: '-pvalue+' + p + '=' + v,
|
||||
lambda d, v: '+define+' + d + '=' + v, '.'),
|
||||
SimOpts('riviera_sim_opts', 'Riviera simulate',
|
||||
lambda p, v: '-g/' + p + '=' + v,
|
||||
lambda d, v: None, '/'),
|
||||
SimOpts('riviera_compile_opts', 'Riviera compile',
|
||||
lambda p, v: None,
|
||||
lambda d, v: '+define+' + d + '=' + v, '/')
|
||||
]
|
||||
|
||||
argparser = argparse.ArgumentParser(description=(
|
||||
'Outputs Ibex configuration '
|
||||
'parameters for a named config in a number of formats. If not '
|
||||
'specified on the command line the config will be read from {0}. This '
|
||||
'default can be overridden by setting the IBEX_CONFIG_FILE environment '
|
||||
'variable').format(get_config_file_location()))
|
||||
'Outputs Ibex configuration parameters for a named config in a number '
|
||||
'of formats. If not specified on the command line the config will be '
|
||||
'read from {0}. This default can be overridden by setting the '
|
||||
'IBEX_CONFIG_FILE environment variable. Some output types support '
|
||||
'arguments to see help for them pass a config_name and an output type '
|
||||
'followed by --help').format(get_config_file_location()))
|
||||
|
||||
argparser.add_argument('config_name',
|
||||
help=('The name of the Ibex '
|
||||
'configuration to output'))
|
||||
|
||||
argparser.add_argument('output_type',
|
||||
help=('Format to output the '
|
||||
'configuration parameters in'),
|
||||
choices=config_outputs.keys())
|
||||
|
||||
argparser.add_argument('--config_filename',
|
||||
help='Config file to read',
|
||||
default=get_config_file_location())
|
||||
|
||||
arg_subparser = argparser.add_subparsers(
|
||||
title='output type',
|
||||
help='Format to output the configuration parameters in')
|
||||
|
||||
for outputter in outputters:
|
||||
outputter.setup_args(arg_subparser)
|
||||
|
||||
args = argparser.parse_args()
|
||||
|
||||
try:
|
||||
|
@ -189,9 +266,9 @@ def main():
|
|||
|
||||
sys.exit(1)
|
||||
|
||||
print(config_outputs[args.output_type](config_dicts[args.config_name]))
|
||||
print(args.output_fn(config_dicts[args.config_name], args))
|
||||
except ConfigException as ce:
|
||||
print('ERROR: failure to read configuration from',
|
||||
print('ERROR: failure to process configuration from',
|
||||
args.config_filename,
|
||||
ce,
|
||||
file=sys.stderr)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue