[dv] Enable use of ibex configs in DV

This commit is contained in:
Greg Chadwick 2020-05-14 09:41:39 +01:00
parent 00b46d9abe
commit 10bc77ddcc
4 changed files with 292 additions and 69 deletions

View file

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

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

View file

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

View file

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