| #! /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; |
| |
| # 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"; |
| # |
| |
| $helpusage = " |
| |
| Main configuration database for SWERV |
| |
| This script documents, and generates the {`#} define/include files for verilog/assembly/backend flows |
| |
| |
| User options: |
| |
| -target = { default, generic } |
| 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 "generic") { |
| print "$self: Using target \"generic\"\n"; |
| 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="0x80000"; } #1*256*1024 |
| if (!defined($dccm_size)) { $dccm_size=512; } |
| if (!defined($dccm_num_banks)) { $dccm_num_banks=8; } |
| if (!defined($iccm_enable)) { $iccm_enable=1; } |
| 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=0; } |
| 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="0x100000"; } # 3*256*1024 |
| if (!defined($pic_size)) { $pic_size=32; } |
| if (!defined($pic_total_int)) { $pic_total_int=8; } |
| if (!defined($dec_instbuf_depth)) { $dec_instbuf_depth=2; } |
| } |
| elsif ($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 |
| } |
| else { |
| die "$self: ERROR! Unsupported target \"$target\". Supported targets are: \"default,generic\"!\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" => "0x40000888", |
| "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" => "0x40000888", |
| "exists" => "true", |
| }, |
| "mvendorid" => { |
| "reset" => "0x45", |
| "mask" => "0x0", |
| "exists" => "true", |
| }, |
| "marchid" => { |
| "reset" => "0x0000000b", |
| "mask" => "0x0", |
| "exists" => "true", |
| }, |
| "mimpid" => { |
| "reset" => "0x1", |
| "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", |
| }, |
| "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" => "", |
| "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" => { |
| "serialio" => 'derived, overridable', |
| "external_data" => 'derived, overridable', |
| "external_prog" => 'derived, overridable', |
| "debug_sb_mem" => 'derived, overridable', |
| "external_data_1" => 'derived, overridable', |
| # "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}; |
| } |
| |
| |
| # 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}"} = ""; |
| |
| # Find an unused region for serial IO |
| for ($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); |
| last; |
| } |
| } |
| $config{memmap}{serialio} = sprintf("0x%08x", $config{memmap}{serialio}); |
| |
| # Find an unused region for external data |
| for ($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); |
| last; |
| } |
| } |
| $config{memmap}{external_data} = sprintf("0x%08x", $config{memmap}{external_data}); |
| # |
| # Find an unused region for external prog |
| for ($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); |
| last; |
| } |
| } |
| $config{memmap}{external_prog} = sprintf("0x%08x", $config{memmap}{external_prog}); |
| |
| # Unused region for second data |
| for ($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); |
| 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 ($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}{debug_sb_mem} = ($rgn << 28) + (22<<18); |
| last; |
| } |
| } |
| $config{memmap}{debug_sb_mem} = sprintf("0x%08x", $config{memmap}{debug_sb_mem}); |
| |
| # Boot generic from ICCM |
| if ($target eq "generic") { |
| $config{reset_vec} = $config{iccm}{iccm_sadr}; |
| $config{testbench}{generic} = 1; |
| print "$self: Setting reset_vec = ICCM start address for Generic\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", |
| ); |
| #}}} |
| |
| #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 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); |
| } |