#! /usr/bin/env perl use strict; # Do not turn this off or else use Data::Dumper; use Getopt::Long; use Bit::Vector; 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 config_key reset_vec tec_rv_icg numiregs nmi_vec target protection.* 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 testbench.* protection.* core.*); my @asm_overridable = qw (reset_vec nmi_vec serialio external_data) ; # Include these macros in PD (pattern matched) my @pd_vars = qw (physical retstack target btb.* bht.* dccm.* iccm.* icache.* pic.* bus.* reset_vec nmi_vec build_ahb_lite datawidth ); # Dump non-derived/settable vars/values for these vars in stdout : my @dvars = qw(retstack btb bht core dccm iccm icache pic protection memmap bus); # Prefix all macros with my $prefix = "RV_"; # No prefix if keyword has my $no_prefix = 'RV|TOP|tec_rv_icg|regwidth|clock_period|^datawidth|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 It is run by vsim (with defaults) every time the file changes, or when -config_set=VAR=value options are passed to vsim This script can be run stand-alone by processes not running vsim User options: -target = {default, default_ahb, high_perf, typical_pd} use default settings for one of the targets -set=var=value set arbitrary variable(parameter) to a value -unset=var unset any definitions for var -snapshot=name name the configuration (only if no -target specified) Parameters that can be set by the end user: -set=ret_stack_size = {2, 3, 4, ... 8} size of return stack -set=btb_enable = {0,1} BTB enabled -set=btb_fullya = {0,1} BTB Fully set-associative -set=btb_size = { 8, 16, 32, 64, 128, 256, 512 } size of branch target buffer -set=bht_size = {32, 64, 128, 256, 512, 1024, 2048} size of branch history buffer -set=div_bit = {1,2,3,4} number of bits to process each cycle -set=div_new = {0,1} new div algorithm -set=dccm_enable = {0,1} DCCM enabled -set=dccm_num_banks = {2, 4} DCCM number of banks -set=dccm_region = { 0x0, 0x1, ... 0xf } number of 256Mb memory region containig DCCM -set=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 -set=dccm_size = { 4, 8, 16, 32, 48, 64, 128, 256, 512 } kB size of DCCM -set=dma_buf_depth = {2,4,5} DMA buffer depth -set=fast_interrupt_redirect = {0, 1} Fast interrupt redirect mechanism -set=iccm_enable = { 0, 1 } whether or not ICCM is enabled -set=icache_enable = { 0, 1 } whether or not icache is enabled -set=icache_waypack = { 0, 1 } whether or not icache packing is enabled -set=icache_ecc = { 0, 1 } whether or not icache has ecc - EXPENSIVE 30% sram growth default: icache_ecc==0 (parity) -set=icache_size = { 8, 16, 32, 64, 128, 256 } kB size of icache -set=icache_2banks = {0,1} Enable 2 banks for icache -set=icache_num_ways { 2,4} Number of ways in icache -set=icache_bypass_enable = {0,1} Enable Icache data bypass buffer -set=icache_num_bypass = {1..8} Number of entries in bypass buffer -set=icache_num_tag_bypass = {1..8} Number of entries in bypass buffer -set=icache_tag_bypass_enable = {0,1} Enable icache tag bypass buffer -set=iccm_region = { 0x0, 0x1, ... 0xf } number of 256Mb memory region containing ICCM -set=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 -set=iccm_size = { 4 , 8 , 16 , 32, 64, 128, 256, 512 } kB size of ICCM -set=iccm_num_banks = {2,4,8,16} Number of ICCM banks -set=lsu_stbuf_depth = {2,4,8 } LSU stbuf depth -set=lsu_num_nbload = {2,4,8 } LSU number of outstanding Non Blocking loads -set=load_to_use_plus1 = {0 1} Load to use latency (fast or +1cycle) -set=pic_2cycle = { 0, 1 } whether or not 2-cycle PIC is enabled (2 cycle pic may result in an overall smaller cycle time) -set=pic_region = { 0x0, 0x1, ... 0xf } number of 256Mb memory region containing PIC memory-mapped registers -set=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 -set=pic_size = { 32, 64, 128, 256 } kB size of PIC -set=pic_total_int = { 1, 2, 3, ..., 255 } number of interrupt sources in PIC -set=dma_buf_depth = {2,4,5} DMA buffer depth -set=timer_legal_en = {0,1} Internal timers legal/enabled -set=bitmanip_zba = {0,1} Bit manipulation extension ZBa enabled/legal -set=bitmanip_zbb = {0,1} Bit manipulation extension ZBb enabled/legal -set=bitmanip_zbc = {0,1} Bit manipulation extension ZBc enabled/legal -set=bitmanip_zbe = {0,1} Bit manipulation extension ZBe enabled/legal -set=bitmanip_zbf = {0,1} Bit manipulation extension ZBf enabled/legal -set=bitmanip_zbp = {0,1} Bit manipulation extension ZBp enabled/legal -set=bitmanip_zbr = {0,1} Bit manipulation extension ZBr enabled/legal -set=bitmanip_zbs = {0,1} Bit manipulation extension ZBs enabled/legal -fpga_optimize = { 0, 1 } if 1, minimize clock-gating to facilitate FPGA builds -text_in_iccm = {0, 1} Don't add ICCM preload code in generated link.ld Additionally the following may be set for bus masters and slaves using the -set=var=value option: {inst|data}_access_enable[0-7] : default 0 {inst|data}_access_addr[0-7] : default 0x00000000 {inst|data}_access_mask[0-7] : default 0xffffffff "; my $ret_stack_size; my $btb_size; my $bht_size; my $btb_fullya; my $btb_toffset_size; my $dccm_region; my $dccm_offset; my $dccm_size; my $iccm_enable; my $icache_enable; my $icache_waypack; my $icache_num_ways; my $icache_banks_way; my $icache_ln_sz; my $icache_bank_width; 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 $top_align_iccm = 0; my $target = "default"; my $snapshot ; my $build_path ; my $verbose; my $load_to_use_plus1; my $btb_enable; my $dccm_enable; my $icache_2banks; my $lsu_stbuf_depth; my $dma_buf_depth; my $lsu_num_nbload; my $dccm_num_banks; my $iccm_num_banks; my $verilator; my $icache_bypass_enable=1; my $icache_num_bypass=2; my $icache_num_bypass_width; my $icache_tag_bypass_enable=1; my $icache_tag_num_bypass=2; my $icache_tag_num_bypass_width; my $fast_interrupt_redirect = 1; # ON by default my $lsu_num_nbload=4; my $ahb = 0; my $axi = 1; my $text_in_iccm = 0; my $lsu2dma = 0; $ret_stack_size=4; $btb_enable=1; $btb_fullya=0; $btb_toffset_size=12; $btb_size=32; $bht_size=128; $dccm_enable=1; $dccm_region="0xf"; $dccm_offset="0x40000"; #1*256*1024 $dccm_size=32; $dccm_num_banks=8; $iccm_enable=0; $iccm_region="0xe"; $top_align_iccm = 1; $iccm_offset="0xe000000"; #0x380*256*1024 $iccm_size=32; $iccm_num_banks=8; $icache_enable=1; $icache_waypack=1; $icache_num_ways=2; $icache_banks_way=2; $icache_2banks=1; $icache_bank_width=8; $icache_ln_sz=64; $icache_ecc=0; $icache_size=16; $pic_2cycle=0; $pic_region="0xf"; $pic_offset="0xc0000"; # 3*256*1024 $pic_size=32; $pic_total_int=8; $load_to_use_plus1=0; $lsu_stbuf_depth=4; $dma_buf_depth=5; my $div_bit=4; # number of bits to process each cycle for div my $div_new=1; # old or new div algorithm my $fpga_optimize = 1; # Default bitmanip options my $bitmanip_zba = 1; my $bitmanip_zbb = 1; my $bitmanip_zbc = 1; my $bitmanip_zbe = 0; my $bitmanip_zbf = 0; my $bitmanip_zbp = 0; my $bitmanip_zbr = 0; my $bitmanip_zbs = 1; GetOptions( "help" => \$help, "target=s" => \$target, "snapshot=s" => \$snapshot, "verbose" => \$verbose, "load_to_use_plus1" => \$load_to_use_plus1, "ret_stack_size=s" => \$ret_stack_size, "btb_fullya" => \$btb_fullya, "btb_enable=s" => \$btb_enable, "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, "dma_buf_depth" => \$dma_buf_depth, "iccm_enable=s" => \$iccm_enable, "icache_enable=s" => \$icache_enable, "icache_waypack=s" => \$icache_waypack, "icache_num_ways=s" => \$icache_num_ways, "icache_ln_sz=s" => \$icache_ln_sz, "icache_ecc=s" => \$icache_ecc, "icache_2banks=s" => \$icache_2banks, "iccm_region=s" => \$iccm_region, "iccm_offset=s" => \$iccm_offset, "iccm_size=s" => \$iccm_size, "lsu_stbuf_depth" => \$lsu_stbuf_depth, "lsu_num_nbload" => \$lsu_num_nbload, "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, "set=s@" => \@sets, "unset=s@" => \@unsets, "fpga_optimize=s" => \$fpga_optimize, "text_in_iccm" => \$text_in_iccm, ) || die("$helpusage"); if ($help) { print "$helpusage\n"; exit; } if (!defined $snapshot ) { $snapshot = $target; } if (!defined $ENV{BUILD_PATH}) { $build_path = "$ENV{PWD}/snapshots/$snapshot" ; } else { $build_path = $ENV{BUILD_PATH}; } if (! -d "$build_path") { system ("mkdir -p $build_path"); } # Parameter file my $tdfile = "$build_path/el2_pdef.vh"; my $paramfile = "$build_path/el2_param.vh"; # 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"; # # Default linker file my $linkerfile = "$build_path/link.ld"; # Perl defines file path my $perlfile = "$build_path/perl_configs.pl"; my $opensource=0; # IDEA: is ghr at 5b the right size for el2 core if ($target eq "default") { } elsif ($target eq "lsu2dma_axi") { $lsu2dma = 1; $iccm_enable = 1; } elsif ($target eq "typical_pd") { print "$self: Using target \"typical_pd\"\n"; $fpga_optimize = 0; $ret_stack_size=2; $btb_size=32; $bht_size=128; $dccm_size=16; $dccm_num_banks=2; $iccm_enable=0; } elsif ($target eq "high_perf") { print "$self: Using target \"high_perf\"\n"; $btb_size=512; $bht_size=2048; } elsif ($target eq "default_ahb") { print "$self: Using target \"default_ahb\"\n"; $axi = 0; $ahb = 1; } else { die "$self: ERROR! Unsupported target \"$target\". Supported are 'default', 'default_ahb', 'typical_pd', 'high_perf', 'lsu2dma_axi\n" ; } # Configure triggers our @triggers = (#{{{ { "reset" => ["0x23e00000", "0x00000000", "0x00000000"], "mask" => ["0x081818c7", "0xffffffff", "0x00000000"], "poke_mask" => ["0x081818c7", "0xffffffff", "0x00000000"] }, { "reset" => ["0x23e00000", "0x00000000", "0x00000000"], "mask" => ["0x081810c7", "0xffffffff", "0x00000000"], "poke_mask" => ["0x081810c7", "0xffffffff", "0x00000000"] }, { "reset" => ["0x23e00000", "0x00000000", "0x00000000"], "mask" => ["0x081818c7", "0xffffffff", "0x00000000"], "poke_mask" => ["0x081818c7", "0xffffffff", "0x00000000"] }, { "reset" => ["0x23e00000", "0x00000000", "0x00000000"], "mask" => ["0x081810c7", "0xffffffff", "0x00000000"], "poke_mask" => ["0x081810c7", "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", }, "mcountinhibit" => { "commnet" => "Performance counter inhibit. One bit per counter.", "reset" => "0x0", "mask" => "0x7d", "poke_mask" => "0x7d", "exists" => "true", }, "mcounteren" => { "exists" => "false", }, "mvendorid" => { "reset" => "0x45", "mask" => "0x0", "exists" => "true", }, "marchid" => { "reset" => "0x00000010", "mask" => "0x0", "exists" => "true", }, "mimpid" => { "reset" => "0x4", "mask" => "0x0", "exists" => "true", }, "misa" => { "reset" => "0x40001104", "mask" => "0x0", "exists" => "true", }, "tselect" => { "reset" => "0x0", "mask" => "0x3", # Four triggers "exists" => "true", }, "mhartid" => { "reset" => "0x0", "mask" => "0x0", "poke_mask" => "0xfffffff0", "exists" => "true", }, "dcsr" => { "reset" => "0x40000003", "mask" => "0x00008c04", "poke_mask" => "0x00008dcc", # cause field modifiable, nmip modifiable "exists" => "true", "debug" => "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" => "0x0000000f", "exists" => "true", }, "mcpc" => { "comment" => "Core pause", "number" => "0x7c2", "reset" => "0x0", "mask" => "0x0", "exists" => "true", }, "mpmc" => { "number" => "0x7c6", "reset" => "0x2", "mask" => "0x2", "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" => "0x200", "mask" => "0x000003ff", "poke_mask" => "0x000003ff", "exists" => "true", }, "mfdc" => { "number" => "0x7f9", "reset" => "0x00070000", "mask" => "0x00071fff", "exists" => "true", }, "mrac" => { "comment" => "Memory region io and cache control.", "number" => "0x7c0", "reset" => "0x0", "mask" => "0xffffffff", "exists" => "true", "shared" => "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", }, "mfdht" => { "comment" => "Force Debug Halt Threshold", "number" => "0x7ce", "reset" => "0x0", "mask" => "0x0000003f", "exists" => "true", "shared" => "true", }, "mfdhs" => { "comment" => "Force Debug Halt Status", "number" => "0x7cf", "reset" => "0x0", "mask" => "0x00000003", "exists" => "true", }, "mscause" => { "number" => "0x7ff", "reset" => "0x0", "mask" => "0x0000000f", "exists" => "true", }, );#}}} # These are the peformance counters events implemented for el2s. An # event number from outside this list will be replaced by zero if # written to an MHPMEVENT CSR. my @perf_events = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 54, 55, 56, 512, 513, 514, 515, 516); 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 # # NOTE: params/keys marked 'derived' are not settable via cmd line, unless they ALSO have the 'overridable' tag # our %config = (#{{{ "harts" => "1", "xlen" => "32", # Testbench, Do Not Override "numiregs" => "32", # Testbench, Do Not Override "regwidth" => "32", # Testbench, Do Not Override "reset_vec" => "0x80000000", # Testbench, Overridable "nmi_vec" => "0x11110000", # Testbench, Overridable "physical" => "1", "num_mmode_perf_regs" => "4", # Whisper only "max_mmode_perf_event" => "516", # Whisper only: performance counters event ids will be clamped to this "target" => $target, # Flow Infrastructure "config_key" => "derived", "tec_rv_icg" => "clockhdr", "retstack" => { "ret_stack_size" => "$ret_stack_size", # Design Parm, Overridable }, "btb" => { "btb_enable" => "$btb_enable", # Design Parm, Overridable "btb_fullya" => "$btb_fullya", # Design Parm, Overridable "btb_toffset_size" => "$btb_toffset_size", # Constant "btb_size" => "$btb_size", # Design Parm, Overridable "btb_index1_hi" => "derived", "btb_index1_lo" => "2", # Constant, Do Not Override "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" => "2", # Constant, Do Not Override "btb_btag_size" => "derived", "btb_btag_fold" => "derived", "btb_fold2_index_hash" => "derived", }, "bht" => { "bht_size" => "$bht_size", # Design Parm, Overridable "bht_addr_hi" => "derived", "bht_addr_lo" => "2", # Constant, Do Not Override "bht_array_depth" => "derived", "bht_ghr_size" => "derived", "bht_ghr_range" => "derived", "bht_hash_string" => "derived", "bht_ghr_hash_1" => "derived", }, "core" => { "div_bit" => "$div_bit", # Design Parm, Overridable "div_new" => "$div_new", # Design Parm, Overridable "lsu_stbuf_depth" => "$lsu_stbuf_depth", # Design Parm, Overridable "dma_buf_depth" => "$dma_buf_depth", # Design Parm, Overridable "lsu_num_nbload" => "$lsu_num_nbload", # Design Parm, Overridable "opensource" => "$opensource", # Flow Infrastructure "verilator" => "$verilator", # Flow Infrastructure "load_to_use_plus1" => "$load_to_use_plus1", # Design Parm, Overridable "iccm_icache" => 'derived', # Used by design "iccm_only" => 'derived', # Used by design "icache_only" => 'derived', # Used by design "no_iccm_no_icache" => 'derived', # Used by design "timer_legal_en" => '1', # Design Parm, Overridable "bitmanip_zba" => $bitmanip_zba, # Design Parm, Overridable "bitmanip_zbb" => $bitmanip_zbb, # Design Parm, Overridable "bitmanip_zbc" => $bitmanip_zbc, # Design Parm, Overridable "bitmanip_zbe" => $bitmanip_zbe, # Design Parm, Overridable "bitmanip_zbf" => $bitmanip_zbf, # Design Parm, Overridable "bitmanip_zbp" => $bitmanip_zbp, # Design Parm, Overridable "bitmanip_zbr" => $bitmanip_zbr, # Design Parm, Overridable "bitmanip_zbs" => $bitmanip_zbs, # Design Parm, Overridable "fast_interrupt_redirect" => "$fast_interrupt_redirect", # Design Parm, Overridable "lsu2dma" => $lsu2dma, # used by design/TB for LSU to DMA bridge "fpga_optimize" => $fpga_optimize # Design Parm, Overridable }, "dccm" => { "dccm_enable" => "$dccm_enable", # Design Parm, Overridable "dccm_region" => "$dccm_region", # Design Parm, Overridable "dccm_offset" => "$dccm_offset", # Design Parm, Overridable "dccm_size" => "$dccm_size", # Design Parm, Overridable "dccm_num_banks" => "$dccm_num_banks", # Design Parm, Overridable "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', # Testbench use only : reserve dccm space for SW/stack - no random r/w }, "iccm" => { "iccm_enable" => "$iccm_enable", # Design Parm, Overridable "iccm_region" => "$iccm_region", # Design Parm, Overridable "iccm_offset" => "$iccm_offset", # Design Parm, Overridable "iccm_size" => "$iccm_size", # Design Parm, Overridable "iccm_num_banks" => "$iccm_num_banks", # Design Parm, Overridable "iccm_bank_bits" => 'derived', "iccm_index_bits" => 'derived', "iccm_rows" => 'derived', "iccm_data_cell" => 'derived', "iccm_sadr" => 'derived', "iccm_eadr" => 'derived', "iccm_reserved" => 'derived', # Testbench use only : reserve iccm space for SW/handlers - no random r/w "iccm_bank_hi" => 'derived', "iccm_bank_index_lo" => 'derived', }, "icache" => { "icache_enable" => "$icache_enable", # Design Parm, Overridable "icache_waypack" => "$icache_waypack", # Design Parm, Overridable "icache_num_ways" => "$icache_num_ways", # Design Parm, Overridable "icache_banks_way" => "2", # Design Parm, Constant "icache_bank_width" => "8", # Design Parm, Constant "icache_ln_sz" => "$icache_ln_sz", # Design Parm, Overridable "icache_size" => "$icache_size", # Design Parm, Overridable "icache_bypass_enable" => "$icache_bypass_enable", # Design Parm, Overridable "icache_num_bypass" => "$icache_num_bypass", # Design Parm, Overridable "icache_num_bypass_width" => 'derived', "icache_tag_bypass_enable" => "$icache_tag_bypass_enable", # Design Parm, Overridable "icache_tag_num_bypass" => "$icache_tag_num_bypass", # Design Parm, Overridable "icache_tag_num_bypass_width" => 'derived', "icache_bank_hi" => 'derived', "icache_bank_lo" => 'derived', "icache_data_cell" => 'derived', "icache_tag_cell" => 'derived', "icache_tag_depth" => 'derived', "icache_data_depth" => 'derived', "icache_num_lines" => 'derived', "icache_num_lines_bank" => 'derived', "icache_num_lines_way" => 'derived', "icache_data_depth" => 'derived', "icache_tag_lo" => 'derived', "icache_index_hi" => 'derived', "icache_data_index_lo" => 'derived', "icache_data_width" => 'derived', "icache_fdata_width" => 'derived', "icache_tag_index_lo" => 'derived', "icache_ecc" => "$icache_ecc", # Design Parm, Overridable "icache_2banks" => "$icache_2banks", # Design Parm, Overridable "icache_bank_bits" => "derived", "icache_status_bits" => "derived", "icache_num_beats" => "derived", "icache_beat_bits" => "derived", "icache_scnd_last" => "derived", "icache_beat_addr_hi" => "derived", }, "pic" => { "pic_2cycle" => "$pic_2cycle", # Design Parm, Overridable "pic_region" => "$pic_region", # Design Parm, Overridable "pic_offset" => "$pic_offset", # Design Parm, Overridable "pic_size" => "$pic_size", # Design Parm, Overridable "pic_base_addr" => 'derived', "pic_total_int_plus1" => 'derived', # pic_total_int + 1 "pic_total_int" => "$pic_total_int", # Design Parm, Overridable "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', # Testbench only: Offset of meipl relative to pic_base_addr "pic_meip_offset" => '0x1000', # Testbench only: Offset of meip relative to pic_base_addr "pic_meie_offset" => '0x2000', # Testbench only: Offset of meie relative to pic_base_addr "pic_mpiccfg_offset" => '0x3000', # Testbench only: Offset of mpiccfg relative to pic_base_addr "pic_meipt_offset" => '0x3004', # Testbench only: Offset of meipt relative to pic_base_addr -- deprecated "pic_meigwctrl_offset" => '0x4000', # Testbench only: gateway control regs relative to pic_base_addr "pic_meigwclr_offset" => '0x5000', # Testbench only: gateway clear regs relative to pic_base_addr "pic_meipl_mask" => '0xf', # Whisper only "pic_meip_mask" => '0x0', "pic_meie_mask" => '0x1', "pic_mpiccfg_mask" => '0x1', "pic_meipt_mask" => '0x0', "pic_meigwctrl_mask" => '0x3', "pic_meigwclr_mask" => '0x0', "pic_meipl_count" => 'derived', "pic_meip_count" => 'derived', "pic_meie_count" => 'derived', "pic_mpiccfg_count" => 1, "pic_meipt_count" => 'derived', "pic_meigwctrl_count" => 'derived', "pic_meigwclr_count" => 'derived', }, "testbench" => { # Testbench only "TOP" => "tb_top", "RV_TOP" => "`TOP.rvtop", "CPU_TOP" => "`RV_TOP.swerv", "clock_period" => "100", "build_ahb_lite" => "$ahb", "build_axi4" => "$axi", "build_axi_native" => "1", "assert_on" => "", "ext_datawidth" => "64", "ext_addrwidth" => "32", "sterr_rollback" => "0", "lderr_rollback" => "1", "SDVT_AHB" => "$ahb", }, "protection" => { # Design parms, Overridable - static MPU "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 "debug_sb_mem" => 'derived, overridable', # Testbench only "external_data_1" => 'derived, overridable', # Testbench only "external_mem_hole" => 'default disabled', # Testbench only # "consoleio" => 'derived', # Part of serial io. }, "bus" => { "lsu_bus_tag" => 'derived', "lsu_bus_id" => '1', "lsu_bus_prty" => '2', "dma_bus_tag" => '1', "dma_bus_id" => '1', "dma_bus_prty" => '2', "sb_bus_tag" => '1', "sb_bus_id" => '1', "sb_bus_prty" => '2', "ifu_bus_tag" => 'derived', "ifu_bus_id" => '1', "ifu_bus_prty" => '2', "bus_prty_default" => '3', }, "triggers" => \@triggers, # Whisper only "csr" => \%csr, # Whisper only "perf_events" => \@perf_events, # Whisper only "even_odd_trigger_chains" => "true", # Whisper only ); # These parms are used in the Verilog and will be part of global parm structure # need to have this be width in binary # for now autosize to the data our %verilog_parms = ( "lsu2dma" => '1', "timer_legal_en" => '1', "bitmanip_zbb" => '1', "bitmanip_zbs" => '1', "bitmanip_zba" => '1', "bitmanip_zbc" => '1', "bitmanip_zbe" => '1', "bitmanip_zbf" => '1', "bitmanip_zbp" => '1', "bitmanip_zbr" => '1', "fast_interrupt_redirect" => '1', "inst_access_enable0" => '1', "inst_access_addr0" => '32', "inst_access_mask0" => '32', "inst_access_enable1" => '1', "inst_access_addr1" => '32', "inst_access_mask1" => '32', "inst_access_enable2" => '1', "inst_access_addr2" => '32', "inst_access_mask2" => '32', "inst_access_enable3" => '1', "inst_access_addr3" => '32', "inst_access_mask3" => '32', "inst_access_enable4" => '1', "inst_access_addr4" => '32', "inst_access_mask4" => '32', "inst_access_enable5" => '1', "inst_access_addr5" => '32', "inst_access_mask5" => '32', "inst_access_enable6" => '1', "inst_access_addr6" => '32', "inst_access_mask6" => '32', "inst_access_enable7" => '1', "inst_access_addr7" => '32', "inst_access_mask7" => '32', "data_access_enable0" => '1', "data_access_addr0" => '32', "data_access_mask0" => '32', "data_access_enable1" => '1', "data_access_addr1" => '32', "data_access_mask1" => '32', "data_access_enable2" => '1', "data_access_addr2" => '32', "data_access_mask2" => '32', "data_access_enable3" => '1', "data_access_addr3" => '32', "data_access_mask3" => '32', "data_access_enable4" => '1', "data_access_addr4" => '32', "data_access_mask4" => '32', "data_access_enable5" => '1', "data_access_addr5" => '32', "data_access_mask5" => '32', "data_access_enable6" => '1', "data_access_addr6" => '32', "data_access_mask6" => '32', "data_access_enable7" => '1', "data_access_addr7" => '32', "data_access_mask7" => '32', "iccm_bits" => '5', "iccm_bank_hi" => '5', "iccm_bank_index_lo" => '5', "icache_bank_bits" => '3', "icache_status_bits" => '3', "icache_num_beats" => '4', "icache_beat_bits" => '4', "icache_scnd_last" => '4', "icache_beat_addr_hi" => '4', "icache_bypass_enable" => '1', "icache_num_bypass" => '4', "icache_num_bypass_width" => '4', "icache_tag_bypass_enable" => '1', "icache_tag_num_bypass" => '4', "icache_tag_num_bypass_width" => '4', "iccm_icache" => '1', "iccm_only" => '1', "icache_only" => '1', "no_iccm_no_icache" => '1', "build_axi4" => '1', "build_ahb_lite" => '1', "build_axi_native" => '1', "lsu_num_nbload_width" => '3', "lsu_num_nbload" => '5', "ret_stack_size" => '4', "btb_fullya" => '1', "btb_toffset_size" => '5', "btb_enable" => '1', "btb_size" => '10', "btb_index1_hi" => '5', "btb_index1_lo" => '5', "btb_index2_hi" => '5', "btb_index2_lo" => '5', "btb_index3_hi" => '5', "btb_index3_lo" => '5', "btb_addr_hi" => '5', "btb_array_depth" => '9', "btb_addr_lo" => '2', "btb_btag_size" => '5', "btb_btag_fold" => '1', "btb_fold2_index_hash" => '1', "bht_size" => '12', "bht_addr_hi" => '4', "bht_addr_lo" => '2', "bht_array_depth" => '11', "bht_ghr_size" => '4', "bht_ghr_hash_1" => '1', "div_bit" => '3', "div_new" => '1', "lsu_stbuf_depth" => '4', "dma_buf_depth" => '3', "load_to_use_plus1" => '1', "dccm_enable" => '1', "dccm_region" => '4', "dccm_size" => '10', "dccm_num_banks" => '5', "dccm_sadr" => '32', "dccm_bits" => '5', "dccm_bank_bits" => '3', "dccm_data_width" => '6', "dccm_fdata_width" => '6', "dccm_byte_width" => '3', "dccm_width_bits" => '2', "dccm_index_bits" => '4', "dccm_ecc_width" => '3', "lsu_sb_bits" => '5', "iccm_enable" => '1', "iccm_region" => '4', "iccm_size" => '10', "iccm_num_banks" => '5', "iccm_bank_bits" => '3', "iccm_index_bits" => '4', "iccm_sadr" => '32', "icache_enable" => '1', "icache_waypack" => '1', "icache_num_ways" => '3', "icache_banks_way" => '3', "icache_bank_width" => '4', "icache_ln_sz" => '7', "icache_size" => '9', "icache_bank_hi" => '3', "icache_bank_lo" => '2', "icache_tag_depth" => '13', "icache_data_depth" => '14', "icache_tag_lo" => '5', "icache_index_hi" => '5', "icache_data_index_lo" => '3', "icache_data_width" => '7', "icache_fdata_width" => '7', "icache_tag_index_lo" => '3', "icache_ecc" => '1', "icache_2banks" => '1', "pic_2cycle" => '1', "pic_region" => '4', "pic_size" => '9', "pic_base_addr" => '32', "pic_total_int_plus1" => '9', "pic_total_int" => '8', "pic_int_words" => '4', "pic_bits" => '5', "lsu_bus_tag" => '4', "lsu_bus_id" => '1', "lsu_bus_prty" => '2', "dma_bus_tag" => '4', "dma_bus_id" => '5', "dma_bus_prty" => '2', "sb_bus_tag" => '4', "sb_bus_id" => '1', "sb_bus_prty" => '2', "ifu_bus_tag" => '4', "ifu_bus_id" => '1', "ifu_bus_prty" => '2', "bus_prty_default" => '2', ); # to make sure parameter math works properly add 4 to each key of %verilog_parms - was an issue in btb calculations my $key; foreach $key (keys %verilog_parms) { $verilog_parms{$key} += 4; } # need to figure out what to do here # for now none of these can be parameters # move deletes lower # Perform any overrides first before derived values # map_set_unset(); gen_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==8||$c==16||$c==32||$c==64||$c==128||$c==256||$c==512)) { die("$helpusage\n\nFAIL: btb_size == $c; ILLEGAL !!!\n\n"); } $c=$config{btb}{btb_size}; if (($c==64||$c==128||$c==256||$c==512) && $config{btb}{btb_fullya}) { die("$helpusage\n\nFAIL: btb_size == $c; btb_fullya=1 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==2||$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==2 || $c==4 || ($c==8 && $config{iccm}{iccm_size} != 2) || ($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: dccm_region == $c ILLEGAL !!!\n\n"); } $c=$config{dccm}{dccm_num_banks}; if (!(($c==2 && $config{dccm}{dccm_size} != 48) || $c==4 || ($c==8 && $config{dccm}{dccm_size} != 48) || ($c==16 && $config{dccm}{dccm_size} != 4 && $config{dccm}{dccm_size} != 48))) { 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: dccm_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: dccm_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_num_bypass}; if ($c<1 || $c>8) { die("$helpusage\n\nFAIL: icache_num_bypass == $c ILLEGAL !!!\n\n"); } $c=$config{icache}{icache_bypass_enable}; if (!($c==0 || $c==1)) { die("$helpusage\n\nFAIL: icache_bypass_enable == $c ILLEGAL !!!\n\n"); } $c=$config{icache}{icache_tag_num_bypass}; if ($c<1 || $c>8) { die("$helpusage\n\nFAIL: icache_tag_num_bypass == $c ILLEGAL !!!\n\n"); } $c=$config{icache}{icache_tag_bypass_enable}; if (!($c==0 || $c==1)) { die("$helpusage\n\nFAIL: icache_tag_bypass_enable == $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_waypack}; if (!($c==0 || $c==1)) { die("$helpusage\n\nFAIL: icache_waypack == $c ILLEGAL !!!\n\n"); } $c=$config{icache}{icache_num_ways}; if (!($c==2 || $c==4)) { die("$helpusage\n\nFAIL: icache_num_ways == $c ILLEGAL !!!\n\n"); } $c=$config{icache}{icache_ln_sz}; if (!($c==32 || $c==64)) { die("$helpusage\n\nFAIL: icache_ln_sz == $c ILLEGAL !!!\n\n"); } $c=$config{icache}{icache_size}; if (!($c==8 || $c==16 || $c==32 || $c==64 || $c==128 || $c==256)) { die("$helpusage\n\nFAIL: icache_size == $c ILLEGAL !!!\n\n"); } $c=$config{core}{div_bit}; if (!($c==1 || $c==2 || $c==3 || $c==4 )) { die("$helpusage\n\nFAIL: div_bit == $c ILLEGAL !!!\n\n"); } $c=$config{core}{div_new}; if (!($c==0 || $c==1)) { die("$helpusage\n\nFAIL: div_new == $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 || $c==5)) { 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"); } # force div_bit to be 1 for old div algorithm if ($config{core}{div_new}==0 && $config{core}{div_bit}!=1) { die("$helpusage\n\nFAIL: div_new=0 requires div_bit=1 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 || invalid_mask($c)) { die("$helpusage\n\nFAIL: inst_access_mask0 invalid !!!\n\n"); } $c=$config{protection}{inst_access_mask1}; if ((hex($c)&0x3f) != 63 || invalid_mask($c)) { die("$helpusage\n\nFAIL: inst_access_mask1 invalid !!!\n\n"); } $c=$config{protection}{inst_access_mask2}; if ((hex($c)&0x3f) != 63 || invalid_mask($c)) { die("$helpusage\n\nFAIL: inst_access_mask2 invalid !!!\n\n"); } $c=$config{protection}{inst_access_mask3}; if ((hex($c)&0x3f) != 63 || invalid_mask($c)) { die("$helpusage\n\nFAIL: inst_access_mask3 invalid !!!\n\n"); } $c=$config{protection}{inst_access_mask4}; if ((hex($c)&0x3f) != 63 || invalid_mask($c)) { die("$helpusage\n\nFAIL: inst_access_mask4 invalid !!!\n\n"); } $c=$config{protection}{inst_access_mask5}; if ((hex($c)&0x3f) != 63 || invalid_mask($c)) { die("$helpusage\n\nFAIL: inst_access_mask5 invalid !!!\n\n"); } $c=$config{protection}{inst_access_mask6}; if ((hex($c)&0x3f) != 63 || invalid_mask($c)) { die("$helpusage\n\nFAIL: inst_access_mask6 invalid !!!\n\n"); } $c=$config{protection}{inst_access_mask7}; if ((hex($c)&0x3f) != 63 || invalid_mask($c)) { die("$helpusage\n\nFAIL: inst_access_mask7 invalid !!!\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 || invalid_mask($c)) { die("$helpusage\n\nFAIL: data_access_mask0 invalid !!!\n\n"); } $c=$config{protection}{data_access_mask1}; if ((hex($c)&0x3f) != 63 || invalid_mask($c)) { die("$helpusage\n\nFAIL: data_access_mask1 invalid !!!\n\n"); } $c=$config{protection}{data_access_mask2}; if ((hex($c)&0x3f) != 63 || invalid_mask($c)) { die("$helpusage\n\nFAIL: data_access_mask2 invalid !!!\n\n"); } $c=$config{protection}{data_access_mask3}; if ((hex($c)&0x3f) != 63 || invalid_mask($c)) { die("$helpusage\n\nFAIL: data_access_mask3 invalid !!!\n\n"); } $c=$config{protection}{data_access_mask4}; if ((hex($c)&0x3f) != 63 || invalid_mask($c)) { die("$helpusage\n\nFAIL: data_access_mask4 invalid !!!\n\n"); } $c=$config{protection}{data_access_mask5}; if ((hex($c)&0x3f) != 63 || invalid_mask($c)) { die("$helpusage\n\nFAIL: data_access_mask5 invalid !!!\n\n"); } $c=$config{protection}{data_access_mask6}; if ((hex($c)&0x3f) != 63 || invalid_mask($c)) { die("$helpusage\n\nFAIL: data_access_mask6 invalid !!!\n\n"); } $c=$config{protection}{data_access_mask7}; if ((hex($c)&0x3f) != 63 || invalid_mask($c)) { die("$helpusage\n\nFAIL: data_access_mask7 invalid !!!\n\n"); } if ((hex($config{protection}{inst_access_addr0}) & hex($config{protection}{inst_access_mask0}))!=0) { die("$helpusage\n\nFAIL: inst_access_addr0 and inst_access_mask0 must be orthogonal!!!\n\n"); } if ((hex($config{protection}{inst_access_addr1}) & hex($config{protection}{inst_access_mask1}))!=0) { die("$helpusage\n\nFAIL: inst_access_addr1 and inst_access_mask1 must be orthogonal!!!\n\n"); } if ((hex($config{protection}{inst_access_addr2}) & hex($config{protection}{inst_access_mask2}))!=0) { die("$helpusage\n\nFAIL: inst_access_addr2 and inst_access_mask2 must be orthogonal!!!\n\n"); } if ((hex($config{protection}{inst_access_addr3}) & hex($config{protection}{inst_access_mask3}))!=0) { die("$helpusage\n\nFAIL: inst_access_addr3 and inst_access_mask3 must be orthogonal!!!\n\n"); } if ((hex($config{protection}{inst_access_addr4}) & hex($config{protection}{inst_access_mask4}))!=0) { die("$helpusage\n\nFAIL: inst_access_addr4 and inst_access_mask4 must be orthogonal!!!\n\n"); } if ((hex($config{protection}{inst_access_addr5}) & hex($config{protection}{inst_access_mask5}))!=0) { die("$helpusage\n\nFAIL: inst_access_addr5 and inst_access_mask5 must be orthogonal!!!\n\n"); } if ((hex($config{protection}{inst_access_addr6}) & hex($config{protection}{inst_access_mask6}))!=0) { die("$helpusage\n\nFAIL: inst_access_addr6 and inst_access_mask6 must be orthogonal!!!\n\n"); } if ((hex($config{protection}{inst_access_addr7}) & hex($config{protection}{inst_access_mask7}))!=0) { die("$helpusage\n\nFAIL: inst_access_addr7 and inst_access_mask7 must be orthogonal!!!\n\n"); } if ((hex($config{protection}{data_access_addr0}) & hex($config{protection}{data_access_mask0}))!=0) { die("$helpusage\n\nFAIL: data_access_addr0 and data_access_mask0 must be orthogonal!!!\n\n"); } if ((hex($config{protection}{data_access_addr1}) & hex($config{protection}{data_access_mask1}))!=0) { die("$helpusage\n\nFAIL: data_access_addr1 and data_access_mask1 must be orthogonal!!!\n\n"); } if ((hex($config{protection}{data_access_addr2}) & hex($config{protection}{data_access_mask2}))!=0) { die("$helpusage\n\nFAIL: data_access_addr2 and data_access_mask2 must be orthogonal!!!\n\n"); } if ((hex($config{protection}{data_access_addr3}) & hex($config{protection}{data_access_mask3}))!=0) { die("$helpusage\n\nFAIL: data_access_addr3 and data_access_mask3 must be orthogonal!!!\n\n"); } if ((hex($config{protection}{data_access_addr4}) & hex($config{protection}{data_access_mask4}))!=0) { die("$helpusage\n\nFAIL: data_access_addr4 and data_access_mask4 must be orthogonal!!!\n\n"); } if ((hex($config{protection}{data_access_addr5}) & hex($config{protection}{data_access_mask5}))!=0) { die("$helpusage\n\nFAIL: data_access_addr5 and data_access_mask5 must be orthogonal!!!\n\n"); } if ((hex($config{protection}{data_access_addr6}) & hex($config{protection}{data_access_mask6}))!=0) { die("$helpusage\n\nFAIL: data_access_addr6 and data_access_mask6 must be orthogonal!!!\n\n"); } if ((hex($config{protection}{data_access_addr7}) & hex($config{protection}{data_access_mask7}))!=0) { die("$helpusage\n\nFAIL: data_access_addr7 and data_access_mask7 must be orthogonal!!!\n\n"); } # Fill in derived configuration entries. if (($config{icache}{icache_enable}==0 || grep(/icache_enable/, @unsets)) && $config{iccm}{iccm_enable}==0) { $config{core}{no_iccm_no_icache}=1; } elsif (($config{icache}{icache_enable}==0 || grep(/icache_enable/, @unsets)) && $config{iccm}{iccm_enable}==1) { $config{core}{iccm_only}=1; } elsif ($config{icache}{icache_enable}==1 && $config{iccm}{iccm_enable}==0) { $config{core}{icache_only}=1; } elsif ($config{icache}{icache_enable}==1 && $config{iccm}{iccm_enable}==1) { $config{core}{iccm_icache}=1; } if (!$config{dccm}{dccm_enable}) { $config{core}{fast_interrupt_redirect} = 0; print "$self: Disabling fast_interrupt_redirect because DCCM not enabled\n"; } $config{btb}{btb_btag_fold} = 0; $config{btb}{btb_fold2_index_hash} = 0; $config{btb}{btb_btag_size} = 31; if($config{btb}{btb_size}==512){ $config{btb}{btb_index1_hi} = 9; $config{btb}{btb_index2_hi} = 17; $config{btb}{btb_index3_hi} = 25; $config{btb}{btb_array_depth}= 256; $config{btb}{btb_btag_size} = 5; } elsif($config{btb}{btb_size}==256){ $config{btb}{btb_index1_hi} = 8; $config{btb}{btb_index2_hi} = 15; $config{btb}{btb_index3_hi} = 22; $config{btb}{btb_array_depth}= 128; $config{btb}{btb_btag_size} = 6; } elsif($config{btb}{btb_size}==128){ $config{btb}{btb_index1_hi} = 7; $config{btb}{btb_index2_hi} = 13; $config{btb}{btb_index3_hi} = 19; $config{btb}{btb_array_depth}= 64; $config{btb}{btb_btag_size} = 7; } elsif($config{btb}{btb_size}==64){ $config{btb}{btb_index1_hi} = 6; $config{btb}{btb_index2_hi} = 11; $config{btb}{btb_index3_hi} = 16; $config{btb}{btb_array_depth}= 32; $config{btb}{btb_btag_size} = 8; } elsif($config{btb}{btb_size}==32){ $config{btb}{btb_index1_hi} = 5; $config{btb}{btb_index2_hi} = 9; $config{btb}{btb_index3_hi} = 13; $config{btb}{btb_array_depth}= 16; $config{btb}{btb_btag_size} = 9 unless $config{btb}{btb_fullya}; $config{btb}{btb_btag_fold} = 1; } elsif($config{btb}{btb_size}<32){ #verif issues require these even though they are not needed $config{btb}{btb_index1_hi} = 5; $config{btb}{btb_index2_hi} = 8; $config{btb}{btb_index3_hi} = 11; $config{btb}{btb_fullya} = 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}; if($config{bht}{bht_size}==2048){ $config{bht}{bht_ghr_size}= 10; $config{bht}{bht_ghr_range}= "9:0"; $config{bht}{bht_array_depth}= 1024; $config{bht}{bht_addr_hi}= 11; } elsif($config{bht}{bht_size}==1024){ $config{bht}{bht_ghr_size}= 9; $config{bht}{bht_ghr_range}= "8:0"; $config{bht}{bht_array_depth}= 512; $config{bht}{bht_addr_hi}= 10; } elsif($config{bht}{bht_size}==512){ $config{bht}{bht_ghr_size}= 8; $config{bht}{bht_ghr_range}= "7:0"; $config{bht}{bht_array_depth}= 256; $config{bht}{bht_addr_hi}= 9; } elsif($config{bht}{bht_size}==256){ $config{bht}{bht_ghr_size}= 7; $config{bht}{bht_ghr_range}= "6:0"; $config{bht}{bht_addr_hi} = 8; $config{bht}{bht_array_depth}= 128; } elsif($config{bht}{bht_size}==128){ $config{bht}{bht_ghr_size}= 6; $config{bht}{bht_ghr_range}= "5:0"; $config{bht}{bht_addr_hi} = 7; $config{bht}{bht_array_depth}= 64; } elsif($config{bht}{bht_size}==64){ $config{bht}{bht_ghr_size}= 5; $config{bht}{bht_ghr_range}= "4:0"; $config{bht}{bht_addr_hi} = 6; $config{bht}{bht_array_depth}= 32; } elsif($config{bht}{bht_size}==32){ $config{bht}{bht_ghr_size}= 4; $config{bht}{bht_ghr_range}= "3:0"; $config{bht}{bht_addr_hi} = 5; $config{bht}{bht_array_depth}= 16; } $config{bht}{bht_ghr_hash_1} = ($config{bht}{bht_ghr_size} > ($config{btb}{btb_index1_hi}-1)); $config{bht}{bht_hash_string} = &ghrhash($config{btb}{btb_index1_hi}, $config{bht}{bht_ghr_size}); # PIC derived $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{pic}{pic_total_int_plus1} = $config{pic}{pic_total_int} + 1; $config{pic}{pic_meipl_count} = $config{pic}{pic_total_int}; $config{pic}{pic_meip_count} = $config{pic}{pic_int_words}; $config{pic}{pic_meie_count} = $config{pic}{pic_total_int}; $config{pic}{pic_meipt_count} = $config{pic}{pic_total_int}; $config{pic}{pic_meigwctrl_count} = $config{pic}{pic_total_int}; $config{pic}{pic_meigwclr_count} = $config{pic}{pic_total_int}; $config{icache}{icache_num_bypass_width} = int(log2($config{icache}{icache_num_bypass})) + 1; $config{icache}{icache_tag_num_bypass_width} = int(log2($config{icache}{icache_tag_num_bypass})) + 1; $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{bus}{ifu_bus_tag} = log2($config{icache}{icache_ln_sz}/8); $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}>=16)? 5120 : ($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{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_num_lines} = $config{icache}{icache_size}*1024/$config{icache}{icache_ln_sz}; $config{icache}{icache_num_lines_way} = $config{icache}{icache_num_lines}/$config{icache}{icache_num_ways}; $config{icache}{icache_num_lines_bank} = $config{icache}{icache_num_lines}/($config{icache}{icache_num_ways} * $config{icache}{icache_banks_way}); $config{icache}{icache_data_depth} = $config{icache}{icache_num_lines_bank} * $config{icache}{icache_ln_sz} /$config{icache}{icache_bank_width}; $config{icache}{icache_data_index_lo} = log2($config{icache}{icache_bank_width}) + log2($config{icache}{icache_banks_way}); $config{icache}{icache_index_hi} = $config{icache}{icache_data_index_lo} + log2($config{icache}{icache_data_depth}) -1; $config{icache}{icache_bank_hi} = $config{icache}{icache_data_index_lo} - 1; $config{icache}{icache_bank_lo} = log2($config{icache}{icache_bank_width}); $config{icache}{icache_tag_index_lo} = log2($config{icache}{icache_ln_sz}); $config{icache}{icache_tag_lo} = log2($config{icache}{icache_num_lines_way}) + $config{icache}{icache_tag_index_lo}; $config{icache}{icache_tag_depth} = $config{icache}{icache_num_lines}/$config{icache}{icache_num_ways}; $config{icache}{icache_data_width} = 8*$config{icache}{icache_bank_width}; $config{icache}{icache_bank_bits} = 1+$config{icache}{icache_bank_hi}-$config{icache}{icache_bank_lo}; $config{icache}{icache_status_bits} = $config{icache}{icache_num_ways}-1; $config{icache}{icache_num_beats} = ($config{icache}{icache_ln_sz}==64) ? 8 : 4; $config{icache}{icache_beat_bits} = ($config{icache}{icache_ln_sz}==64) ? 3 : 2; $config{icache}{icache_scnd_last} = ($config{icache}{icache_ln_sz}==64) ? 6 : 2; $config{icache}{icache_beat_addr_hi} = ($config{icache}{icache_ln_sz}==64) ? 5 : 4; if (($config{icache}{icache_ecc})) { $config{icache}{icache_fdata_width} = $config{icache}{icache_data_width} + 7; $config{icache}{icache_data_cell} = "ram_$config{icache}{icache_data_depth}x$config{icache}{icache_fdata_width}"; $config{icache}{icache_tag_cell} = ($config{icache}{icache_tag_depth} == 32) ? "ram_$config{icache}{icache_tag_depth}x26" : "ram_$config{icache}{icache_tag_depth}x25"; } else { $config{icache}{icache_fdata_width} = $config{icache}{icache_data_width} + 4; $config{icache}{icache_data_cell} = "ram_$config{icache}{icache_data_depth}x$config{icache}{icache_fdata_width}"; $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"; $config{iccm}{iccm_bank_hi} = 2+$config{iccm}{iccm_bank_bits}-1; $config{iccm}{iccm_bank_index_lo} = 1+$config{iccm}{iccm_bank_hi}; # 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}); # # 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{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}{external_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 || $config{memmap}{external_mem_hole} eq "default disabled"){ delete($config{memmap}{external_mem_hole}) ; } else { # Unused region to create a memory map hole, if not already specified if ($config{memmap}{external_mem_hole} eq 'derived, overridable') { for (my $rgn = 15;$rgn >= 0; $rgn--) { if (!defined($regions_used{$rgn})) { $config{memmap}{external_mem_hole} = ($rgn << 28); $regions_used{$rgn} = 1; last; } } } else { my $rgn = hex($config{memmap}{external_mem_hole})>>28; $config{memmap}{external_mem_hole} = ($rgn << 28); $regions_used{$rgn} =1; } 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 my $unrg = 0; foreach my $unr (reverse(0 .. 15)) { if (!defined($regions_used{$unr})) { $config{memmap}{"unused_region$unrg"} = sprintf("0x%08x",($unr << 28)); $regions_used{$unr} = 1; $unrg++; } } 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", ); #}}} print "\nSweRV configuration for target=$target\n\n"; dump_define("","", \%config,[]); #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"; } #printf( "axi4 %s\n",$config{"testbench"}{"build_axi4"}); #printf( "ahb_lite %s\n",$config{"testbench"}{"build_ahb_lite"}); #printf( "axi_native %s\n",$config{"testbench"}{"build_axi_native"}); if( $target eq "el2_formal_axi" ) { $config{testbench}{build_axi_native} = 1; $config{testbench}{build_axi4} = 1; print( "\$config{testbench}{build_axi_native} = $config{testbench}{build_axi_native} \n" ); print( "\$config{testbench}{build_axi4 } = $config{testbench}{build_axi4 } \n" ); } if (($config{testbench}{build_ahb_lite} == 1)) { delete $config{testbench}{build_axi4}; $config{testbench}{build_axi_native}=1; $verilog_parms{build_axi4} = 0; } elsif (($config{testbench}{build_axi4} == 1)) { $config{testbench}{build_axi_native}=1; delete $config{testbench}{build_ahb_lite}; $verilog_parms{build_ahb_lite} = 0; } elsif (($config{testbench}{build_axi_native} == 1)) { die("illegal to set build_axi_native w/out build_axi4"); } #printf( "axi4 %s\n",$config{"testbench"}{"build_axi4"}); #printf( "ahb_lite %s\n",$config{"testbench"}{"build_ahb_lite"}); #printf( "axi_native %s\n",$config{"testbench"}{"build_axi_native"}); # Over-ride MFDC reset value for AXI. # Disable Bus barrier and 64b for AXI if (defined($config{"testbench"}{"build_axi_native"}) && ($config{"testbench"}{"build_axi_native"} ne "0")) { if (! (defined($config{testbench}{build_ahb_lite}) && $config{testbench}{build_ahb_lite} ne "0")) { $config{csr}{mfdc}{reset} = "0x00070040" if exists $config{csr}{mfdc}; } } # parm processing before any values are deleted from the hash delete $config{core}{fpga_optimize} if ($config{core}{fpga_optimize} == 0); print "$self: Writing $tdfile\n"; print "$self: Writing $paramfile\n"; open (FILE1, ">$tdfile") || die "Cannot open $tdfile for writing $!\n"; open (FILE2, ">$paramfile") || die "Cannot open $paramfile for writing $!\n"; print_header("//"); gen_define("","`", \%config, \%verilog_parms, \@verilog_vars); dump_parms(\%verilog_parms); close FILE1; close FILE2; $config{config_key}="32'hdeadbeef"; # end parms # deletes if (($load_to_use_plus1==0) && !grep(/load_to_use_plus1/, @sets)) { delete $config{"core"}{"load_to_use_plus1"}; } if (($iccm_enable==0) && !grep(/iccm_enable/, @sets)) { delete $config{"iccm"}{"iccm_enable"}; } # new code to handle the -set=parm=0 value correctly for common_defines.vh $c=$config{core}{load_to_use_plus1}; if ($c==0 && !grep(/load_to_use_plus1=1/, @sets)) { delete $config{"core"}{"load_to_use_plus1"}; } $c=$config{core}{opensource}; if ($c==0 && !grep(/opensource=1/, @sets)) { delete $config{"core"}{"opensource"}; } $c=$config{core}{verilator}; if ($c==0 && !grep(/verilator=1/, @sets)) { delete $config{"core"}{"verilator"}; } $c=$config{core}{div_new}; if ($c==0 && !grep(/div_new=1/, @sets)) { delete $config{"core"}{"div_new"}; } # not needed #$c=$config{core}{div_bit}; if ($c==0 && !grep(/div_bit=1/, @sets)) { delete $config{"core"}{"div_bit"}; } $c=$config{iccm}{iccm_enable}; if ($c==0 && !grep(/iccm_enable=1/, @sets)) { delete $config{"iccm"}{"iccm_enable"}; } $c=$config{btb}{btb_enable}; if ($c==0 && !grep(/btb_enable=1/, @sets)) { delete $config{"btb"}{"btb_enable"}; } $c=$config{dccm}{dccm_enable}; if ($c==0 && !grep(/dccm_enable=1/, @sets)) { delete $config{"dccm"}{"dccm_enable"}; } $c=$config{icache}{icache_waypack}; if ($c==0 && !grep(/icache_waypack=1/, @sets)) { delete $config{"icache"}{"icache_waypack"}; } $c=$config{icache}{icache_enable}; if ($c==0 && !grep(/icache_enable=1/, @sets)) { delete $config{"icache"}{"icache_enable"}; } $c=$config{icache}{icache_2banks}; if ($c==0 && !grep(/icache_2banks=1/, @sets)) { delete $config{"icache"}{"icache_2banks"}; } $c=$config{pic}{pic_2cycle}; if ($c==0 && !grep(/pic_2cycle=1/, @sets)) { delete $config{"pic"}{"pic_2cycle"}; } $c=$config{btb}{btb_fullya}; if ($c==0 && !grep(/btb_fullya=1/, @sets)) { delete $config{"btb"}{"btb_fullya"}; } if ($target eq "default") { } elsif (($config{"testbench"}{"build_axi4"} == 1)) { delete $config{"testbench"}{"build_ahb_lite"}; delete $config{"testbench"}{"build_axi_native_ahb"}; } elsif (($config{"testbench"}{"build_ahb_lite"} == 1)) { delete $config{"testbench"}{"build_axi4"}; delete $config{"testbench"}{"build_axi_native"}; delete $config{"testbench"}{"build_axi_native_ahb"}; } elsif (($config{"testbench"}{"build_axi_native_ahb"} == 1)) { delete $config{"testbench"}{"build_axi4"}; delete $config{"testbench"}{"build_axi_native_ahb"}; } elsif (($config{"testbench"}{"build_axi_native"} == 1)) { die("illegal to set build_axi_native w/out build_axi4"); } else { delete $config{"testbench"}{"build_ahb_lite"}; delete $config{"testbench"}{"build_axi4"}; delete $config{"testbench"}{"build_axi_native"}; delete $config{"testbench"}{"build_axi_native_ahb"}; } ##################### 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("//"); print FILE "`define RV_ROOT \"".$ENV{RV_ROOT}."\"\n"; 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 RV_ASSERT_ON `undef TEC_RV_ICG `define RV_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); # PIC address map based on config `$ENV{RV_ROOT}/tools/picmap -t $config{pic}{pic_total_int} > $build_path/pic_map_auto.h`; # 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; # Default linker script gen_default_linker_script(); # 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 $parms = @_[1]; my @printvars = @{@_[2]}; my @overridable = @{@_[3]} if defined @_[3]; 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}); if ($parms and defined($parms->{$key})) { $parms->{$key} = 0; } 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, $parms, \@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); } my $override = grep(/^$key$/, @overridable); print_define($prefix, $key, $value, $override) if ($value !~ /derived/); #printf("$key = $value\n"); if ($parms and defined($parms->{$key})) { $value=decimal($value); #printf("verilog parm $key = $value %s\n",$parms->{$key}); $value=d2b($key,$value,$parms->{$key}); #printf("verilog parm $key = $value\n"); $parms->{$key}=$value; } } } } }#}}} sub dump_define {#{{{ my $matched = shift; my $prefix = shift; my $hash = @_[0]; my @printvars = @{@_[1]}; my @overridable = @{@_[2]} if defined @_[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 : @unsets\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 $tag 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 the memory mapped registers associated with the pic (platform # interrup controller) to include in the whisper.json file. sub collect_mem_mapped_regs {#{{{ my ($pic, $results) = @_; my $default_mask = 0; $results->{default_mask} = $default_mask; my $addr = hex($pic->{pic_region})*256*1024*1024 + hex($pic->{pic_offset}); $results->{address} = sprintf("0x%x", $addr); $results->{size} = sprintf("0x%x", $pic->{pic_size}*1024); my @names = qw ( mpiccfg meipl meip meie meigwctrl meigwclr meidels ); $results->{registers} = {}; foreach my $name (@names) { my $tag = "pic_${name}_offset"; next unless exists $pic->{$tag}; my %item; my $offset = hex($pic->{$tag}); $offset += 4 if ($name ne 'mpiccfg' and $name ne 'meip'); $item{address} = sprintf("0x%x", $addr + $offset); $item{mask} = $pic->{"pic_${name}_mask"}; $item{count} = $pic->{"pic_${name}_count"}; $results->{registers}{$name} = \%item; } }#}}} 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; $config{memmap}{consoleio} = $config{memmap}{serialio} if exists $config{memmap}{serialio}; foreach my $tag (qw ( size page_size serialio consoleio)) { $jh{memmap}{$tag} = $config{memmap}{$tag} if exists $config{memmap}{$tag}; } # 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 $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 $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 CSRs not included in verilog. my @removed_csrs; if (! $config{core}{timer_legal_en}) { push(@removed_csrs, $_) for qw (mitcnt0 mitbnd0 mitctl0 mitcnt1 mitbnd1 mitctl1); } # Collect fast interrupt enable. if (exists $config{core}{fast_interrupt_redirect}) { $jh{fast_interrupt_redirect} = $config{core}{fast_interrupt_redirect}; # meicpct CSR is not built if fast interrupt. push(@removed_csrs, 'meicpct') if $jh{fast_interrupt_redirect}; } # Remove CSRs not configured into verilog. delete $jh{csr}{$_} foreach @removed_csrs; # Collect zb extension configs $jh{enable_zbb} = $config{core}{bitmanip_zbb}; $jh{enable_zbs} = $config{core}{bitmanip_zbs}; $jh{enable_zba} = $config{core}{bitmanip_zba}; $jh{enable_zbc} = $config{core}{bitmanip_zbc}; $jh{enable_zbe} = $config{core}{bitmanip_zbe}; $jh{enable_zbf} = $config{core}{bitmanip_zbf}; $jh{enable_zbp} = $config{core}{bitmanip_zbp}; $jh{enable_zbr} = $config{core}{bitmanip_zbr}; # Collect pic configs. if (exists $config{pic}) { my %mem_mapped; collect_mem_mapped_regs($config{pic}, \%mem_mapped); $jh{'memory_mapped_registers'} = \%mem_mapped; } # Collect performance events. Uncomment when RTL ready. if (exists $config{perf_events}) { $jh{mmode_perf_events} = $config{perf_events}; } # Make atomic instructions illegal outside of DCCM. $jh{amo_illegal_outside_dccm} = "true"; # Make ld/st instructions trigger misaligned exceptions if base # address (value in rs1) and effective address refer to regions of # different types. $jh{effective_address_compatible_with_base} = "true"; # 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); }#}}} sub b2d {#{{{ my ($v) = @_; $v = oct("0b" . $v); return($v); }#}}} sub d2b {#{{{ my ($key,$v,$LEN) = @_; my $repeat; $v = sprintf "%b",$v; if (length($v)<$LEN) { $repeat=$LEN-length($v); $v="0"x$repeat.$v; } elsif (length($v)>$LEN) { die("d2b: parm $key value $v > len $LEN"); } return($v); }#}}} sub invalid_mask {#{{{ my ($m) = @_; if ($m =~ /^0x(0)*([137]?f+)$/) { return(0); } return(1); }#}}} sub b2h {#{{{ my ($bin) = @_; # Make input bit string a multiple of 4 $bin = substr("0000",length($bin)%4) . $bin if length($bin)%4; my ($hex, $nybble) = (""); while (length($bin)) { ($nybble,$bin) = (substr($bin,0,4), substr($bin,4)); $nybble = eval "0b$nybble"; $hex .= substr("0123456789ABCDEF", $nybble, 1); } return $hex; }#}}} # BHT index is a hash of the GHR and PC_HASH sub ghrhash{#{{{ my($btb_index_hi,$ghr_size) = @_; $btb_size = $btb_index_hi - 1; my $ghr_hi = $ghr_size - 1; my $ghr_lo = $btb_size; my $ghr_start = "{"; if($ghr_size > $btb_size){ return "{ghr[$ghr_hi:$ghr_lo], hashin[$btb_index_hi:2]^ghr[$ghr_lo-1:0]} // cf1"; } else { return "{hashin[$ghr_size+1:2]^ghr[$ghr_size-1:0]}// cf2"; } }#}}} sub dump_parms {#{{{ my ($hash) = @_; my ($bvalue, $blen, $upper); printf(FILE1 "typedef struct packed {\n"); foreach my $key (sort keys %$hash) { $bvalue=$hash->{$key}; $blen=length($bvalue); $upper=$key; $upper=~ tr/a-z/A-Z/; if ($blen==1) { printf(FILE1 "\tbit %-10s $upper;\n"); } else { printf(FILE1 "\tbit %-10s $upper;\n",sprintf("[%d:0]",$blen-1)); } } printf(FILE1 "} el2_param_t;\n\n"); my $bcat=""; my $parmcnt=0; foreach my $key (sort keys %$hash) { #printf("// $key = %s\n",$verilog_parms{$key}); $bcat.=$hash->{$key}; $parmcnt++; } my $bvalue=""; my $pcnt=0; my $delim=","; my $msb; printf(FILE2 "parameter el2_param_t pt = '{\n"); foreach my $key (sort keys %$hash) { $upper=$key; $upper=~ tr/a-z/A-Z/; $pcnt++; if ($pcnt==$parmcnt) { undef $delim; } if ($hash->{$key} eq "0") { $hash->{$key}="0000"; } $msb=substr($hash->{$key},0,4); # require upper 4b to be 0 if ($msb ne "0000") { die("parameter $upper upper 4b must be 0"); } printf(FILE2 "\t%-22s : %d\'h%-10s $delim\n",$upper,length($hash->{$key}),b2h($hash->{$key})); } printf(FILE2 "}\n"); printf(FILE2 "// parameter el2_param_t pt = %d'h%s\n",length($bcat),b2h($bcat)); }#}}} sub gen_default_linker_script {#{{{ open (FILE, ">$linkerfile") || die "Cannot open $linkerfile for writing $!\n"; print "$self: Writing $linkerfile\n"; print FILE "/*\n"; print_header(); my $io = "0xd0580000"; $io = $config{memmap}{serialio} if exists $config{memmap}{serialio}; my $iccm = ""; my $iccm_ctl = ""; if (exists $config{iccm} and $config{iccm}{iccm_enable} and $text_in_iccm) { my $sa = $config{iccm}{iccm_sadr}; my $ea = $config{iccm}{iccm_eadr}; $iccm = " . = $sa ;"; $iccm_ctl = " . = 0xfffffff0; .iccm.ctl . : { LONG($sa); LONG($ea) }" ; } my $sa = $config{memmap}{external_data}; my $dccm_ctl = ""; if (exists $config{dccm} and $config{dccm}{dccm_enable}) { $sa = $config{dccm}{dccm_sadr}; $dccm_ctl = " . = 0xfffffff8; .data.ctl : { LONG($sa); LONG(STACK) }" ; } my $data_loc = " . = $sa ;"; print FILE "*/\n"; print FILE <<"EOF"; OUTPUT_ARCH( "riscv" ) ENTRY(_start) SECTIONS { . = $config{reset_vec}; .text.init . : { *(.text.init) } $iccm .text . : { *(.text) } _end = .; . = $io; .data.io . : { *(.data.io) } $data_loc .data : ALIGN(0x800) { *(.*data) *(.rodata*)} .bss : {BSS_START = .; *(.*bss)} BSS_END = .; STACK = ALIGN(16) + 0x1000; $iccm_ctl $dccm_ctl } EOF close FILE; } #}}}