1992 lines
80 KiB
Perl
Executable File
1992 lines
80 KiB
Perl
Executable File
#! /usr/bin/env perl
|
|
#
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
# Copyright 2019 Western Digital Corporation or its affiliates.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
#use strict;
|
|
use Data::Dumper;
|
|
use Getopt::Long;
|
|
use lib "$ENV{RV_ROOT}/tools";
|
|
use JSON;
|
|
|
|
my ($self) = $0 =~ m/.*\/(\w+)/o;
|
|
my @argv_orig = @ARGV;
|
|
|
|
|
|
# Master configuration file
|
|
#
|
|
# Configuration is perl hash
|
|
# Output are define files for various flows
|
|
# Verilog (`defines common to RTL/TB)
|
|
# Software (#defines)
|
|
# Whisper (JSON/#defines)
|
|
#
|
|
# Default values and valid ranges should be specified
|
|
# Can be overridden via the cmd line (-set=name=value-string)
|
|
#
|
|
# Format of the hash is
|
|
# name => VALUE | LIST | HASH
|
|
#
|
|
# Special name "inside" followed by list .. values must be one of provided list
|
|
# Special name "derive" followed by equation to derive
|
|
#
|
|
|
|
# Dump verilog/assembly macros in upper case
|
|
my $defines_case = "U";
|
|
|
|
# Include these macros in verilog (pattern matched)
|
|
my @verilog_vars = qw (xlen reset_vec numiregs nmi_vec protection.* icg target testbench.* dccm.* retstack core.* iccm.* btb.* bht.* icache.* pic.* regwidth memmap bus.*);
|
|
|
|
# Include these macros in assembly (pattern matched)
|
|
my @asm_vars = qw (xlen reset_vec nmi_vec target dccm.* iccm.* pic.* memmap bus.* testbench.* protection.*);
|
|
my @asm_overridable = qw (reset_vec nmi_vec) ;
|
|
|
|
# Include these macros in PD (pattern matched)
|
|
my @pd_vars = qw (physical retstack target btb.* bht.* dccm.* iccm.* icache.* pic.* reset_vec nmi_vec build_ahb_lite datawidth bus.*);
|
|
|
|
# Dump non-derived/settable vars/values for these vars in stdout :
|
|
my @dvars = qw(retstack btb bht core dccm iccm icache pic bus.* reset_vec nmi_vec memmap bus);
|
|
|
|
|
|
# Prefix all macros with
|
|
my $prefix = "RV_";
|
|
# No prefix if keyword has
|
|
my $no_prefix = 'RV|TOP|^tec|regwidth|clock_period|assert_on|^datawidth|^physical|verilator|SDVT_AHB';
|
|
|
|
my $vlog_use__wh = 1;
|
|
|
|
my %regions_used = ();
|
|
|
|
# Cmd Line options#{{{
|
|
our %sets;
|
|
our %unsets;
|
|
my $help;
|
|
my @sets = ();
|
|
my @unsets = ();
|
|
|
|
#Configurations may be changed via the -set option
|
|
#
|
|
# -set=name=value : Change the default config parameter value (lowercase)\n";
|
|
# -unset=name : Remove the default config parameter (lowercase)\n";
|
|
# : Do not prepend RV_ prefex to -set/-unset variables\n";
|
|
# : multiple -set/-unset options accepted\n\n";
|
|
#
|
|
|
|
my $helpusage = "
|
|
|
|
Main configuration database for SWERV
|
|
|
|
This script documents, and generates the {`#} define/include files for verilog/assembly/backend flows
|
|
|
|
|
|
User options:
|
|
|
|
-target = { default, default_ahb, default_pd, high_perf}
|
|
use default settings for one of the targets
|
|
|
|
-set=var=value
|
|
set arbitrary variable to a value
|
|
-unset=var
|
|
unset any definitions for var
|
|
-snapshot=name
|
|
name the configuration (only if no -target specified)
|
|
|
|
Direct options for the following parameters exist:
|
|
|
|
-ret_stack_size = {2, 3, 4, ... 8}
|
|
size of return stack
|
|
-btb_size = { 32, 48, 64, 128, 256, 512 }
|
|
size of branch target buffer
|
|
-dccm_region = { 0x0, 0x1, ... 0xf }
|
|
number of 256Mb memory region containig DCCM
|
|
-dccm_offset = hexadecimal
|
|
offset (in bytes) of DCCM witin dccm_region
|
|
dccm address will be: 256M * dccm_region + dccm_offset\", and that must be aligned
|
|
to the dccm size or the next larger power of 2 if size is not a power of 2
|
|
-dccm_size = { 4, 8, 16, 32, 48, 64, 128, 256, 512 } kB
|
|
size of DCCM
|
|
-iccm_enable = { 0, 1 }
|
|
whether or not ICCM is enabled
|
|
-icache_enable = { 0, 1 }
|
|
whether or not icache is enabled
|
|
-icache_ecc = { 0, 1 }
|
|
whether or not icache has ecc - EXPENSIVE 30% sram growth
|
|
default: icache_ecc==0 (parity)
|
|
-iccm_region = { 0x0, 0x1, ... 0xf }
|
|
number of 256Mb memory region containing ICCM
|
|
-iccm_offset = hexadecimal
|
|
offcet (in bytes) of ICCM within iccm_region
|
|
iccm address will be: \"256M * iccm_region + iccm_offset\", and that must be aligned
|
|
to the iccm size or the next larger power of 2 if size is not a power of 2
|
|
-iccm_size = { 4 , 8 , 16 , 32, 64, 128, 256, 512 } kB
|
|
size of ICCM
|
|
-icache_size = { 16, 32, 64, 128, 256 } kB
|
|
size of icache
|
|
-pic_2cycle = { 0, 1 }
|
|
whether or not 2-cycle PIC is enabled (2 cycle pic may result
|
|
in an overall smaller cycle time)
|
|
-pic_region = { 0x0, 0x1, ... 0xf }
|
|
nuber of 256Mb memory region containing PIC memory-mapped registers
|
|
-pic_offset = hexadecial
|
|
offset (in bytes) of PIC within pic_region
|
|
pic address will be: \"256M * pic_region + pic_offset\", and that must be aligned
|
|
to the pic size or the next larger power of 2 if size is not a power of 2
|
|
-pic_size = { 32, 64, 128, 256 } kB
|
|
size of PIC
|
|
-pic_total_int = { 1, 2, 3, ..., 255 }
|
|
number of interrupt sources in PIC
|
|
-ahb_lite
|
|
build with AHB-lite bus interface
|
|
default is AXI4
|
|
-fpga_optimize = { 0, 1 }
|
|
if 1, minimize clock-gating to facilitate FPGA builds
|
|
";
|
|
|
|
|
|
my $ret_stack_size;
|
|
my $btb_size;
|
|
my $bht_size;
|
|
my $dccm_region;
|
|
my $dccm_offset;
|
|
my $dccm_size;
|
|
my $iccm_enable;
|
|
my $icache_enable;
|
|
my $icache_ecc;
|
|
my $iccm_region;
|
|
my $iccm_offset;
|
|
my $iccm_size;
|
|
my $icache_size;
|
|
my $pic_2cycle;
|
|
my $pic_region;
|
|
my $pic_offset;
|
|
my $pic_size;
|
|
my $pic_total_int;
|
|
my $ahb_lite;
|
|
my $fpga_optimize;
|
|
|
|
my $top_align_iccm = 0;
|
|
|
|
my $target = "default";
|
|
my $snapshot ;
|
|
my $build_path ;
|
|
|
|
GetOptions(
|
|
"help" => \$help,
|
|
"target=s" => \$target,
|
|
"snapshot=s" => \$snapshot,
|
|
"verbose" => \$verbose,
|
|
"ret_stack_size=s" => \$ret_stack_size,
|
|
"btb_size=s" => \$btb_size,
|
|
"bht_size=s" => \$bht_size,
|
|
"dccm_enable=s" => \$dccm_enable,
|
|
"dccm_region=s" => \$dccm_region,
|
|
"dccm_offset=s" => \$dccm_offset,
|
|
"dccm_size=s" => \$dccm_size,
|
|
"iccm_enable=s" => \$iccm_enable,
|
|
"icache_enable=s" => \$icache_enable,
|
|
"icache_ecc=s" => \$icache_ecc,
|
|
"iccm_region=s" => \$iccm_region,
|
|
"iccm_offset=s" => \$iccm_offset,
|
|
"iccm_size=s" => \$iccm_size,
|
|
"pic_2cycle=s" => \$pic_2cycle,
|
|
"pic_region=s" => \$pic_region,
|
|
"pic_offset=s" => \$pic_offset,
|
|
"pic_size=s" => \$pic_size,
|
|
"pic_total_int=s" => \$pic_total_int,
|
|
"icache_size=s" => \$icache_size,
|
|
"ahb_lite" => \$ahb_lite,
|
|
"fpga_optimize" => \$fpga_optimize,
|
|
"set=s@" => \@sets,
|
|
"unset=s@" => \@unsets,
|
|
) || die("$helpusage");
|
|
|
|
if ($help) {
|
|
print "$helpusage\n";
|
|
exit;
|
|
}
|
|
|
|
if (!defined $snapshot ) {
|
|
$snapshot = $target;
|
|
}
|
|
|
|
if (!defined $ENV{BUILD_PATH}) {
|
|
$build_path = "$ENV{RV_ROOT}/configs/snapshots/$snapshot" ;
|
|
} else {
|
|
$build_path = $ENV{BUILD_PATH};
|
|
}
|
|
|
|
if (! -d "$build_path") {
|
|
system ("mkdir -p $build_path");
|
|
}
|
|
|
|
# Verilog defines file path
|
|
my $vlogfile = "$build_path/common_defines.vh";
|
|
|
|
# Assembly defines file path
|
|
my $asmfile = "$build_path/defines.h";
|
|
|
|
# PD defines file path
|
|
my $pdfile = "$build_path/pd_defines.vh";
|
|
|
|
# Whisper config file path
|
|
my $whisperfile = "$build_path/whisper.json";
|
|
|
|
# Perl defines file path
|
|
my $perlfile = "$build_path/perl_configs.pl";
|
|
|
|
my $no_secondary_alu=0;
|
|
|
|
if ($target eq "default") {
|
|
if (!defined($ret_stack_size)) { $ret_stack_size=4; }
|
|
if (!defined($btb_size)) { $btb_size=32; }
|
|
if (!defined($bht_size)) { $bht_size=128; }
|
|
if (!defined($dccm_enable)) { $dccm_enable=1; }
|
|
if (!defined($dccm_region)) { $dccm_region="0xf"; }
|
|
if (!defined($dccm_offset)) { $dccm_offset="0x40000"; } #1*256*1024
|
|
if (!defined($dccm_size)) { $dccm_size=64; }
|
|
if (!defined($dccm_num_banks)) { $dccm_num_banks=8; }
|
|
if (!defined($iccm_enable)) { $iccm_enable=0; }
|
|
if (!defined($iccm_region)) { $iccm_region="0xe"; }
|
|
if (!defined($iccm_offset)) { $iccm_offset="0xe000000"; } #0x380*256*1024
|
|
if (!defined($iccm_size)) { $iccm_size=512; }
|
|
if (!defined($iccm_num_banks)) { $iccm_num_banks=8; }
|
|
if (!defined($icache_enable)) { $icache_enable=1; }
|
|
if (!defined($icache_ecc)) { $icache_ecc=0; }
|
|
if (!defined($icache_size)) { $icache_size=16; }
|
|
if (!defined($pic_2cycle)) { $pic_2cycle=0; }
|
|
if (!defined($pic_region)) { $pic_region="0xf"; }
|
|
if (!defined($pic_offset)) { $pic_offset="0xc0000"; } # 3*256*1024
|
|
if (!defined($pic_size)) { $pic_size=32; }
|
|
if (!defined($pic_total_int)) { $pic_total_int=8; }
|
|
|
|
# default is AXI bus
|
|
}
|
|
elsif ($target eq "default_ahb") {
|
|
if (!defined($ret_stack_size)) { $ret_stack_size=4; }
|
|
if (!defined($btb_size)) { $btb_size=32; }
|
|
if (!defined($bht_size)) { $bht_size=128; }
|
|
if (!defined($dccm_enable)) { $dccm_enable=1; }
|
|
if (!defined($dccm_region)) { $dccm_region="0xf"; }
|
|
if (!defined($dccm_offset)) { $dccm_offset="0x40000"; } #1*256*1024
|
|
if (!defined($dccm_size)) { $dccm_size=64; }
|
|
if (!defined($dccm_num_banks)) { $dccm_num_banks=8; }
|
|
if (!defined($iccm_enable)) { $iccm_enable=0; }
|
|
if (!defined($iccm_region)) { $iccm_region="0xe"; }
|
|
if (!defined($iccm_offset)) { $iccm_offset="0xe000000"; } #0x380*256*1024
|
|
if (!defined($iccm_size)) { $iccm_size=512; }
|
|
if (!defined($iccm_num_banks)) { $iccm_num_banks=8; }
|
|
if (!defined($icache_enable)) { $icache_enable=1; }
|
|
if (!defined($icache_ecc)) { $icache_ecc=0; }
|
|
if (!defined($icache_size)) { $icache_size=16; }
|
|
if (!defined($pic_2cycle)) { $pic_2cycle=0; }
|
|
if (!defined($pic_region)) { $pic_region="0xf"; }
|
|
if (!defined($pic_offset)) { $pic_offset="0xc0000"; } # 3*256*1024
|
|
if (!defined($pic_size)) { $pic_size=32; }
|
|
if (!defined($pic_total_int)) { $pic_total_int=8; }
|
|
$ahb_lite = 1;
|
|
|
|
} elsif ($target eq "default_pd") {
|
|
if (!defined($ret_stack_size)) { $ret_stack_size=4; }
|
|
if (!defined($btb_size)) { $btb_size=32; }
|
|
if (!defined($bht_size)) { $bht_size=128; }
|
|
if (!defined($dccm_enable)) { $dccm_enable=1; }
|
|
if (!defined($dccm_region)) { $dccm_region="0xf"; }
|
|
if (!defined($dccm_offset)) { $dccm_offset="0x40000"; } #1*256*1024
|
|
if (!defined($dccm_size)) { $dccm_size=32; }
|
|
if (!defined($dccm_num_banks)) { $dccm_num_banks=8; }
|
|
if (!defined($iccm_enable)) { $iccm_enable=0; }
|
|
if (!defined($iccm_region)) { $iccm_region="0xe"; }
|
|
if (!defined($iccm_offset)) { $iccm_offset="0xe000000"; } #0x380*256*1024
|
|
if (!defined($iccm_size)) { $iccm_size=512; }
|
|
if (!defined($iccm_num_banks)) { $iccm_num_banks=8; }
|
|
if (!defined($icache_enable)) { $icache_enable=1; }
|
|
if (!defined($icache_ecc)) { $icache_ecc=0; }
|
|
if (!defined($icache_size)) { $icache_size=16; }
|
|
if (!defined($pic_2cycle)) { $pic_2cycle=0; }
|
|
if (!defined($pic_region)) { $pic_region="0xf"; }
|
|
if (!defined($pic_offset)) { $pic_offset="0xc0000"; } # 3*256*1024
|
|
if (!defined($pic_size)) { $pic_size=32; }
|
|
if (!defined($pic_total_int)) { $pic_total_int=8; }
|
|
|
|
} elsif ($target eq "high_perf") {
|
|
if (!defined($ret_stack_size)) { $ret_stack_size=4; }
|
|
if (!defined($btb_size)) { $btb_size=512; }
|
|
if (!defined($bht_size)) { $bht_size=2048; }
|
|
if (!defined($dccm_enable)) { $dccm_enable=1; }
|
|
if (!defined($dccm_region)) { $dccm_region="0xf"; }
|
|
if (!defined($dccm_offset)) { $dccm_offset="0x40000"; } #1*256*1024
|
|
if (!defined($dccm_size)) { $dccm_size=64; }
|
|
if (!defined($dccm_num_banks)) { $dccm_num_banks=8; }
|
|
if (!defined($iccm_enable)) { $iccm_enable=0; }
|
|
if (!defined($iccm_region)) { $iccm_region="0xe"; }
|
|
if (!defined($iccm_offset)) { $iccm_offset="0xe000000"; } #0x380*256*1024
|
|
if (!defined($iccm_size)) { $iccm_size=512; }
|
|
if (!defined($iccm_num_banks)) { $iccm_num_banks=8; }
|
|
if (!defined($icache_enable)) { $icache_enable=1; }
|
|
if (!defined($icache_ecc)) { $icache_ecc=0; }
|
|
if (!defined($icache_size)) { $icache_size=32; }
|
|
if (!defined($pic_2cycle)) { $pic_2cycle=0; }
|
|
if (!defined($pic_region)) { $pic_region="0xf"; }
|
|
if (!defined($pic_offset)) { $pic_offset="0xc0000"; } # 3*256*1024
|
|
if (!defined($pic_size)) { $pic_size=32; }
|
|
if (!defined($pic_total_int)) { $pic_total_int=8; }
|
|
|
|
} else {
|
|
die "$self: ERROR! Unsupported target \"$target\". Supported targets are: \"default, default_ahb, default_pd, high_perf\"!\n";
|
|
}
|
|
|
|
# general stuff - can't set from command line other than -set
|
|
|
|
if (!defined($lsu_stbuf_depth)) { $lsu_stbuf_depth=8; }
|
|
if (!defined($dma_buf_depth)) { $dma_buf_depth=4; }
|
|
if (!defined($lsu_num_nbload)) { $lsu_num_nbload=8; }
|
|
if (!defined($dec_instbuf_depth)) { $dec_instbuf_depth=4; }
|
|
|
|
|
|
# Configure triggers
|
|
our @triggers = (#{{{
|
|
{
|
|
"reset" => ["0x23e00000", "0x00000000", "0x00000000"],
|
|
"mask" => ["0x081818c7", "0xffffffff", "0x00000000"],
|
|
"poke_mask" => ["0x081818c7", "0xffffffff", "0x00000000"]
|
|
},
|
|
{
|
|
"reset" => ["0x23e00000", "0x00000000", "0x00000000"],
|
|
"mask" => ["0x081818c7", "0xffffffff", "0x00000000"],
|
|
"poke_mask" => ["0x081818c7", "0xffffffff", "0x00000000"]
|
|
},
|
|
{
|
|
"reset" => ["0x23e00000", "0x00000000", "0x00000000"],
|
|
"mask" => ["0x081818c7", "0xffffffff", "0x00000000"],
|
|
"poke_mask" => ["0x081818c7", "0xffffffff", "0x00000000"]
|
|
},
|
|
{
|
|
"reset" => ["0x23e00000", "0x00000000", "0x00000000"],
|
|
"mask" => ["0x081818c7", "0xffffffff", "0x00000000"],
|
|
"poke_mask" => ["0x081818c7", "0xffffffff", "0x00000000"]
|
|
},
|
|
);#}}}
|
|
|
|
|
|
# Configure CSRs
|
|
our %csr = (#{{{
|
|
"mstatus" => {
|
|
"reset" => "0x1800", # MPP bits hard wired to binrary 11.
|
|
"mask" => "0x88", # Only mpie(7) & mie(3) bits writeable
|
|
"exists" => "true",
|
|
},
|
|
"mie" => {
|
|
"reset" => "0x0",
|
|
# Only external, timer, local, and software writeable
|
|
"mask" => "0x70000888",
|
|
"exists" => "true",
|
|
},
|
|
"mip" => {
|
|
"reset" => "0x0",
|
|
# None of the bits are writeable using CSR instructions
|
|
"mask" => "0x0",
|
|
# Bits corresponding to error overflow, external, timer and stoftware
|
|
# interrupts are modifiable
|
|
"poke_mask" => "0x70000888",
|
|
"exists" => "true",
|
|
},
|
|
"mvendorid" => {
|
|
"reset" => "0x45",
|
|
"mask" => "0x0",
|
|
"exists" => "true",
|
|
},
|
|
"marchid" => {
|
|
"reset" => "0x0000000b",
|
|
"mask" => "0x0",
|
|
"exists" => "true",
|
|
},
|
|
"mimpid" => {
|
|
"reset" => "0x3",
|
|
"mask" => "0x0",
|
|
"exists" => "true",
|
|
},
|
|
"misa" => {
|
|
"reset" => "0x40001104",
|
|
"mask" => "0x0",
|
|
"exists" => "true",
|
|
},
|
|
"tselect" => {
|
|
"reset" => "0x0",
|
|
"mask" => "0x3", # Four triggers
|
|
"exists" => "true",
|
|
},
|
|
"dcsr" => {
|
|
"reset" => "0x40000003",
|
|
"mask" => "0x00008c04",
|
|
"poke_mask" => "0x00008dcc", # cause field modifiable, nmip modifiable
|
|
"exists" => "true",
|
|
},
|
|
"cycle" => {
|
|
"exists" => "false",
|
|
},
|
|
"time" => {
|
|
"exists" => "false",
|
|
},
|
|
"instret" => {
|
|
"exists" => "false",
|
|
},
|
|
"mhpmcounter3" => {
|
|
"reset" => "0x0",
|
|
"mask" => "0xffffffff",
|
|
"exists" => "true",
|
|
},
|
|
"mhpmcounter4" => {
|
|
"reset" => "0x0",
|
|
"mask" => "0xffffffff",
|
|
"exists" => "true",
|
|
},
|
|
"mhpmcounter5" => {
|
|
"reset" => "0x0",
|
|
"mask" => "0xffffffff",
|
|
"exists" => "true",
|
|
},
|
|
"mhpmcounter6" => {
|
|
"reset" => "0x0",
|
|
"mask" => "0xffffffff",
|
|
"exists" => "true",
|
|
},
|
|
"mhpmcounter3h" => {
|
|
"reset" => "0x0",
|
|
"mask" => "0xffffffff",
|
|
"exists" => "true",
|
|
},
|
|
"mhpmcounter4h" => {
|
|
"reset" => "0x0",
|
|
"mask" => "0xffffffff",
|
|
"exists" => "true",
|
|
},
|
|
"mhpmcounter5h" => {
|
|
"reset" => "0x0",
|
|
"mask" => "0xffffffff",
|
|
"exists" => "true",
|
|
},
|
|
"mhpmcounter6h" => {
|
|
"reset" => "0x0",
|
|
"mask" => "0xffffffff",
|
|
"exists" => "true",
|
|
},
|
|
"mhpmevent3" => {
|
|
"reset" => "0x0",
|
|
"mask" => "0xffffffff",
|
|
"exists" => "true",
|
|
},
|
|
"mhpmevent4" => {
|
|
"reset" => "0x0",
|
|
"mask" => "0xffffffff",
|
|
"exists" => "true",
|
|
},
|
|
"mhpmevent5" => {
|
|
"reset" => "0x0",
|
|
"mask" => "0xffffffff",
|
|
"exists" => "true",
|
|
},
|
|
"mhpmevent6" => {
|
|
"reset" => "0x0",
|
|
"mask" => "0xffffffff",
|
|
"exists" => "true",
|
|
},
|
|
# Remaining CSRs are non-standard. These are specific to SWERV
|
|
"dicawics" => {
|
|
"number" => "0x7c8",
|
|
"reset" => "0x0",
|
|
"mask" => "0x0130fffc",
|
|
"exists" => "true",
|
|
},
|
|
"dicad0" => {
|
|
"number" => "0x7c9",
|
|
"reset" => "0x0",
|
|
"mask" => "0xffffffff",
|
|
"exists" => "true",
|
|
},
|
|
"dicad1" => {
|
|
"number" => "0x7ca",
|
|
"reset" => "0x0",
|
|
"mask" => "0x3",
|
|
"exists" => "true",
|
|
},
|
|
"dicago" => {
|
|
"number" => "0x7cb",
|
|
"reset" => "0x0",
|
|
"mask" => "0x0",
|
|
"exists" => "true",
|
|
},
|
|
"mitcnt0" => {
|
|
"number" => "0x7d2",
|
|
"reset" => "0x0",
|
|
"mask" => "0xffffffff",
|
|
"exists" => "true",
|
|
},
|
|
"mitbnd0" => {
|
|
"number" => "0x7d3",
|
|
"reset" => "0xffffffff",
|
|
"mask" => "0xffffffff",
|
|
"exists" => "true",
|
|
},
|
|
"mitctl0" => {
|
|
"number" => "0x7d4",
|
|
"reset" => "0x1",
|
|
"mask" => "0x00000007",
|
|
"exists" => "true",
|
|
},
|
|
"mitcnt1" => {
|
|
"number" => "0x7d5",
|
|
"reset" => "0x0",
|
|
"mask" => "0xffffffff",
|
|
"exists" => "true",
|
|
},
|
|
"mitbnd1" => {
|
|
"number" => "0x7d6",
|
|
"reset" => "0xffffffff",
|
|
"mask" => "0xffffffff",
|
|
"exists" => "true",
|
|
},
|
|
"mitctl1" => {
|
|
"number" => "0x7d7",
|
|
"reset" => "0x1",
|
|
"mask" => "0x00000007",
|
|
"exists" => "true",
|
|
},
|
|
"mcpc" => {
|
|
"number" => "0x7c2",
|
|
"reset" => "0x0",
|
|
"mask" => "0x0",
|
|
"exists" => "true",
|
|
},
|
|
"mpmc" => {
|
|
"comment" => "Core pause: Implemented as read only.",
|
|
"number" => "0x7c6",
|
|
"reset" => "0x0",
|
|
"mask" => "0x0",
|
|
"exists" => "true",
|
|
},
|
|
"micect" => {
|
|
"number" => "0x7f0",
|
|
"reset" => "0x0",
|
|
"mask" => "0xffffffff",
|
|
"exists" => "true",
|
|
},
|
|
"miccmect" => {
|
|
"number" => "0x7f1",
|
|
"reset" => "0x0",
|
|
"mask" => "0xffffffff",
|
|
"exists" => "true",
|
|
},
|
|
"mdccmect" => {
|
|
"number" => "0x7f2",
|
|
"reset" => "0x0",
|
|
"mask" => "0xffffffff",
|
|
"exists" => "true",
|
|
},
|
|
"mcgc" => {
|
|
"number" => "0x7f8",
|
|
"reset" => "0x0",
|
|
"mask" => "0x000001ff",
|
|
"poke_mask" => "0x000001ff",
|
|
"exists" => "true",
|
|
},
|
|
"mfdc" => {
|
|
"number" => "0x7f9",
|
|
"reset" => "0x00070000",
|
|
"mask" => "0x000707ff",
|
|
"exists" => "true",
|
|
},
|
|
"dmst" => {
|
|
"comment" => "Memory synch trigger: Flush caches in debug mode.",
|
|
"number" => "0x7c4",
|
|
"reset" => "0x0",
|
|
"mask" => "0x0",
|
|
"exists" => "true",
|
|
"debug" => "true",
|
|
},
|
|
"dicawics" => {
|
|
"comment" => "Cache diagnostics.",
|
|
"number" => "0x7c8",
|
|
"reset" => "0x0",
|
|
"mask" => "0x0130fffc",
|
|
"exists" => "true",
|
|
"debug" => "true",
|
|
},
|
|
"dicad0" => {
|
|
"comment" => "Cache diagnostics.",
|
|
"number" => "0x7c9",
|
|
"reset" => "0x0",
|
|
"mask" => "0xffffffff",
|
|
"exists" => "true",
|
|
"debug" => "true",
|
|
},
|
|
"dicad1" => {
|
|
"comment" => "Cache diagnostics.",
|
|
"number" => "0x7ca",
|
|
"reset" => "0x0",
|
|
"mask" => "0x3",
|
|
"exists" => "true",
|
|
"debug" => "true",
|
|
},
|
|
"dicago" => {
|
|
"comment" => "Cache diagnostics.",
|
|
"number" => "0x7cb",
|
|
"reset" => "0x0",
|
|
"mask" => "0x0",
|
|
"exists" => "true",
|
|
"debug" => "true",
|
|
},
|
|
"meipt" => {
|
|
"comment" => "External interrupt priority threshold.",
|
|
"number" => "0xbc9",
|
|
"reset" => "0x0",
|
|
"mask" => "0xf",
|
|
"exists" => "true",
|
|
},
|
|
"meicpct" => {
|
|
"comment" => "External claim id/priority capture.",
|
|
"number" => "0xbca",
|
|
"reset" => "0x0",
|
|
"mask" => "0x0",
|
|
"exists" => "true",
|
|
},
|
|
"meicidpl" => {
|
|
"comment" => "External interrupt claim id priority level.",
|
|
"number" => "0xbcb",
|
|
"reset" => "0x0",
|
|
"mask" => "0xf",
|
|
"exists" => "true",
|
|
},
|
|
"meicurpl" => {
|
|
"comment" => "External interrupt current priority level.",
|
|
"number" => "0xbcc",
|
|
"reset" => "0x0",
|
|
"mask" => "0xf",
|
|
"exists" => "true",
|
|
},
|
|
|
|
);#}}}
|
|
|
|
|
|
foreach my $i (0 .. 3) {
|
|
$csr{"pmpcfg$i"} = { "exists" => "false" };
|
|
}
|
|
|
|
foreach my $i (0 .. 15) {
|
|
$csr{"pmpaddr$i"} = { "exists" => "false" };
|
|
}
|
|
|
|
|
|
|
|
# }}}
|
|
# Main config hash, with default values
|
|
#
|
|
# Hash can be hierarchical with arbitrary levels
|
|
# Hexadecimal values are prefixed with 0x
|
|
#
|
|
# For verilog, if bit width is expected, add to %width hash below
|
|
our %config = (#{{{
|
|
"harts" => "1",
|
|
"xlen" => "32",
|
|
"numiregs" => "32",
|
|
"regwidth" => "32",
|
|
"reset_vec" => "0x80000000",
|
|
"nmi_vec" => "0x11110000",
|
|
"physical" => "1",
|
|
"num_mmode_perf_regs" => "4", # Whisper only
|
|
"max_mmode_perf_event" => "50", # Whisper only: performance counters event ids will be clamped to this
|
|
"target" => $target,
|
|
"tec_rv_icg" => "clockhdr",
|
|
"verilator" => "$verilator",
|
|
|
|
"retstack" => {
|
|
"ret_stack_size" => "$ret_stack_size",
|
|
},
|
|
|
|
"btb" => {
|
|
"btb_size" => "$btb_size",
|
|
"btb_index1_hi" => "derived",
|
|
"btb_index1_lo" => "4",
|
|
"btb_index2_hi" => "derived",
|
|
"btb_index2_lo" => "derived",
|
|
"btb_index3_hi" => "derived",
|
|
"btb_index3_lo" => "derived",
|
|
"btb_addr_hi" => "derived",
|
|
"btb_array_depth" => "derived",
|
|
"btb_addr_lo" => "4",
|
|
"btb_btag_size" => "derived",
|
|
},
|
|
"bht" => {
|
|
"bht_size" => "$bht_size",
|
|
"bht_addr_hi" => "derived",
|
|
"bht_addr_lo" => "4",
|
|
"bht_array_depth" => "derived",
|
|
"bht_ghr_size" => "derived",
|
|
"bht_ghr_range" => "derived",
|
|
"bht_ghr_pad" => "derived",
|
|
"bht_ghr_pad2" => "derived",
|
|
"bht_hash_string" => "derived",
|
|
|
|
},
|
|
|
|
"core" => {
|
|
"dec_instbuf_depth" => "$dec_instbuf_depth",
|
|
"lsu_stbuf_depth" => "$lsu_stbuf_depth",
|
|
"dma_buf_depth" => "$dma_buf_depth",
|
|
"lsu_num_nbload" => "$lsu_num_nbload",
|
|
"no_secondary_alu" => "$no_secondary_alu",
|
|
"fpga_optimize" => "$fpga_optimize"
|
|
},
|
|
|
|
"dccm" => {
|
|
"dccm_enable" => "$dccm_enable", # Comment this out if no DCCM
|
|
"dccm_region" => "$dccm_region", # 256M region number
|
|
"dccm_offset" => "$dccm_offset", # 256K offset number
|
|
"dccm_size" => "$dccm_size", # Size in Kbytes
|
|
"dccm_num_banks" => "$dccm_num_banks",
|
|
"dccm_sadr" => 'derived',
|
|
"dccm_eadr" => 'derived',
|
|
"dccm_bits" => 'derived',
|
|
"dccm_bank_bits" => 'derived',
|
|
"dccm_data_width" => 'derived',
|
|
"dccm_fdata_width" => 'derived',
|
|
"dccm_byte_width" => 'derived',
|
|
"dccm_width_bits" => 'derived',
|
|
"dccm_index_bits" => 'derived',
|
|
"dccm_ecc_width" => 'derived',
|
|
"lsu_sb_bits" => 'derived',
|
|
"dccm_data_cell" => 'derived',
|
|
"dccm_rows" => 'derived',
|
|
"dccm_reserved" => 'derived', # reserve dccm space for SW/stack - no random r/w
|
|
},
|
|
|
|
|
|
"iccm" => {
|
|
"iccm_enable" => "$iccm_enable", # Comment this out if no ICCM
|
|
"iccm_region" => "$iccm_region", # 256M region number
|
|
"iccm_offset" => "$iccm_offset", # 256K offset number
|
|
"iccm_size" => "$iccm_size", # Size in Kbytes
|
|
"iccm_num_banks" => "$iccm_num_banks",
|
|
"iccm_bank_bits" => 'derived',
|
|
"iccm_index_bits" => 'derived',
|
|
"iccm_rows" => 'derived',
|
|
"iccm_data_cell" => 'derived',
|
|
"iccm_sadr" => 'derived',
|
|
"iccm_eadr" => 'derived',
|
|
"iccm_reserved" => 'derived', # reserve iccm space for SW/handlers - no random r/w
|
|
},
|
|
"icache" => {
|
|
"icache_enable" => "$icache_enable",
|
|
"icache_size" => "$icache_size",
|
|
"icache_data_cell" => 'derived',
|
|
"icache_tag_cell" => 'derived',
|
|
"icache_taddr_high" => 'derived',
|
|
"icache_tag_high" => 'derived',
|
|
"icache_tag_depth" => 'derived',
|
|
"icache_ic_depth" => 'derived',
|
|
"icache_ic_rows" => 'derived',
|
|
"icache_ic_index" => 'derived',
|
|
"icache_tag_low" => '6',
|
|
"icache_ecc" => "$icache_ecc",
|
|
},
|
|
"pic" => {
|
|
"pic_2cycle" => "$pic_2cycle", # two cycle PIC for timing reasons
|
|
"pic_region" => "$pic_region", # 256M region number
|
|
"pic_offset" => "$pic_offset", # 256K offset number
|
|
"pic_size" => "$pic_size", # Size in Kbytes
|
|
"pic_base_addr" => 'derived', # base_addr = pic_region + offset
|
|
"pic_total_int_plus1" => 'derived', # pic_total_int + 1
|
|
"pic_total_int" => "$pic_total_int",# number of interrupt pins (Smax)
|
|
"pic_int_words" => 'derived', # number of 32 bit words for packed registers (Xmax)
|
|
"pic_bits" => 'derived', # of bits needs to address the PICM
|
|
"pic_meipl_offset" => '0x0000', # Offset of meipl relative to pic_base_addr
|
|
"pic_meip_offset" => '0x1000', # Offset of meip relative to pic_base_addr
|
|
"pic_meie_offset" => '0x2000', # Offset of meie relative to pic_base_addr
|
|
"pic_mpiccfg_offset" => '0x3000', # Offset of mpiccfg relative to pic_base_addr
|
|
"pic_meipt_offset" => '0x3004', # Offset of meipt relative to pic_base_addr -- deprecated
|
|
"pic_meigwctrl_offset" => '0x4000', # gateway control regs relative to pic_base_addr
|
|
"pic_meigwclr_offset" => '0x5000' # gateway clear regs relative to pic_base_addr
|
|
|
|
},
|
|
"testbench" => {
|
|
"TOP" => "tb_top",
|
|
"RV_TOP" => "`TOP.rvtop",
|
|
"CPU_TOP" => "`RV_TOP.swerv",
|
|
"clock_period" => "100",
|
|
"build_ahb_lite" => "$ahb_lite", # one and only one bus build arg will ever be defined
|
|
"build_axi4" => "1",
|
|
"assert_on" => "",
|
|
"datawidth" => "64", # deprecate this !! FIXME
|
|
"ext_datawidth" => "64",
|
|
"ext_addrwidth" => "32",
|
|
"sterr_rollback" => "0",
|
|
"lderr_rollback" => "1",
|
|
"SDVT_AHB" => "1",
|
|
},
|
|
"protection" => {
|
|
"inst_access_enable0" => "0x0",
|
|
"inst_access_addr0" => "0x00000000",
|
|
"inst_access_mask0" => "0xffffffff",
|
|
"inst_access_enable1" => "0x0",
|
|
"inst_access_addr1" => "0x00000000",
|
|
"inst_access_mask1" => "0xffffffff",
|
|
"inst_access_enable2" => "0x0",
|
|
"inst_access_addr2" => "0x00000000",
|
|
"inst_access_mask2" => "0xffffffff",
|
|
"inst_access_enable3" => "0x0",
|
|
"inst_access_addr3" => "0x00000000",
|
|
"inst_access_mask3" => "0xffffffff",
|
|
"inst_access_enable4" => "0x0",
|
|
"inst_access_addr4" => "0x00000000",
|
|
"inst_access_mask4" => "0xffffffff",
|
|
"inst_access_enable5" => "0x0",
|
|
"inst_access_addr5" => "0x00000000",
|
|
"inst_access_mask5" => "0xffffffff",
|
|
"inst_access_enable6" => "0x0",
|
|
"inst_access_addr6" => "0x00000000",
|
|
"inst_access_mask6" => "0xffffffff",
|
|
"inst_access_enable7" => "0x0",
|
|
"inst_access_addr7" => "0x00000000",
|
|
"inst_access_mask7" => "0xffffffff",
|
|
"data_access_enable0" => "0x0",
|
|
"data_access_addr0" => "0x00000000",
|
|
"data_access_mask0" => "0xffffffff",
|
|
"data_access_enable1" => "0x0",
|
|
"data_access_addr1" => "0x00000000",
|
|
"data_access_mask1" => "0xffffffff",
|
|
"data_access_enable2" => "0x0",
|
|
"data_access_addr2" => "0x00000000",
|
|
"data_access_mask2" => "0xffffffff",
|
|
"data_access_enable3" => "0x0",
|
|
"data_access_addr3" => "0x00000000",
|
|
"data_access_mask3" => "0xffffffff",
|
|
"data_access_enable4" => "0x0",
|
|
"data_access_addr4" => "0x00000000",
|
|
"data_access_mask4" => "0xffffffff",
|
|
"data_access_enable5" => "0x0",
|
|
"data_access_addr5" => "0x00000000",
|
|
"data_access_mask5" => "0xffffffff",
|
|
"data_access_enable6" => "0x0",
|
|
"data_access_addr6" => "0x00000000",
|
|
"data_access_mask6" => "0xffffffff",
|
|
"data_access_enable7" => "0x0",
|
|
"data_access_addr7" => "0x00000000",
|
|
"data_access_mask7" => "0xffffffff",
|
|
},
|
|
"memmap" => { # Testbench only
|
|
"serialio" => 'derived, overridable', # Testbench only
|
|
"external_data" => 'derived, overridable', # Testbench only
|
|
"external_prog" => 'derived, overridable', # Testbench only
|
|
"debug_sb_mem" => 'derived, overridable', # Testbench only
|
|
"external_data_1" => 'derived, overridable', # Testbench only
|
|
"external_mem_hole" => 'derived, overridable', # Testbench only
|
|
# "consoleio" => 'derived', # Part of serial io.
|
|
},
|
|
"bus" => {
|
|
"lsu_bus_tag" => 'derived',
|
|
"dma_bus_tag" => '1',
|
|
"sb_bus_tag" => '1',
|
|
"ifu_bus_tag" => '3',
|
|
},
|
|
"triggers" => \@triggers,
|
|
"csr" => \%csr,
|
|
"even_odd_trigger_chains" => "true",
|
|
);
|
|
|
|
if (($fpga_optimize==0) && !grep(/fpga_optimize/, @sets)) { delete $config{"core"}{"fpga_optimize"}; }
|
|
if (($iccm_enable==0) && !grep(/iccm_enable/, @sets)) { delete $config{"iccm"}{"iccm_enable"}; }
|
|
if (($dccm_enable==0) && !grep(/dccm_enable/, @sets)) { delete $config{"dccm"}{"dccm_enable"}; }
|
|
if (($icache_enable==0) && !grep(/icache_enable/, @sets)) { delete $config{"icache"}{"icache_enable"}; }
|
|
if (($verilator==0) && !grep(/verilator/, @sets)) { delete $config{"core"}{"verilator"}; }
|
|
if (($no_secondary_alu==0) && !grep(/no_secondary_alu/, @sets)) { delete $config{"core"}{"no_secondary_alu"}; }
|
|
if (($pic_2cycle==0) && !grep(/pic_2cycle/, @sets)) { delete $config{"pic"}{"pic_2cycle"}; }
|
|
if (($icache_ecc==0) && !grep(/icache_ecc/, @sets)) { delete $config{"icache"}{"icache_ecc"}; }
|
|
|
|
|
|
|
|
# Perform any overrides first before derived values
|
|
map_set_unset();
|
|
gen_define("","", \%config,[]);
|
|
print "\nSweRV configuration for target=$target\n\n";
|
|
dump_define("","", \%config,[]);
|
|
|
|
# perform final checks
|
|
my $c;
|
|
$c=$config{retstack}{ret_stack_size}; if (!($c >=2 && $c <=8)) { die("$helpusage\n\nFAIL: ret_stack_size == $c; ILLEGAL !!!\n\n"); }
|
|
$c=$config{btb}{btb_size}; if (!($c==32||$c==48||$c==64||$c==128||$c==256||$c==512)){ die("$helpusage\n\nFAIL: btb_size == $c; ILLEGAL !!!\n\n"); }
|
|
$c=$config{iccm}{iccm_region}; if (!($c>=0 && $c<16)) { die("$helpusage\n\nFAIL: iccm_region == $c ILLEGAL !!!\n\n"); }
|
|
$c=$config{iccm}{iccm_offset}; if (!($c>=0 && $c<256*1024*1024 && ($c&0xfff)==0)) { die("$helpusage\n\nFAIL: iccm_offset == $c ILLEGAL !!!\n\n"); }
|
|
$c=$config{iccm}{iccm_size}; if (!($c==4||$c==8||$c==16||$c==32||$c==64||$c==128||$c==256||$c==512)) { die("$helpusage\n\nFAIL: iccm_size == $c ILLEGAL !!!\n\n"); }
|
|
$c=$config{iccm}{iccm_num_banks}; if (!($c==4 || $c==8 || ($c==16 && $config{iccm}{iccm_size} != 4))) { die("$helpusage\n\nFAIL: iccm_num_banks == $c ILLEGAL !!!\n\n"); }
|
|
$c=$config{iccm}{iccm_enable}; if (!($c==0 || $c==1)) { die("$helpusage\n\nFAIL: iccm_enable == $c ILLEGAL !!!\n\n"); }
|
|
$c=$config{dccm}{dccm_region}; if (!($c>=0 && $c<16)) { die("$helpusage\n\nFAIL: iccm_region == $c ILLEGAL !!!\n\n"); }
|
|
$c=$config{dccm}{dccm_num_banks}; if (!($c==4 || $c==8 || ($c==16 && $config{dccm}{dccm_size} != 4) )) { die("$helpusage\n\nFAIL: dccm_num_banks == $c ILLEGAL !!!\n\n"); }
|
|
$c=$config{dccm}{dccm_offset}; if (!($c>=0 && $c<256*1024*1024 && ($c&0xfff)==0)) { die("$helpusage\n\nFAIL: iccm_offset == $c ILLEGAL !!!\n\n"); }
|
|
$c=$config{dccm}{dccm_size}; if (!($c==4||$c==8||$c==16||$c==32||$c==48||$c==64||$c==128||$c==256||$c==512)) { die("$helpusage\n\nFAIL: iccm_size == $c ILLEGAL !!!\n\n"); }
|
|
$c=$config{pic}{pic_2cycle}; if (!($c==0 || $c==1)) { die("$helpusage\n\nFAIL: pic_2cycle == $c ILLEGAL !!!\n\n"); }
|
|
$c=$config{pic}{pic_region}; if (!($c>=0 && $c<16)) { die("$helpusage\n\nFAIL: pic_region == $c ILLEGAL !!!\n\n"); }
|
|
$c=$config{pic}{pic_offset}; if (!($c>=0 && $c<256*1024*1024 && ($c&0xfff)==0)) { die("$helpusage\n\nFAIL: pic_offset == $c ILLEGAL !!!\n\n"); }
|
|
$c=$config{pic}{pic_size}; if (!($c==32 || $c==64 || $c==128 || $c==256)) { die("$helpusage\n\nFAIL: pic_size == $c ILLEGAL !!!\n\n"); }
|
|
$c=$config{pic}{pic_total_int}; if ( $c<1 || $c>255) { die("$helpusage\n\nFAIL: pic_total_int == $c ILLEGAL !!!\n\n"); }
|
|
$c=$config{icache}{icache_enable}; if (!($c==0 || $c==1)) { die("$helpusage\n\nFAIL: icache_enable == $c ILLEGAL !!!\n\n"); }
|
|
$c=$config{icache}{icache_size}; if (!($c==16 || $c==32 || $c==64 || $c==128 || $c==256)) { die("$helpusage\n\nFAIL: icache_size == $c ILLEGAL !!!\n\n"); }
|
|
$c=$config{core}{dec_instbuf_depth}; if (!($c==2 || $c==4)) { die("$helpusage\n\nFAIL: dec_instbuf_depth == $c ILLEGAL !!!\n\n"); }
|
|
$c=$config{core}{lsu_stbuf_depth}; if (!($c==2 || $c==4 || $c==8)) { die("$helpusage\n\nFAIL: lsu_stbuf_depth == $c ILLEGAL !!!\n\n"); }
|
|
$c=$config{core}{dma_buf_depth}; if (!($c==2 || $c==4)) { die("$helpusage\n\nFAIL: dma_buf_depth == $c ILLEGAL !!!\n\n"); }
|
|
$c=$config{core}{lsu_num_nbload}; if (!($c==2 || $c==4 || $c==8)) { die("$helpusage\n\nFAIL: lsu_num_nbload == $c ILLEGAL !!!\n\n"); }
|
|
|
|
$c=$config{protection}{inst_access_addr0}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: inst_access_addr0 lower 6b must be 0s $c !!!\n\n"); }
|
|
$c=$config{protection}{inst_access_addr1}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: inst_access_addr1 lower 6b must be 0s !!!\n\n"); }
|
|
$c=$config{protection}{inst_access_addr2}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: inst_access_addr2 lower 6b must be 0s !!!\n\n"); }
|
|
$c=$config{protection}{inst_access_addr3}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: inst_access_addr3 lower 6b must be 0s !!!\n\n"); }
|
|
$c=$config{protection}{inst_access_addr4}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: inst_access_addr4 lower 6b must be 0s !!!\n\n"); }
|
|
$c=$config{protection}{inst_access_addr5}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: inst_access_addr5 lower 6b must be 0s !!!\n\n"); }
|
|
$c=$config{protection}{inst_access_addr6}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: inst_access_addr6 lower 6b must be 0s !!!\n\n"); }
|
|
$c=$config{protection}{inst_access_addr7}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: inst_access_addr7 lower 6b must be 0s !!!\n\n"); }
|
|
$c=$config{protection}{inst_access_mask0}; if ((hex($c)&0x3f) != 63) { die("$helpusage\n\nFAIL: inst_access_mask0 lower 6b must be 1s !!!\n\n"); }
|
|
$c=$config{protection}{inst_access_mask1}; if ((hex($c)&0x3f) != 63) { die("$helpusage\n\nFAIL: inst_access_mask1 lower 6b must be 1s !!!\n\n"); }
|
|
$c=$config{protection}{inst_access_mask2}; if ((hex($c)&0x3f) != 63) { die("$helpusage\n\nFAIL: inst_access_mask2 lower 6b must be 1s !!!\n\n"); }
|
|
$c=$config{protection}{inst_access_mask3}; if ((hex($c)&0x3f) != 63) { die("$helpusage\n\nFAIL: inst_access_mask3 lower 6b must be 1s !!!\n\n"); }
|
|
$c=$config{protection}{inst_access_mask4}; if ((hex($c)&0x3f) != 63) { die("$helpusage\n\nFAIL: inst_access_mask4 lower 6b must be 1s !!!\n\n"); }
|
|
$c=$config{protection}{inst_access_mask5}; if ((hex($c)&0x3f) != 63) { die("$helpusage\n\nFAIL: inst_access_mask5 lower 6b must be 1s !!!\n\n"); }
|
|
$c=$config{protection}{inst_access_mask6}; if ((hex($c)&0x3f) != 63) { die("$helpusage\n\nFAIL: inst_access_mask6 lower 6b must be 1s !!!\n\n"); }
|
|
$c=$config{protection}{inst_access_mask7}; if ((hex($c)&0x3f) != 63) { die("$helpusage\n\nFAIL: inst_access_mask7 lower 6b must be 1s !!!\n\n"); }
|
|
$c=$config{protection}{data_access_addr0}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: data_access_addr0 lower 6b must be 0s !!!\n\n"); }
|
|
$c=$config{protection}{data_access_addr1}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: data_access_addr1 lower 6b must be 0s !!!\n\n"); }
|
|
$c=$config{protection}{data_access_addr2}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: data_access_addr2 lower 6b must be 0s !!!\n\n"); }
|
|
$c=$config{protection}{data_access_addr3}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: data_access_addr3 lower 6b must be 0s !!!\n\n"); }
|
|
$c=$config{protection}{data_access_addr4}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: data_access_addr4 lower 6b must be 0s !!!\n\n"); }
|
|
$c=$config{protection}{data_access_addr5}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: data_access_addr5 lower 6b must be 0s !!!\n\n"); }
|
|
$c=$config{protection}{data_access_addr6}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: data_access_addr6 lower 6b must be 0s !!!\n\n"); }
|
|
$c=$config{protection}{data_access_addr7}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: data_access_addr7 lower 6b must be 0s !!!\n\n"); }
|
|
$c=$config{protection}{data_access_mask0}; if ((hex($c)&0x3f) != 63) { die("$helpusage\n\nFAIL: data_access_mask0 lower 6b must be 1s !!!\n\n"); }
|
|
$c=$config{protection}{data_access_mask1}; if ((hex($c)&0x3f) != 63) { die("$helpusage\n\nFAIL: data_access_mask1 lower 6b must be 1s !!!\n\n"); }
|
|
$c=$config{protection}{data_access_mask2}; if ((hex($c)&0x3f) != 63) { die("$helpusage\n\nFAIL: data_access_mask2 lower 6b must be 1s !!!\n\n"); }
|
|
$c=$config{protection}{data_access_mask3}; if ((hex($c)&0x3f) != 63) { die("$helpusage\n\nFAIL: data_access_mask3 lower 6b must be 1s !!!\n\n"); }
|
|
$c=$config{protection}{data_access_mask4}; if ((hex($c)&0x3f) != 63) { die("$helpusage\n\nFAIL: data_access_mask4 lower 6b must be 1s !!!\n\n"); }
|
|
$c=$config{protection}{data_access_mask5}; if ((hex($c)&0x3f) != 63) { die("$helpusage\n\nFAIL: data_access_mask5 lower 6b must be 1s !!!\n\n"); }
|
|
$c=$config{protection}{data_access_mask6}; if ((hex($c)&0x3f) != 63) { die("$helpusage\n\nFAIL: data_access_mask6 lower 6b must be 1s !!!\n\n"); }
|
|
$c=$config{protection}{data_access_mask7}; if ((hex($c)&0x3f) != 63) { die("$helpusage\n\nFAIL: data_access_mask7 lower 6b must be 1s !!!\n\n"); }
|
|
|
|
|
|
|
|
if (($config{"testbench"}{"build_ahb_lite"} ne "")) {
|
|
delete $config{"testbench"}{"build_axi4"};
|
|
}
|
|
else { # default is AXI bus
|
|
delete $config{"testbench"}{"build_ahb_lite"};
|
|
}
|
|
|
|
|
|
# Over-ride MFDC reset value for AXI.
|
|
if (exists($config{"testbench"}{"build_axi_native"}) and
|
|
$config{"testbench"}{"build_axi_native"} ne "") {
|
|
$config{csr}{mfdc}{reset} = "0x00070040" if exists $config{csr}{mfdc};
|
|
}
|
|
|
|
# Over-ride MFDC reset value for AXI.
|
|
if (exists($config{"testbench"}{"build_axi_native"}) and
|
|
$config{"testbench"}{"build_axi_native"} ne "") {
|
|
$config{csr}{mfdc}{reset} = "0x00070040" if exists $config{csr}{mfdc};
|
|
}
|
|
|
|
|
|
# Fill in derived configuration entries.
|
|
|
|
if($config{btb}{btb_size}==512){
|
|
$config{btb}{btb_index1_hi} = 9;
|
|
$config{btb}{btb_index2_hi} = 15;
|
|
$config{btb}{btb_index3_hi} = 21;
|
|
$config{btb}{btb_array_depth}= 64;
|
|
$config{btb}{btb_btag_size} = 5;
|
|
} elsif($config{btb}{btb_size}==256){
|
|
$config{btb}{btb_index1_hi} = 8;
|
|
$config{btb}{btb_index2_hi} = 13;
|
|
$config{btb}{btb_index3_hi} = 18;
|
|
$config{btb}{btb_array_depth}= 32;
|
|
$config{btb}{btb_btag_size} = 6;
|
|
} elsif($config{btb}{btb_size}==128){
|
|
$config{btb}{btb_index1_hi} = 7;
|
|
$config{btb}{btb_index2_hi} = 11;
|
|
$config{btb}{btb_index3_hi} = 15;
|
|
$config{btb}{btb_array_depth}= 16;
|
|
$config{btb}{btb_btag_size} = 7;
|
|
} elsif($config{btb}{btb_size}==64){
|
|
$config{btb}{btb_index1_hi} = 6;
|
|
$config{btb}{btb_index2_hi} = 9;
|
|
$config{btb}{btb_index3_hi} = 12;
|
|
$config{btb}{btb_array_depth}= 8;
|
|
$config{btb}{btb_btag_size} = 8;
|
|
} elsif($config{btb}{btb_size}==48){
|
|
$config{btb}{btb_index1_hi} = 5;
|
|
$config{btb}{btb_index2_hi} = 7;
|
|
$config{btb}{btb_index3_hi} = 9;
|
|
$config{btb}{btb_array_depth}= 4;
|
|
$config{btb}{btb_48}= 1;
|
|
$config{btb}{btb_fold2_index_hash} = 1;
|
|
$config{btb}{btb_btag_size} = 9;
|
|
$config{btb}{btb_btag_fold} = 1;
|
|
} elsif($config{btb}{btb_size}==32){
|
|
$config{btb}{btb_index1_hi} = 5;
|
|
$config{btb}{btb_index2_hi} = 7;
|
|
$config{btb}{btb_index3_hi} = 9;
|
|
$config{btb}{btb_array_depth}= 4;
|
|
$config{btb}{btb_btag_size} = 9;
|
|
$config{btb}{btb_btag_fold} = 1;
|
|
}
|
|
|
|
$config{btb}{btb_index2_lo} = $config{btb}{btb_index1_hi}+1;
|
|
$config{btb}{btb_index3_lo} = $config{btb}{btb_index2_hi}+1;
|
|
$config{btb}{btb_addr_hi} = $config{btb}{btb_index1_hi};
|
|
|
|
# BHT index is a hash of the GHR and PC_HASH
|
|
sub ghrhash{
|
|
my($btb_index_hi,$ghr_size) = @_;
|
|
|
|
$btb_addr_width = $btb_index_hi - 3;
|
|
|
|
$ghr_hi = $ghr_size - 1;
|
|
$ghr_lo = $btb_addr_width;
|
|
|
|
$ghr_start = "{";
|
|
if($ghr_size > $btb_addr_width){
|
|
if($ghr_size-1 == $btb_addr_width){
|
|
$string= "{ghr[$ghr_hi:$ghr_lo] ^ ghr[$ghr_hi+1],hashin[$config{btb}{btb_index1_hi}:4]^ghr[$ghr_lo-1:0]}";
|
|
}
|
|
else{
|
|
$string = "{ghr[$ghr_hi:$ghr_lo] ^ {ghr[$ghr_hi+1], {$ghr_size-1-$btb_addr_width\{1'b0} } },hashin[$config{btb}{btb_index1_hi}:4]^ghr[$ghr_lo-1:0]}";
|
|
}
|
|
}
|
|
elsif($ghr_size < $btb_addr_width){
|
|
$string = "{hashin[$ghr_size+3:4]^ghr[$ghr_size-1:0]^{ghr[$ghr_hi+1], {$ghr_hi\{1'b0} } }}";
|
|
}
|
|
else{ $string = "{hashin[$config{btb}{btb_index1_hi}:4]^ghr[$ghr_lo-1:0]^{ghr[$ghr_hi+1], {$btb_addr_width-1\{1'b0} } } }"}
|
|
return $string;
|
|
|
|
}
|
|
|
|
|
|
if($config{bht}{bht_size}==2048){
|
|
$config{bht}{bht_ghr_size}= 9;
|
|
$config{bht}{bht_ghr_range}= "8:0";
|
|
$config{bht}{bht_ghr_pad}= "fghr[8:4],3'b0";
|
|
$config{bht}{bht_ghr_pad2}= "fghr[8:3],2'b0";
|
|
$config{bht}{bht_array_depth}= 256;
|
|
$config{bht}{bht_addr_hi}= 11;
|
|
} elsif($config{bht}{bht_size}==1024){
|
|
$config{bht}{bht_ghr_size}= 8;
|
|
$config{bht}{bht_ghr_range}= "7:0";
|
|
$config{bht}{bht_ghr_pad}= "fghr[7:4],3'b0";
|
|
$config{bht}{bht_ghr_pad2}= "fghr[7:3],2'b0";
|
|
$config{bht}{bht_array_depth}= 128;
|
|
$config{bht}{bht_addr_hi}= 10;
|
|
} elsif($config{bht}{bht_size}==512){
|
|
$config{bht}{bht_ghr_size}= 7;
|
|
$config{bht}{bht_ghr_range}= "6:0";
|
|
$config{bht}{bht_ghr_pad}= "fghr[6:4],3'b0";
|
|
$config{bht}{bht_ghr_pad2}= "fghr[6:3],2'b0";
|
|
$config{bht}{bht_array_depth}= 64;
|
|
$config{bht}{bht_addr_hi}= 9;
|
|
} elsif($config{bht}{bht_size}==256){
|
|
$config{bht}{bht_ghr_size}= 6;
|
|
$config{bht}{bht_ghr_range}= "5:0";
|
|
$config{bht}{bht_ghr_pad}= "fghr[5:4],3'b0";
|
|
$config{bht}{bht_ghr_pad2}= "fghr[5:3],2'b0";
|
|
$config{bht}{bht_addr_hi} = 8;
|
|
$config{bht}{bht_array_depth}= 32;
|
|
} elsif($config{bht}{bht_size}==128){
|
|
$config{bht}{bht_ghr_size}= 5;
|
|
$config{bht}{bht_ghr_range}= "4:0";
|
|
$config{bht}{bht_ghr_pad}= "fghr[4],3'b0";
|
|
$config{bht}{bht_ghr_pad2}= "fghr[4:3],2'b0";
|
|
$config{bht}{bht_addr_hi} = 7;
|
|
$config{bht}{bht_array_depth}= 16;
|
|
} elsif($config{bht}{bht_size}==64){
|
|
$config{bht}{bht_ghr_size}= 4;
|
|
$config{bht}{bht_ghr_range}= "3:0";
|
|
$config{bht}{bht_ghr_pad}= "3'b0 ";
|
|
$config{bht}{bht_ghr_pad2}= "fghr[3],2'b0";
|
|
$config{bht}{bht_addr_hi} = 6;
|
|
$config{bht}{bht_array_depth}= 8;
|
|
} elsif($config{bht}{bht_size}==32){
|
|
$config{bht}{bht_ghr_size}= 3;
|
|
$config{bht}{bht_ghr_range}= "2:0";
|
|
$config{bht}{bht_ghr_pad}= "2'b0 ";
|
|
$config{bht}{bht_ghr_pad2}= "2'b0";
|
|
$config{bht}{bht_addr_hi} = 5;
|
|
$config{bht}{bht_array_depth}= 4;
|
|
}
|
|
#if($config{bht}{bht_size}==2048){
|
|
# $config{bht}{bht_ghr_size}= 8;
|
|
# $config{bht}{bht_ghr_range}= "7:0";
|
|
# $config{bht}{bht_ghr_pad}= "fghr[7:4],3'b0";
|
|
# $config{bht}{bht_ghr_pad2}= "fghr[7:3],2'b0";
|
|
# $config{bht}{bht_array_depth}= 256;
|
|
# $config{bht}{bht_addr_hi}= 11;
|
|
#} elsif($config{bht}{bht_size}==1024){
|
|
# $config{bht}{bht_ghr_size}= 7;
|
|
# $config{bht}{bht_ghr_range}= "6:0";
|
|
# $config{bht}{bht_ghr_pad}= "fghr[6:4],3'b0";
|
|
# $config{bht}{bht_ghr_pad2}= "fghr[6:3],2'b0";
|
|
# $config{bht}{bht_array_depth}= 128;
|
|
# $config{bht}{bht_addr_hi}= 10;
|
|
#} elsif($config{bht}{bht_size}==512){
|
|
# $config{bht}{bht_ghr_size}= 6;
|
|
# $config{bht}{bht_ghr_range}= "5:0";
|
|
# $config{bht}{bht_ghr_pad}= "fghr[5:4],3'b0";
|
|
# $config{bht}{bht_ghr_pad2}= "fghr[5:3],2'b0";
|
|
# $config{bht}{bht_array_depth}= 64;
|
|
# $config{bht}{bht_addr_hi}= 9;
|
|
#} elsif($config{bht}{bht_size}==256){
|
|
# $config{bht}{bht_ghr_size}= 5;
|
|
# $config{bht}{bht_ghr_range}= "4:0";
|
|
# $config{bht}{bht_ghr_pad}= "fghr[4],3'b0";
|
|
# $config{bht}{bht_ghr_pad2}= "fghr[4:3],2'b0";
|
|
# $config{bht}{bht_addr_hi} = 8;
|
|
# $config{bht}{bht_array_depth}= 32;
|
|
#} elsif($config{bht}{bht_size}==128){
|
|
# $config{bht}{bht_ghr_size}= 5;
|
|
# $config{bht}{bht_ghr_range}= "4:0";
|
|
# $config{bht}{bht_ghr_pad}= "fghr[4],3'b0";
|
|
# $config{bht}{bht_ghr_pad2}= "fghr[4:3],2'b0";
|
|
# $config{bht}{bht_addr_hi} = 7;
|
|
# $config{bht}{bht_array_depth}= 16;
|
|
#} elsif($config{bht}{bht_size}==64){
|
|
# $config{bht}{bht_ghr_size}= 4;
|
|
# $config{bht}{bht_ghr_range}= "3:0";
|
|
# $config{bht}{bht_ghr_pad}= "3'b0 ";
|
|
# $config{bht}{bht_ghr_pad2}= "fghr[4],2'b0";
|
|
# $config{bht}{bht_addr_hi} = 6;
|
|
# $config{bht}{bht_array_depth}= 8;
|
|
#} elsif($config{bht}{bht_size}==32){
|
|
# $config{bht}{bht_ghr_size}= 3;
|
|
# $config{bht}{bht_ghr_range}= "2:0";
|
|
# $config{bht}{bht_ghr_pad}= "2'b0 ";
|
|
# $config{bht}{bht_ghr_pad2}= "2'b0";
|
|
# $config{bht}{bht_addr_hi} = 5;
|
|
# $config{bht}{bht_array_depth}= 4;
|
|
# $config{bht}{bht_ghr_size_2} = 1;
|
|
#}
|
|
|
|
$config{bht}{bht_hash_string} = &ghrhash($config{btb}{btb_index1_hi}, $config{bht}{bht_ghr_size}-1);
|
|
|
|
$config{pic}{pic_base_addr} = (hex($config{pic}{pic_region})<<28) +
|
|
(hex($config{pic}{pic_offset}));
|
|
$config{pic}{pic_base_addr} = sprintf("0x%x", $config{pic}{pic_base_addr});
|
|
|
|
$config{pic}{pic_int_words} = int($config{pic}{pic_total_int}/32 +0.9);
|
|
$config{pic}{pic_bits} = 10 + log2($config{pic}{pic_size});
|
|
|
|
$config{core}{lsu_num_nbload_width} = log2($config{core}{lsu_num_nbload});
|
|
|
|
$config{bus}{lsu_bus_tag} = log2($config{core}{lsu_num_nbload}) + 1;
|
|
|
|
$config{dccm}{dccm_sadr} = (hex($config{dccm}{dccm_region})<<28) +
|
|
(hex($config{dccm}{dccm_offset}));
|
|
$config{dccm}{dccm_sadr} = sprintf("0x%x", $config{dccm}{dccm_sadr});
|
|
|
|
$config{dccm}{dccm_eadr} = (hex($config{dccm}{dccm_region})<<28) +
|
|
(hex($config{dccm}{dccm_offset})) + size($config{dccm}{dccm_size})-1;
|
|
$config{dccm}{dccm_eadr} = sprintf("0x%x", $config{dccm}{dccm_eadr});
|
|
|
|
$config{dccm}{dccm_reserved} = sprintf("0x%x", ($config{dccm}{dccm_size}>30)? 4096 : ($config{dccm}{dccm_size}*1024)/4);
|
|
|
|
$config{dccm}{dccm_bits} = ($config{dccm}{dccm_size}==48 ) ? 16 : 10 + log2($config{dccm}{dccm_size});
|
|
|
|
$config{dccm}{dccm_bank_bits} = log2($config{dccm}{dccm_num_banks});
|
|
$config{dccm}{dccm_data_width} = 32;
|
|
$config{dccm}{dccm_fdata_width} = $config{dccm}{dccm_data_width} + log2($config{dccm}{dccm_data_width}) + 2;
|
|
$config{dccm}{dccm_byte_width} = $config{dccm}{dccm_data_width}/8;
|
|
|
|
$config{dccm}{dccm_width_bits} = log2($config{dccm}{dccm_byte_width});
|
|
$config{dccm}{dccm_index_bits} = $config{dccm}{dccm_bits} - $config{dccm}{dccm_bank_bits} - $config{dccm}{dccm_width_bits};
|
|
|
|
$config{dccm}{dccm_ecc_width} = log2($config{dccm}{dccm_data_width}) + 2;
|
|
$config{dccm}{lsu_sb_bits} = (($config{dccm}{dccm_bits}) > ($config{pic}{pic_bits})) ? ($config{dccm}{dccm_bits}) : ($config{pic}{pic_bits});
|
|
$config{dccm}{dccm_rows} = ($config{dccm}{dccm_size}==48 ) ? (2**($config{dccm}{dccm_index_bits}-1) + 2**$config{dccm}{dccm_index_bits})/2 : 2**$config{dccm}{dccm_index_bits};
|
|
$config{dccm}{dccm_data_cell} = "ram_$config{dccm}{dccm_rows}x39";
|
|
|
|
|
|
$config{icache}{icache_tag_high} = (($config{icache}{icache_size}==256) ? 16 :
|
|
($config{icache}{icache_size}==128) ? 15 :
|
|
($config{icache}{icache_size}==64) ? 14 :
|
|
($config{icache}{icache_size}==32) ? 13 : 12);
|
|
|
|
$config{icache}{icache_tag_depth} = (($config{icache}{icache_size}==256) ? 1024 :
|
|
($config{icache}{icache_size}==128) ? 512 :
|
|
($config{icache}{icache_size}==64) ? 256 :
|
|
($config{icache}{icache_size}==32) ? 128 : 64);
|
|
|
|
|
|
$config{icache}{icache_ic_depth} = log2($config{icache}{icache_size}) + 4;
|
|
$config{icache}{icache_ic_index} = log2($config{icache}{icache_size}) + 4;
|
|
$config{icache}{icache_ic_rows} = 2**$config{icache}{icache_ic_depth};
|
|
|
|
|
|
$config{icache}{icache_taddr_high} = log2($config{icache}{icache_tag_depth}) - 1;
|
|
|
|
if (defined($config{icache}{icache_ecc})) {
|
|
$config{icache}{icache_data_cell} = "ram_$config{icache}{icache_ic_rows}x42";
|
|
$config{icache}{icache_tag_cell} = "ram_$config{icache}{icache_tag_depth}x25";
|
|
|
|
}
|
|
else {
|
|
$config{icache}{icache_data_cell} = "ram_$config{icache}{icache_ic_rows}x34";
|
|
$config{icache}{icache_tag_cell} = "ram_$config{icache}{icache_tag_depth}x21";
|
|
}
|
|
$config{pic}{pic_total_int_plus1} = $config{pic}{pic_total_int} + 1;
|
|
# Defines with explicit values in the macro name
|
|
$config{dccm}{"dccm_num_banks_$config{dccm}{dccm_num_banks}"} = "";
|
|
$config{dccm}{"dccm_size_$config{dccm}{dccm_size}"} = "";
|
|
|
|
# If ICCM offset not explicitly provided, align to TOP of the region
|
|
if ($top_align_iccm && ($config{iccm}{iccm_offset} eq $iccm_offset) && ($config{iccm}{iccm_size} < 32)) {
|
|
$config{iccm}{iccm_region} = "0xa";
|
|
print "$self: Setting default iccm region to region $config{iccm}{iccm_region}\n";
|
|
$config{iccm}{iccm_offset} = sprintf("0x%08x",256*1024*1024-size($config{iccm}{iccm_size}));
|
|
print "$self: Aligning default iccm offset to top of region @ $config{iccm}{iccm_offset}\n";
|
|
}
|
|
$config{iccm}{iccm_sadr} = (hex($config{iccm}{iccm_region})<<28) +
|
|
(hex($config{iccm}{iccm_offset}));
|
|
$config{iccm}{iccm_sadr} = sprintf("0x%08x", $config{iccm}{iccm_sadr});
|
|
|
|
$config{iccm}{iccm_eadr} = (hex($config{iccm}{iccm_region})<<28) +
|
|
(hex($config{iccm}{iccm_offset})) + size($config{iccm}{iccm_size})-1;
|
|
$config{iccm}{iccm_eadr} = sprintf("0x%08x", $config{iccm}{iccm_eadr});
|
|
|
|
$config{iccm}{iccm_reserved} = sprintf("0x%x", ($config{iccm}{iccm_size}>30)? 4096 : ($config{iccm}{iccm_size}*1024)/4);
|
|
|
|
$config{iccm}{iccm_bits} = 10 + log2($config{iccm}{iccm_size});
|
|
$config{iccm}{iccm_bank_bits} = log2($config{iccm}{iccm_num_banks}); //-1;
|
|
$config{iccm}{iccm_index_bits} = $config{iccm}{iccm_bits} - $config{iccm}{iccm_bank_bits} - 2; # always 4 bytes
|
|
$config{iccm}{iccm_rows} = 2**$config{iccm}{iccm_index_bits};
|
|
$config{iccm}{iccm_data_cell} = "ram_$config{iccm}{iccm_rows}x39";
|
|
# Defines with explicit values in the macro name
|
|
$config{iccm}{"iccm_num_banks_$config{iccm}{iccm_num_banks}"} = "";
|
|
$config{iccm}{"iccm_size_$config{iccm}{iccm_size}"} = "";
|
|
|
|
# Track used regions
|
|
|
|
$regions_used{hex($config{iccm}{iccm_region})} = 1;
|
|
$regions_used{hex($config{dccm}{dccm_region})} = 1;
|
|
$regions_used{hex($config{pic}{pic_region})} = 1;
|
|
$regions_used{hex($config{reset_vec})>>28} = 1;
|
|
|
|
# Find an unused region for serial IO
|
|
for (my $rgn = 15;$rgn >= 0; $rgn--) {
|
|
if (($rgn != hex($config{iccm}{iccm_region})) &&
|
|
($rgn != hex($config{dccm}{dccm_region})) &&
|
|
($rgn != (hex($config{pic}{pic_region})))) {
|
|
$config{memmap}{serialio} = ($rgn << 28) + (22<<18);
|
|
$regions_used{$rgn} = 1;
|
|
last;
|
|
}
|
|
}
|
|
|
|
$config{memmap}{serialio} = sprintf("0x%08x", $config{memmap}{serialio});
|
|
|
|
# Find an unused region for external data
|
|
for (my $rgn = 15;$rgn >= 0; $rgn--) {
|
|
if (($rgn != hex($config{iccm}{iccm_region})) &&
|
|
($rgn != hex($config{dccm}{dccm_region})) &&
|
|
($rgn != (hex($config{memmap}{serialio})>>28)) &&
|
|
($rgn != (hex($config{pic}{pic_region})))) {
|
|
$config{memmap}{external_data} = ($rgn << 28) + (22<<18);
|
|
$regions_used{$rgn} = 1;
|
|
last;
|
|
}
|
|
}
|
|
$config{memmap}{external_data} = sprintf("0x%08x", $config{memmap}{external_data});
|
|
#
|
|
# Find an unused region for external prog
|
|
for (my $rgn = 15;$rgn >= 0; $rgn--) {
|
|
if (($rgn != hex($config{iccm}{iccm_region})) &&
|
|
($rgn != hex($config{dccm}{dccm_region})) &&
|
|
($rgn != (hex($config{memmap}{serialio})>>28)) &&
|
|
($rgn != (hex($config{memmap}{external_data})>>28)) &&
|
|
($rgn != (hex($config{pic}{pic_region})))) {
|
|
$config{memmap}{external_prog} = ($rgn << 28);
|
|
$regions_used{$rgn} = 1;
|
|
last;
|
|
}
|
|
}
|
|
$config{memmap}{external_prog} = sprintf("0x%08x", $config{memmap}{external_prog});
|
|
|
|
# Unused region for second data
|
|
for (my $rgn = 15;$rgn >= 0; $rgn--) {
|
|
if (($rgn != hex($config{iccm}{iccm_region})) &&
|
|
($rgn != hex($config{dccm}{dccm_region})) &&
|
|
($rgn != (hex($config{memmap}{serialio})>>28)) &&
|
|
($rgn != (hex($config{memmap}{external_data})>>28)) &&
|
|
($rgn != (hex($config{memmap}{external_prog})>>28) &&
|
|
($rgn != (hex($config{pic}{pic_region})))
|
|
)) {
|
|
$config{memmap}{external_data_1} = ($rgn << 28);
|
|
$regions_used{$rgn} = 1;
|
|
last;
|
|
}
|
|
}
|
|
$config{memmap}{external_data_1} = sprintf("0x%08x", $config{memmap}{data_1});
|
|
|
|
|
|
#$config{memmap}{consoleio} = hex($config{memmap}{serialio}) + 0x100;
|
|
#$config{memmap}{consoleio} = sprintf("0x%x", $config{memmap}{consoleio});
|
|
|
|
# Find an unused region for debug_sb_memory data
|
|
for (my $rgn = 15;$rgn >= 0; $rgn--) {
|
|
if (($rgn != hex($config{iccm}{iccm_region})) &&
|
|
($rgn != hex($config{dccm}{dccm_region})) &&
|
|
($rgn != (hex($config{memmap}{serialio})>>28)) &&
|
|
($rgn != (hex($config{memmap}{external_data})>>28)) &&
|
|
($rgn != (hex($config{memmap}{external_data_1})>>28)) &&
|
|
($rgn != (hex($config{pic}{pic_region})))) {
|
|
$config{memmap}{debug_sb_mem} = ($rgn << 28) + (22<<18);
|
|
$regions_used{$rgn} = 1;
|
|
last;
|
|
}
|
|
}
|
|
$config{memmap}{debug_sb_mem} = sprintf("0x%08x", $config{memmap}{debug_sb_mem});
|
|
|
|
|
|
# Create the memory map hole for random testing
|
|
# Only do this if masks are not enabled already
|
|
if (hex($config{protection}{data_access_enable0}) > 0 ||
|
|
hex($config{protection}{data_access_enable1}) > 0 ||
|
|
hex($config{protection}{data_access_enable2}) > 0 ||
|
|
hex($config{protection}{data_access_enable3}) > 0 ||
|
|
hex($config{protection}{data_access_enable4}) > 0 ||
|
|
hex($config{protection}{data_access_enable5}) > 0 ||
|
|
hex($config{protection}{data_access_enable6}) > 0 ||
|
|
hex($config{protection}{data_access_enable7}) > 0 ||
|
|
hex($config{protection}{inst_access_enable0}) > 0 ||
|
|
hex($config{protection}{inst_access_enable1}) > 0 ||
|
|
hex($config{protection}{inst_access_enable2}) > 0 ||
|
|
hex($config{protection}{inst_access_enable3}) > 0 ||
|
|
hex($config{protection}{inst_access_enable4}) > 0 ||
|
|
hex($config{protection}{inst_access_enable5}) > 0 ||
|
|
hex($config{protection}{inst_access_enable6}) > 0 ||
|
|
hex($config{protection}{inst_access_enable7}) > 0) {
|
|
delete($config{memmap}{external_mem_hole}) ;
|
|
} else {
|
|
# Unused region to create a memory map hole
|
|
for (my $rgn = 15;$rgn >= 0; $rgn--) {
|
|
if (!defined($regions_used{$rgn})) {
|
|
$config{memmap}{external_mem_hole} = ($rgn << 28);
|
|
$regions_used{$rgn} = 1;
|
|
last;
|
|
}
|
|
}
|
|
if ($config{memmap}{external_mem_hole} == 0) {
|
|
$config{protection}{data_access_addr0} = "0x10000000";
|
|
$config{protection}{data_access_mask0} = "0xffffffff";
|
|
$config{protection}{data_access_enable0} = "1";
|
|
} elsif (($config{memmap}{external_mem_hole}>>28) == 16) {
|
|
$config{protection}{data_access_addr0} = "0x00000000";
|
|
$config{protection}{data_access_mask0} = "0xefffffff";
|
|
$config{protection}{data_access_enable0} = "1";
|
|
} else {
|
|
my $hreg = $config{memmap}{external_mem_hole}>>28;
|
|
$config{protection}{data_access_addr0} = sprintf("0x%x", (($hreg^8)&8)<<28);
|
|
$config{protection}{data_access_mask0} = "0x7fffffff";
|
|
$config{protection}{data_access_addr1} = sprintf("0x%x", ($hreg&8) << 28 |(($hreg^4)&4)<<28);
|
|
$config{protection}{data_access_mask1} = "0x3fffffff";
|
|
$config{protection}{data_access_addr2} = sprintf("0x%x", ($hreg&12) <<28 | (($hreg^2)&2) <<28);
|
|
$config{protection}{data_access_mask2} = "0x1fffffff";
|
|
$config{protection}{data_access_addr3} = sprintf("0x%x", ($hreg&14) << 28 |(($hreg^1)&1)<<28);
|
|
$config{protection}{data_access_mask3} = "0x0fffffff";
|
|
$config{protection}{data_access_enable0} = "1";
|
|
$config{protection}{data_access_enable1} = "1";
|
|
$config{protection}{data_access_enable2} = "1";
|
|
$config{protection}{data_access_enable3} = "1";
|
|
$config{protection}{inst_access_addr0} = sprintf("0x%x", (($hreg^8)&8)<<28);
|
|
$config{protection}{inst_access_mask0} = "0x7fffffff";
|
|
$config{protection}{inst_access_addr1} = sprintf("0x%x", ($hreg&8) << 28 |(($hreg^4)&4)<<28);
|
|
$config{protection}{inst_access_mask1} = "0x3fffffff";
|
|
$config{protection}{inst_access_addr2} = sprintf("0x%x", ($hreg&12) <<28 | (($hreg^2)&2) <<28);
|
|
$config{protection}{inst_access_mask2} = "0x1fffffff";
|
|
$config{protection}{inst_access_addr3} = sprintf("0x%x", ($hreg&14) << 28 |(($hreg^1)&1)<<28);
|
|
$config{protection}{inst_access_mask3} = "0x0fffffff";
|
|
$config{protection}{inst_access_enable0} = "1";
|
|
$config{protection}{inst_access_enable1} = "1";
|
|
$config{protection}{inst_access_enable2} = "1";
|
|
$config{protection}{inst_access_enable3} = "1";
|
|
}
|
|
$config{memmap}{external_mem_hole} = sprintf("0x%08x", $config{memmap}{external_mem_hole});
|
|
}
|
|
|
|
#Define 5 unused regions for used in TG
|
|
|
|
foreach my $unr (reverse(0 .. 15)) {
|
|
if (!defined($regions_used{$unr})) {
|
|
$config{memmap}{"unused_region$unr"} = sprintf("0x%08x",($unr << 28));
|
|
$regions_used{$unr} = 1;
|
|
}
|
|
}
|
|
|
|
if ($target eq "baseline") {
|
|
$config{reset_vec} = $config{iccm}{iccm_sadr};
|
|
$config{testbench}{magellan} = 1;
|
|
print "$self: Setting reset_vec = ICCM start address for Baseline\n";
|
|
}
|
|
|
|
|
|
# Output bit-width specifiers for these variables
|
|
our %widths = (
|
|
"dccm_region" => "4",
|
|
"dccm_offset" => "28",
|
|
"dccm_sadr" => "32",
|
|
"dccm_eadr" => "32",
|
|
"pic_region" => "4",
|
|
"pic_offset" => "10",
|
|
"pic_base_addr" => "32",
|
|
"iccm_region" => "4",
|
|
"iccm_offset" => "10",
|
|
"iccm_sadr" => "32",
|
|
"iccm_eadr" => "32",
|
|
"bus_prty_default" => "2",
|
|
"inst_access_enable0" => "1",
|
|
"inst_access_enable1" => "1",
|
|
"inst_access_enable2" => "1",
|
|
"inst_access_enable3" => "1",
|
|
"inst_access_enable4" => "1",
|
|
"inst_access_enable5" => "1",
|
|
"inst_access_enable6" => "1",
|
|
"inst_access_enable7" => "1",
|
|
"data_access_enable0" => "1",
|
|
"data_access_enable1" => "1",
|
|
"data_access_enable2" => "1",
|
|
"data_access_enable3" => "1",
|
|
"data_access_enable4" => "1",
|
|
"data_access_enable5" => "1",
|
|
"data_access_enable6" => "1",
|
|
"data_access_enable7" => "1",
|
|
);
|
|
#}}}
|
|
|
|
|
|
#-----------------------Reset Vector MPU check-----------------------#
|
|
$flag_pass=0;
|
|
if(!(hex($config{reset_vec}) >= ((hex($config{iccm}{iccm_region})<<28) + (hex($config{iccm}{iccm_offset}))) && (hex($config{reset_vec}) < ((hex($config{iccm}{iccm_region})<<28) + (hex($config{iccm}{iccm_offset})) + size($config{iccm}{iccm_size})-1))))
|
|
{
|
|
for(my $i=0; $i<8; $i++)
|
|
{
|
|
$inst_access_enable = "inst_access_enable$i";
|
|
$inst_access_addr = "inst_access_addr$i";
|
|
$inst_access_mask = "inst_access_mask$i";
|
|
if(hex($config{protection}{$inst_access_enable}))
|
|
{
|
|
if((hex($config{reset_vec})>= hex($config{protection}{$inst_access_addr})) && (hex($config{reset_vec})< (hex($config{protection}{$inst_access_addr}) | hex($config{protection}{$inst_access_mask}))))
|
|
{
|
|
$flag_pass++;
|
|
last;
|
|
}
|
|
}
|
|
else {$enable_check++;}
|
|
}
|
|
|
|
if($flag_pass == 0 & $enable_check < 8) { die("$helpusage\n\nFAIL: RESET_VECTOR not in any of MPU enabled instruction access windows or ICCM !!!\n\n");}
|
|
}
|
|
#-----------------------Reset Vector MPU check-----------------------#
|
|
|
|
#print Dumper(\%config);
|
|
#print Dumper(\%width);
|
|
|
|
#print Dumper(\%sets);
|
|
#print Dumper(\%unsets);
|
|
|
|
# Sanity checks
|
|
check_addr_align("dccm", hex($config{dccm}{dccm_sadr}), $config{dccm}{dccm_size}*1024);
|
|
check_addr_align("iccm", hex($config{iccm}{iccm_sadr}), $config{iccm}{iccm_size}*1024);
|
|
check_addr_align("pic", hex($config{pic}{pic_base_addr}), $config{pic}{pic_size}*1024);
|
|
|
|
# Prevent overlap of internal memories
|
|
if ((hex($config{pic}{pic_region}) == hex($config{iccm}{iccm_region})) && (hex($config{pic}{pic_offset}) == hex($config{iccm}{iccm_offset}))) {
|
|
die "$self: ERROR! PIC and ICCM blocks collide (region $config{iccm}{iccm_region}, offset $config{pic}{pic_offset})!\n";
|
|
}
|
|
if ((hex($config{pic}{pic_region}) == hex($config{dccm}{dccm_region})) && (hex($config{pic}{pic_offset}) == hex($config{dccm}{dccm_offset}))) {
|
|
die "$self: ERROR! PIC and DCCM blocks collide (region $config{dccm}{dccm_region}, offset $config{pic}{pic_offset})!\n";
|
|
}
|
|
if ((hex($config{iccm}{iccm_region}) == hex($config{dccm}{dccm_region})) && (hex($config{iccm}{iccm_offset}) == hex($config{dccm}{dccm_offset}))) {
|
|
die "$self: ERROR! ICCM and DCCM blocks collide (region $config{iccm}{iccm_region}, offset $config{dccm}{dccm_offset})!\n";
|
|
}
|
|
|
|
##################### Add dumper routines here ##########################
|
|
#
|
|
# Dump Verilog $RV_ROOT/configs/common_defines.vh
|
|
print "$self: Writing $vlogfile\n";
|
|
open (FILE, ">$vlogfile") || die "Cannot open $vlogfile for writing $!\n";
|
|
print_header("//");
|
|
gen_define("","`", \%config, \@verilog_vars);
|
|
close FILE;
|
|
|
|
print "$self: Writing $asmfile\n";
|
|
open (FILE, ">$asmfile") || die "Cannot open $asmfile for writing $!\n";
|
|
# Dump ASM/C $RV_ROOT/diags/env/defines.h
|
|
print_header("//");
|
|
gen_define("","#", \%config, \@asm_vars, \@asm_overridable);
|
|
close FILE;
|
|
|
|
# add `define PHYSICAL 1
|
|
# remove `undef RV_ICCM_ENABLE
|
|
|
|
my $pddata='
|
|
`include "common_defines.vh"
|
|
`undef ASSERT_ON
|
|
`undef TEC_RV_ICG
|
|
`define TEC_RV_ICG CKLNQD12BWP35P140
|
|
`define PHYSICAL 1
|
|
';
|
|
|
|
|
|
print "$self: Writing $pdfile\n";
|
|
open (FILE, ">$pdfile") || die "Cannot open $pdfile for writing $!\n";
|
|
# Dump PD $RV_ROOT/$RV_ROOT/configs/pd_defines.vh
|
|
print_header("//");
|
|
printf (FILE "$pddata");
|
|
close FILE;
|
|
|
|
print "$self: Writing $whisperfile\n";
|
|
dump_whisper_config(\%config, $whisperfile);
|
|
|
|
|
|
# change this to use config version
|
|
#`$ENV{RV_ROOT}/tools/picmap -t $config{pic}{pic_total_int} > $ENV{RV_ROOT}/design/include/pic_map_auto.h`;
|
|
`$ENV{RV_ROOT}/tools/picmap -t $config{pic}{pic_total_int} > $build_path/pic_map_auto.h`;
|
|
#`$ENV{RV_ROOT}/tools/unrollforverilator $config{pic}{pic_total_int_plus1} > $ENV{RV_ROOT}/design/include/pic_ctrl_verilator_unroll.sv`;
|
|
`$ENV{RV_ROOT}/tools/unrollforverilator $config{pic}{pic_total_int_plus1} > $build_path/pic_ctrl_verilator_unroll.sv`;
|
|
|
|
# Perl vars for use by scripts
|
|
print "$self: Writing $perlfile\n";
|
|
open (FILE, ">$perlfile") || die "Cannot open $perlfile for writing $!\n";
|
|
print_header("# ");
|
|
print FILE "# To use this in a perf script, use 'require \$RV_ROOT/configs/config.pl'\n";
|
|
print FILE "# Reference the hash via \$config{name}..\n\n\n";
|
|
print FILE Data::Dumper->Dump([\%config], [ qw(*config) ]);
|
|
print FILE "1;\n";
|
|
close FILE;
|
|
|
|
# Done ##################################################################
|
|
#
|
|
exit(0);
|
|
|
|
# ###################### Helper subroutines ##########################{{{
|
|
# Convert size in kilobytes to real value
|
|
|
|
sub size {#{{{
|
|
my $ksize = shift;
|
|
my $size = sprintf("%d",$ksize*1024);
|
|
return $size;
|
|
}#}}}
|
|
|
|
# Print the defines with prefix
|
|
sub print_define {#{{{
|
|
my ($sym, $key,$value, $override) = @_;
|
|
my $lprefix = $prefix if ($key !~ /$no_prefix/);
|
|
if ($sym eq "`") {
|
|
if (defined($widths{$key})) {
|
|
$value =~ s/^(0x)*/$widths{$key}'h/;
|
|
} else {
|
|
$value =~ s/^0x/'h/;
|
|
}
|
|
}
|
|
if ($defines_case eq "U") {
|
|
print FILE "${sym}ifndef \U$lprefix$key\E\n" if ($override);
|
|
print FILE "${sym}define \U$lprefix$key\E $value\n";
|
|
print FILE "${sym}endif\n" if ($override);
|
|
} else {
|
|
print FILE "${sym}ifndef $lprefix$key\n" if ($override);
|
|
print FILE "${sym}define $lprefix$key $value\n";
|
|
print FILE "${sym}endif\n" if ($override);
|
|
}
|
|
}#}}}
|
|
|
|
# print header
|
|
sub print_header {#{{{
|
|
my $cs = shift;
|
|
print FILE "$cs NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE\n";
|
|
print FILE "$cs This is an automatically generated file by $ENV{USER} on ",`date`;
|
|
print FILE "$cs\n$cs cmd: $self @argv_orig \n";
|
|
print FILE "$cs\n";
|
|
}#}}}
|
|
|
|
# evaluate derivations
|
|
sub derive {#{{{
|
|
my $eqn = shift;
|
|
return sprintf("0x%x", eval($eqn));
|
|
}#}}}
|
|
|
|
# traverse the database and extract the key/value pair
|
|
sub gen_define {#{{{
|
|
my $matched = shift;
|
|
my $prefix = shift;
|
|
my $hash = @_[0];
|
|
my @printvars = @{@_[1]};
|
|
my @overridable = @{@_[2]};
|
|
my $re = join("|",@printvars);
|
|
$re = qr/($re)/;
|
|
#print Dumper($hash);
|
|
foreach my $key (keys %$hash) {
|
|
next if $key eq "csr";
|
|
#print "looking at $key:$matched ($re)\n";
|
|
if (defined($unsets{$key})) {
|
|
print "$self:unsetting $key\n";
|
|
delete($config{$key});
|
|
next
|
|
}
|
|
if (defined($sets{$key}) && $sets{$key} ne $$hash{$key}) {
|
|
if (($$hash{$key} =~ /derived/i) && ($$hash{$key} !~ /overridable/i)) {
|
|
die ("$self: ERROR! $key is a derived and non-overridable parameter!\n");
|
|
} else {
|
|
print "$self: Overriding $key value $$hash{$key} with $sets{$key}\n";
|
|
$$hash{$key} = $sets{$key};
|
|
}
|
|
}
|
|
my $value = $$hash{$key};
|
|
if (ref($value) eq "HASH") {
|
|
if ($key =~ /$re/) {
|
|
$matched = 1;
|
|
}
|
|
gen_define($matched,$prefix, $value, \@printvars, \@overridable);
|
|
$matched = 0;
|
|
} elsif (ref($value) eq "ARRAY") {
|
|
# print "$key : @{$value}\n";
|
|
$matched = 0;
|
|
} else {
|
|
if ($matched eq "1" || $key =~ /$re/) {
|
|
if($value =~ /derive\(.*\)/o) {
|
|
$value = eval($value);
|
|
}
|
|
$override = grep(/^$key$/, @overridable);
|
|
print_define($prefix, $key, $value, $override);
|
|
}
|
|
}
|
|
}
|
|
}#}}}
|
|
|
|
sub dump_define {#{{{
|
|
my $matched = shift;
|
|
my $prefix = shift;
|
|
my $hash = @_[0];
|
|
my @printvars = @{@_[1]};
|
|
my @overridable = @{@_[2]};
|
|
my $re = join("|",@printvars);
|
|
$re = qr/($re)/;
|
|
#print Dumper($hash);
|
|
foreach my $key (keys %$hash) {
|
|
next if $key eq "csr";
|
|
next unless $matched || grep(/^$key$/,@dvars);
|
|
#print "looking at $key:$matched ($re)\n";
|
|
if (defined($unsets{$key})) {
|
|
print "$self:unsetting $key\n";
|
|
delete($config{$key});
|
|
next
|
|
}
|
|
if (defined($sets{$key}) && $sets{$key} ne $$hash{$key}) {
|
|
if (($$hash{$key} =~ /derived/i) && ($$hash{$key} !~ /overridable/i)) {
|
|
die ("$self: ERROR! $key is a derived and non-overridable parameter!\n");
|
|
} else {
|
|
print "$self: Overriding $key value $$hash{$key} with $sets{$key}\n";
|
|
$$hash{$key} = $sets{$key};
|
|
}
|
|
}
|
|
my $value = $$hash{$key};
|
|
if (ref($value) eq "HASH") {
|
|
if ($key =~ /$re/) {
|
|
$matched = 1;
|
|
}
|
|
dump_define($matched,$prefix, $value, \@printvars, \@overridable);
|
|
$matched = 0;
|
|
} elsif (ref($value) eq "ARRAY") {
|
|
# print "$key : @{$value}\n";
|
|
$matched = 0;
|
|
} else {
|
|
if ($matched eq "1" || $key =~ /$re/) {
|
|
if($value =~ /derive\(.*\)/o) {
|
|
$value = eval($value);
|
|
}
|
|
printf ("swerv: %-30s = $value\n",$key) if ($value !~ /derived/);
|
|
}
|
|
}
|
|
}
|
|
}#}}}
|
|
|
|
# Perform cmd line set/unset ############################################{{{
|
|
sub map_set_unset {
|
|
if (scalar(@sets)) {
|
|
print "$self: Set(s) requested : @sets\n";
|
|
foreach (@sets) {
|
|
my ($key,$value) = m/(\w+)=*(\w+)*/o;
|
|
$value = 1 if (!defined($value));
|
|
$sets{$key} = $value;
|
|
}
|
|
}
|
|
if (scalar(@unsets)) {
|
|
print "$self: Unset(s) requested : @sets\n";
|
|
foreach (@unsets) {
|
|
$unsets{$_} = 1;
|
|
}
|
|
}
|
|
} #}}}
|
|
#}}}
|
|
|
|
|
|
# If arg looks like a hexadecimal string, then convert it to decimal.#{{{
|
|
# Otherwise, return arg.
|
|
sub decimal {
|
|
my ($x) = @_;
|
|
return hex($x) if $x =~ /^0x/o;
|
|
return $x;
|
|
}#}}}
|
|
|
|
# Collect memory protection specs (array of address pairs) in the given
|
|
# resutls array. Tag is either "data" or "inst".
|
|
sub collect_mem_protection {
|
|
my ($tag, $config, $results) = @_;
|
|
return unless exists $config{protection};
|
|
|
|
my $prot = $config{protection};
|
|
|
|
my $enable_tag = $tag . "_access_enable";
|
|
my $addr_tag = $tag . "_access_addr";
|
|
my $mask_tag = $tag . "_access_mask";
|
|
|
|
foreach my $key (keys %{$prot}) {
|
|
next unless $key =~ /^$enable_tag(\d+)$/;
|
|
my $ix = $1;
|
|
|
|
my $enable = $prot->{$key};
|
|
if ($enable !~ /[01]$/) {
|
|
warn("Invalid value for protection entry $key: $enable\n");
|
|
next;
|
|
}
|
|
|
|
next unless ($enable eq "1" or $enable eq "1'b1");
|
|
|
|
if (! exists $prot->{"$addr_tag$ix"}) {
|
|
warn("Missing $addr_tag$ix\n");
|
|
next;
|
|
}
|
|
|
|
if (! exists $prot->{"$mask_tag$ix"}) {
|
|
warn("Missing $mask_tag$ix\n");
|
|
next;
|
|
}
|
|
|
|
my $addr = $prot->{"$addr_tag$ix"};
|
|
my $mask = $prot->{"$mask_tag$ix"};
|
|
|
|
if ($addr !~ /^0x[0-9a-fA-F]+$/) {
|
|
warn("Invalid $addr_tag$ix: $addr\n");
|
|
next;
|
|
}
|
|
|
|
if ($mask !~ /^0x[0-9a-fA-F]+$/) {
|
|
warn("Invalid $mask_tag$ix: $mask\n");
|
|
next;
|
|
}
|
|
|
|
if ((hex($addr) & hex($mask)) != 0) {
|
|
warn("Protection mask bits overlap address bits in mask $mask and addr $addr\n");
|
|
}
|
|
|
|
if ($mask !~ /^0x0*[137]?f*$/) {
|
|
warn("Protection $tag mask ($mask) must have all its one bits to the right of its zero bits\n");
|
|
next;
|
|
}
|
|
|
|
my $start = hex($addr) & ~hex($mask) & 0xffffffff;
|
|
my $end = (hex($addr) | hex($mask)) & 0xffffffff;
|
|
|
|
$start = sprintf("0x%08x", $start);
|
|
$end = sprintf("0x%08x", $end);
|
|
|
|
push(@{$results}, [ $start, $end ]);
|
|
}
|
|
}
|
|
|
|
# Collect memory protection specs (array of address pairs) in the given
|
|
# resutls array. Tag is either "data" or "inst".
|
|
sub collect_mem_protection {
|
|
my ($tag, $config, $results) = @_;
|
|
return unless exists $config{protection};
|
|
|
|
my $prot = $config{protection};
|
|
|
|
my $enable_tag = $tag . "_access_enable";
|
|
my $addr_tag = $tag . "_access_addr";
|
|
my $mask_tag = $tag . "_access_mask";
|
|
|
|
foreach my $key (keys %{$prot}) {
|
|
next unless $key =~ /^$enable_tag(\d+)$/;
|
|
my $ix = $1;
|
|
|
|
my $enable = $prot->{$key};
|
|
if ($enable !~ /[01]$/) {
|
|
warn("Invalid value for protection entry $key: $enable\n");
|
|
next;
|
|
}
|
|
|
|
next unless ($enable eq "1" or $enable eq "1'b1");
|
|
|
|
if (! exists $prot->{"$addr_tag$ix"}) {
|
|
warn("Missing $addr_tag$ix\n");
|
|
next;
|
|
}
|
|
|
|
if (! exists $prot->{"$mask_tag$ix"}) {
|
|
warn("Missing $mask_tag$ix\n");
|
|
next;
|
|
}
|
|
|
|
my $addr = $prot->{"$addr_tag$ix"};
|
|
my $mask = $prot->{"$mask_tag$ix"};
|
|
|
|
if ($addr !~ /^0x[0-9a-fA-F]+$/) {
|
|
warn("Invalid $addr_tag$ix: $addr\n");
|
|
next;
|
|
}
|
|
|
|
if ($mask !~ /^0x[0-9a-fA-F]+$/) {
|
|
warn("Invalid $mask_tag$ix: $mask\n");
|
|
next;
|
|
}
|
|
|
|
if ((hex($addr) & hex($mask)) != 0) {
|
|
warn("Protection mask bits overlap address bits in mask $mask and addr $addr\n");
|
|
}
|
|
|
|
if ($mask !~ /^0x0*[137]?f*$/) {
|
|
warn("Protection mask ($mask) must have all its one bits to the right of its zero bits\n");
|
|
next;
|
|
}
|
|
|
|
my $start = hex($addr) & ~hex($mask) & 0xffffffff;
|
|
my $end = (hex($addr) | hex($mask)) & 0xffffffff;
|
|
|
|
$start = sprintf("0x%08x", $start);
|
|
$end = sprintf("0x%08x", $end);
|
|
|
|
push(@{$results}, [ $start, $end ]);
|
|
}
|
|
}
|
|
|
|
|
|
sub dump_whisper_config{#{{{
|
|
my ($config, $path) = @_;
|
|
|
|
open(my $fh, ">", "$path") or die ("Failed to open $path for writing: $!\n");
|
|
|
|
# Put the configuration parameters relevant to whisper into a hash
|
|
# in preparation for a JSON dump.
|
|
my %jh; # Json hash
|
|
|
|
# Collect top-level integer entries.
|
|
foreach my $tag (qw( harts xlen )) {
|
|
$jh{$tag} = $config{$tag} + 0 if exists $config{$tag};
|
|
}
|
|
|
|
# Collect top-level string/hex entries.
|
|
foreach my $tag (qw ( reset_vec nmi_vec num_mmode_perf_regs max_mmode_perf_event
|
|
even_odd_trigger_chains)) {
|
|
$jh{$tag} = $config{$tag} if exists $config{$tag};
|
|
}
|
|
|
|
# Collect memory map configs.
|
|
my (@inst_mem_prot, @data_mem_prot);
|
|
collect_mem_protection("inst", $config, \@inst_mem_prot);
|
|
collect_mem_protection("data", $config, \@data_mem_prot);
|
|
$jh{memmap}{inst} = [@inst_mem_prot] if @inst_mem_prot;
|
|
$jh{memmap}{data} = [@data_mem_prot] if @data_mem_prot;
|
|
$jh{memmap}{cosnoleio} = $config{memmap}{serialio} if exists $config{memmap}{serialio};
|
|
|
|
# Collect load/store-error rollback parameter.
|
|
if (exists $config{testbench} and exists $config{testbench}{sterr_rollback}) {
|
|
$jh{store_error_rollback} = $config{testbench}{sterr_rollback};
|
|
}
|
|
if (exists $config{testbench} and exists $config{testbench}{lderr_rollback}) {
|
|
$jh{load_error_rollback} = $config{testbench}{lderr_rollback};
|
|
}
|
|
|
|
# Collect dccm configs
|
|
if (exists $config{dccm} and exists $config{dccm}{dccm_enable}) {
|
|
$jh{dccm}{region} = $config{dccm}{dccm_region};
|
|
$jh{dccm}{size} = 1024*decimal($config{dccm}{dccm_size}); # From 1k to bytes
|
|
$jh{dccm}{offset} = $config{dccm}{dccm_offset};
|
|
|
|
$jh{dccm}{size} = sprintf("0x%x", $jh{dccm}{size});
|
|
}
|
|
|
|
# Collect icccm configs.
|
|
if (exists $config{iccm} and exists $config{iccm}{iccm_enable}) {
|
|
$jh{iccm}{region} = $config{iccm}{iccm_region};
|
|
$jh{iccm}{size} = 1024*decimal($config{iccm}{iccm_size}); # From 1k to bytes
|
|
$jh{iccm}{offset} = $config{iccm}{iccm_offset};
|
|
|
|
$jh{iccm}{size} = sprintf("0x%x", $jh{iccm}{size});
|
|
}
|
|
|
|
# Collect CSRs
|
|
|
|
$jh{csr} = $config{csr} if exists $config{csr};
|
|
|
|
# Collect pic configs.
|
|
if (exists $config{pic}) {
|
|
while (my ($k, $v) = each %{$config{pic}}) {
|
|
next if $k eq 'pic_base_addr'; # derived from region and offset
|
|
if ($k eq 'pic_size') {
|
|
$v *= 1024; # from kbytes to bytes
|
|
$v = sprintf("0x%x", $v);
|
|
}
|
|
$k =~ s/^pic_//o;
|
|
$v += 0 if $v =~ /^\d+$/o;
|
|
$jh{pic}{$k} = $v;
|
|
}
|
|
}
|
|
|
|
# Collect triggers.
|
|
$jh{triggers} = $config{triggers} if exists $config{triggers};
|
|
|
|
# Dump JSON config file.
|
|
my $json = JSON->new->allow_nonref;
|
|
my $text = $json->pretty->encode(\%jh);
|
|
print($fh $text);
|
|
|
|
close $fh;
|
|
}#}}}
|
|
|
|
|
|
# Checker for iccm/dccm/pic sub-region address alignment. Address must be a multiple
|
|
# of size or next higher power of 2 if size is not a power of 2.
|
|
sub check_addr_align {
|
|
my ($section, $addr, $size) = @_;
|
|
|
|
die("Invalid $section size: $size\n") if $size <= 0;
|
|
|
|
my $log_size = log2($size);
|
|
my $p2 = 1 << $log_size;
|
|
$size = 2*$p2 if $size != $p2;
|
|
|
|
if (($addr % $size) != 0) {
|
|
printf("Address of $section area(0x%x) is not a multiple of its size (0x%x)\n",
|
|
$addr, $size);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
|
|
sub log2 {
|
|
my ($n) = @_;
|
|
return log($n)/log(2);
|
|
}
|