diff --git a/demo/jtag/.gitignore b/demo/jtag/.gitignore new file mode 100644 index 0000000..491b34c --- /dev/null +++ b/demo/jtag/.gitignore @@ -0,0 +1,3 @@ +build/ +obj_dir/ +gen/ \ No newline at end of file diff --git a/demo/jtag/Makefile b/demo/jtag/Makefile new file mode 100644 index 0000000..cd3b236 --- /dev/null +++ b/demo/jtag/Makefile @@ -0,0 +1,84 @@ +export RV_ROOT = ${PWD}/../.. +GCC_PREFIX = /opt/riscv/bin/riscv32-unknown-elf +GDB_PREFIX = /opt/riscv/bin/riscv32-unknown-elf-gdb + +ABI = -mabi=ilp32 -march=rv32imc + +DEMODIR = ${PWD} +BUILD_DIR = ${DEMODIR}/build +RV_SOC = ${RV_ROOT}/soc + +TEST = jtag + +ifdef debug + DEBUG_PLUS = +dumpon + VERILATOR_DEBUG = --trace +endif + +LINK = $(DEMODIR)/link.ld + +# CFLAGS for verilator generated Makefiles. Without -std=c++11 it complains for `auto` variables +CFLAGS += "-std=c++11" +# Optimization for better performance; alternative is nothing for slower runtime (faster compiles) +# -O2 for faster runtime (slower compiles), or -O for balance. +VERILATOR_MAKE_FLAGS = OPT_FAST="-Os" + +# Targets +all: clean verilator + +clean: + rm -rf build obj_dir + +swerv_define : + BUILD_PATH=${BUILD_DIR} PERLLIB=${RV_SOC} ${RV_SOC}/swerv.config -target=default -set build_axi4 + +##################### Verilog Builds ##################################### + +verilator-build: swerv_define + echo '`undef RV_ASSERT_ON' >> ${BUILD_DIR}/common_defines.vh + verilator --cc -CFLAGS ${CFLAGS} \ + $(BUILD_DIR)/common_defines.vh \ + $(BUILD_DIR)/el2_pdef.vh \ + -I${BUILD_DIR} \ + -Wno-WIDTH \ + -Wno-UNOPTFLAT \ + -F ${RV_SOC}/soc_top.mk \ + -F ${RV_SOC}/soc_sim.mk \ + $(RV_SOC)/soc_sim.sv \ + --top-module soc_sim -exe test_soc_sim.cpp --autoflush $(VERILATOR_DEBUG) + cp ${DEMODIR}/test_soc_sim.cpp obj_dir + $(MAKE) -j -e -C obj_dir/ -f Vsoc_sim.mk $(VERILATOR_MAKE_FLAGS) + +##################### Simulation Runs ##################################### + +verilator: program.hex verilator-build + cd build && ../obj_dir/Vsoc_sim ${DEBUG_PLUS} + +sim: + cd build && ../obj_dir/Vsoc_sim ${DEBUG_PLUS} + +##################### Test hex Build ##################################### + +program.hex: $(TEST).o $(LINK) + @echo Building $(TEST) + $(GCC_PREFIX)-gcc $(ABI) -Wl,-Map=$(BUILD_DIR)/$(TEST).map -lgcc -T$(LINK) -o $(BUILD_DIR)/$(TEST).bin $(BUILD_DIR)/$(TEST).o -nostartfiles $(TEST_LIBS) + $(GCC_PREFIX)-objcopy -O verilog $(BUILD_DIR)/$(TEST).bin $(BUILD_DIR)/program.hex + $(GCC_PREFIX)-objdump -S $(BUILD_DIR)/$(TEST).bin > $(BUILD_DIR)/$(TEST).dis + @echo Completed building $(TEST) + +%.o : %.s swerv_define + $(GCC_PREFIX)-cpp -g -I${BUILD_DIR} $< > $(BUILD_DIR)/$*.cpp.s + $(GCC_PREFIX)-as -g $(ABI) $(BUILD_DIR)/$*.cpp.s -o $(BUILD_DIR)/$@ + +##################### openocd ##################################### + +openocd: + openocd -f swerv.cfg + +gdb: + $(GDB_PREFIX) -x gdbinit + +help: + @echo Possible targets: verilator help clean all verilator-build program.hex + +.PHONY: help clean verilator \ No newline at end of file diff --git a/demo/jtag/Readmd.md b/demo/jtag/Readmd.md new file mode 100644 index 0000000..2b06cdd --- /dev/null +++ b/demo/jtag/Readmd.md @@ -0,0 +1,18 @@ +# jtag simulation + + +## start openocd + +`openocd -d -f swerv.cfg` + +## start gdb + +`/opt/riscv/bin/riscv32-unknown-elf-gdb -ex "target extended-remote :3333"` + +## quick start + +At demo/jtag/ + +1. `make all` +2. `make openocd` +3. `make gdb` \ No newline at end of file diff --git a/demo/jtag/gdbinit b/demo/jtag/gdbinit new file mode 100644 index 0000000..da9dc18 --- /dev/null +++ b/demo/jtag/gdbinit @@ -0,0 +1,3 @@ +set debug remote 1 +target extended-remote :3333 +set remotetimeout 5000 \ No newline at end of file diff --git a/demo/jtag/jtag.s b/demo/jtag/jtag.s new file mode 100644 index 0000000..50b49f1 --- /dev/null +++ b/demo/jtag/jtag.s @@ -0,0 +1,84 @@ +// 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. +// + +// Assembly code for Hello World +// Not using only ALU ops for creating the string + + +#include "defines.h" + +#define STDOUT 0xd0580000 + + +// Code to execute +.section .text +.global _start +_start: + + // Clear minstret + csrw minstret, zero + csrw minstreth, zero + + // Set up MTVEC - not expecting to use it though + li x1, RV_ICCM_SADR + csrw mtvec, x1 + + + // Enable Caches in MRAC + li x1, 0x5f555555 + csrw 0x7c0, x1 + + // Load string from hw_data + // and write to stdout address + + li x3, STDOUT + la x4, hw_data + +loop: + lb x5, 0(x4) + sb x5, 0(x3) + addi x4, x4, 1 + bnez x5, loop + + li x3, STDOUT + la x4, hw_data + +loop2: + lb x5, 0(x4) + sb x5, 0(x3) + addi x4, x4, 1 + bnez x5, loop2 + +loop3: + beq x0, x0, loop3 + +// Write 0xff to STDOUT for TB to terminate test. +_finish: + li x3, STDOUT + addi x5, x0, 0xff + sb x5, 0(x3) + beq x0, x0, _finish +.rept 100 + nop +.endr + +.global hw_data +.data +hw_data: +.ascii "----------------------------------\n" +.ascii "Hello World Colin.liang EL2@WDC !!\n" +.ascii "----------------------------------\n" +.byte 0 diff --git a/demo/jtag/link.ld b/demo/jtag/link.ld new file mode 100644 index 0000000..f6d03cc --- /dev/null +++ b/demo/jtag/link.ld @@ -0,0 +1,16 @@ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + +SECTIONS +{ + . = 0; + .text_init : { *(.text_init*) } + .text : { *(.text*) } + _end = .; + . = 0x4000; + .data : ALIGN(0x800) { *(.*data) *(.rodata*) STACK = ALIGN(16) + 0x2000; } + .bss : { *(.bss) } + . = 0xd0580000; + .data.io : { *(.data.io) } +} diff --git a/demo/jtag/soc.lpf b/demo/jtag/soc.lpf new file mode 100644 index 0000000..c6e36a6 --- /dev/null +++ b/demo/jtag/soc.lpf @@ -0,0 +1,32 @@ +LOCATE COMP "clk" SITE "P3"; +IOBUF PORT "clk" IO_TYPE=LVCMOS33; +FREQUENCY PORT "clk" 25 MHZ; + +LOCATE COMP "dbg_rst" SITE "N2"; +IOBUF PORT "dbg_rst" IO_TYPE=LVCMOS33; +FREQUENCY PORT "dbg_rst" 25 MHZ; + +LOCATE COMP "rst" SITE "N3"; +IOBUF PORT "rst" IO_TYPE=LVCMOS33; +FREQUENCY PORT "rst" 25 MHZ; + +LOCATE COMP "jtag_tck" SITE "T2"; +IOBUF PORT "jtag_tck" IO_TYPE=LVCMOS33; +FREQUENCY PORT "jtag_tck" 25 MHZ; + +LOCATE COMP "jtag_tms" SITE "T3"; +IOBUF PORT "jtag_tms" IO_TYPE=LVCMOS33; +FREQUENCY PORT "jtag_tms" 25 MHZ; + +LOCATE COMP "jtag_tdi" SITE "N4"; +IOBUF PORT "jtag_tdi" IO_TYPE=LVCMOS33; +FREQUENCY PORT "jtag_tdi" 25 MHZ; + +LOCATE COMP "jtag_trst_n" SITE "M3"; +IOBUF PORT "jtag_trst_n" IO_TYPE=LVCMOS33; +FREQUENCY PORT "jtag_trst_n" 25 MHZ; + + + +LOCATE COMP "jtag_tdo" SITE "M4"; +IOBUF PORT "jtag_tdo" IO_TYPE=LVCMOS33; diff --git a/demo/jtag/swerv.cfg b/demo/jtag/swerv.cfg new file mode 100644 index 0000000..1bb2fe9 --- /dev/null +++ b/demo/jtag/swerv.cfg @@ -0,0 +1,34 @@ +# "JTAG adapter" for simulation, exposed to OpenOCD through a TCP socket +# speaking the remote_bitbang protocol. The adapter is implemented as +# SystemVerilog DPI module. + +adapter driver remote_bitbang +remote_bitbang host localhost +remote_bitbang port 44853 + +# Target configuration for the riscv chip + +set _CHIPNAME riscv +set _TARGETNAME $_CHIPNAME.cpu + +jtag newtap $_CHIPNAME tap -irlen 5 -expected-id 0x1000008b +set _TARGETNAME $_CHIPNAME.tap +target create $_TARGETNAME riscv -chain-position $_TARGETNAME + +# Configure work area in on-chip SRAM +# $_TARGETNAME configure -work-area-phys 0x1000e000 -work-area-size 1000 -work-area-backup 0 + +riscv expose_csrs 1988 + +# Be verbose about GDB errors +gdb_report_data_abort enable +gdb_report_register_access_error enable + +# Increase timeouts in simulation +riscv set_command_timeout_sec 4200 + +# Conclude OpenOCD configuration +init + +# Halt the target +halt diff --git a/demo/jtag/synth.sh b/demo/jtag/synth.sh new file mode 100755 index 0000000..0434120 --- /dev/null +++ b/demo/jtag/synth.sh @@ -0,0 +1,83 @@ +#!/bin/bash + +# if [ $# -ne 1 -o ! -d "$1" ]; then +# echo "Usage: $0 " >&2 +# exit 1 +# fi + +set -ex + +PWD=$(pwd) +SOC=$PWD/../../soc +design=${1%/} + +YOSYS_COARSE=true +YOSYS_GLOBRST=false +YOSYS_SPLITNETS=false +TOP="soc_top" +RTL=$(cat ../../soc/soc_top.mk) + +rtl_files="" + + +rtl_files+=" /home/colin/develop/Cores-SweRV-EL2/demo/jtag/build/pd_defines.vh " +# rtl_files+=" /home/colin/develop/Cores-SweRV-EL2/demo/jtag/build/common_defines.vh " +# # rtl_files+=" /home/colin/develop/Cores-SweRV-EL2/demo/jtag/build/pic_map_auto.h " +# rtl_files+=" /home/colin/develop/Cores-SweRV-EL2/demo/jtag/build/el2_pdef.vh " +# rtl_files+=" /home/colin/develop/Cores-SweRV-EL2/demo/jtag/build/el2_param.vh " + +for src in $RTL; do + rtl_files="$rtl_files $SOC/$src" +done + +mkdir -p gen +rm -rf gen/* +mkdir gen/design + + +filelist="" +for file in $rtl_files; do + filelist="$filelist $file" +done +sv2v -Ibuild $filelist > gen/soc_top.v + +{ + # echo "read_verilog -sv -Igen/ gen/common_defines.vh" + # for file in $rtl_files; do + # echo "read_verilog -sv -I../../design/include $file" + # done + echo "read_verilog gen/soc_top.v" + + if test -n "$TOP"; then + echo "hierarchy -check -top $TOP" + else + echo "hierarchy -check" + fi + if $YOSYS_GLOBRST; then + # insertation of global reset (e.g. for FPGA cores) + echo "add -global_input globrst 1" + echo "proc -global_arst globrst" + fi + echo "synth -run coarse; opt -fine" + # echo "tee -o gen/brams.log memory_bram -rules scripts/brams.txt;;" + if ! $YOSYS_COARSE; then + echo "memory_map; techmap; opt; abc -dff; clean" + fi + if $YOSYS_SPLITNETS; then + # icarus verilog has a performance problems when there are + # dependencies between the bits of a long vector + echo "splitnets; clean" + fi + if $YOSYS_COARSE; then + echo "write_verilog -noexpr -noattr gen/synth.v" + else + echo "select -assert-none t:\$[!_]" + echo "write_verilog -noattr gen/synth.v" + fi + echo "synth_ecp5 -top $TOP -json gen/soc.json" + # echo "synth_xilinx -top $TOP" +} > gen/synth.ys + +yosys -v2 -l gen/synth.log gen/synth.ys + +nextpnr-ecp5 --25k --package CABGA381 --speed 6 --textcfg soc.cfg --lpf soc.lpf --freq 1 --json gen/soc.json diff --git a/demo/jtag/test_soc_sim.cpp b/demo/jtag/test_soc_sim.cpp new file mode 100644 index 0000000..11bb03f --- /dev/null +++ b/demo/jtag/test_soc_sim.cpp @@ -0,0 +1,65 @@ +// 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. +// +#include +#include +#include +#include +#include "Vsoc_sim.h" +#include "verilated.h" +#include "verilated_vcd_c.h" + + +vluint64_t main_time = 0; + +double sc_time_stamp () { + return main_time; +} + + +int main(int argc, char** argv) { + std::cout << "\nVerilatorTB: Start of sim\n" << std::endl; + + Verilated::commandArgs(argc, argv); + + Vsoc_sim* soc = new Vsoc_sim; + + // init trace dump + VerilatedVcdC* tfp = NULL; + +#if VM_TRACE + Verilated::traceEverOn(true); + tfp = new VerilatedVcdC; + soc->trace (tfp, 24); + tfp->open ("sim.vcd"); +#endif + // Simulate + while(!Verilated::gotFinish()){ +#if VM_TRACE + tfp->dump (main_time); +#endif + main_time += 5; + soc->core_clk = !soc->core_clk; + soc->eval(); + } + +#if VM_TRACE + tfp->close(); +#endif + + std::cout << "\nVerilatorTB: End of sim" << std::endl; + exit(EXIT_SUCCESS); + +} diff --git a/soc/JSON.pm b/soc/JSON.pm new file mode 100644 index 0000000..6fb7a90 --- /dev/null +++ b/soc/JSON.pm @@ -0,0 +1,2267 @@ +package JSON; + + +use strict; +use Carp (); +use base qw(Exporter); +@JSON::EXPORT = qw(from_json to_json jsonToObj objToJson encode_json decode_json); + +BEGIN { + $JSON::VERSION = '2.53'; + $JSON::DEBUG = 0 unless (defined $JSON::DEBUG); + $JSON::DEBUG = $ENV{ PERL_JSON_DEBUG } if exists $ENV{ PERL_JSON_DEBUG }; +} + +my $Module_XS = 'JSON::XS'; +my $Module_PP = 'JSON::PP'; +my $Module_bp = 'JSON::backportPP'; # included in JSON distribution +my $PP_Version = '2.27200'; +my $XS_Version = '2.27'; + + +# XS and PP common methods + +my @PublicMethods = qw/ + ascii latin1 utf8 pretty indent space_before space_after relaxed canonical allow_nonref + allow_blessed convert_blessed filter_json_object filter_json_single_key_object + shrink max_depth max_size encode decode decode_prefix allow_unknown +/; + +my @Properties = qw/ + ascii latin1 utf8 indent space_before space_after relaxed canonical allow_nonref + allow_blessed convert_blessed shrink max_depth max_size allow_unknown +/; + +my @XSOnlyMethods = qw//; # Currently nothing + +my @PPOnlyMethods = qw/ + indent_length sort_by + allow_singlequote allow_bignum loose allow_barekey escape_slash as_nonblessed +/; # JSON::PP specific + + +# used in _load_xs and _load_pp ($INSTALL_ONLY is not used currently) +my $_INSTALL_DONT_DIE = 1; # When _load_xs fails to load XS, don't die. +my $_INSTALL_ONLY = 2; # Don't call _set_methods() +my $_ALLOW_UNSUPPORTED = 0; +my $_UNIV_CONV_BLESSED = 0; +my $_USSING_bpPP = 0; + + +# Check the environment variable to decide worker module. + +unless ($JSON::Backend) { + $JSON::DEBUG and Carp::carp("Check used worker module..."); + + my $backend = exists $ENV{PERL_JSON_BACKEND} ? $ENV{PERL_JSON_BACKEND} : 1; + + if ($backend eq '1' or $backend =~ /JSON::XS\s*,\s*JSON::PP/) { + _load_xs($_INSTALL_DONT_DIE) or _load_pp(); + } + elsif ($backend eq '0' or $backend eq 'JSON::PP') { + _load_pp(); + } + elsif ($backend eq '2' or $backend eq 'JSON::XS') { + _load_xs(); + } + elsif ($backend eq 'JSON::backportPP') { + $_USSING_bpPP = 1; + _load_pp(); + } + else { + Carp::croak "The value of environmental variable 'PERL_JSON_BACKEND' is invalid."; + } +} + + +sub import { + my $pkg = shift; + my @what_to_export; + my $no_export; + + for my $tag (@_) { + if ($tag eq '-support_by_pp') { + if (!$_ALLOW_UNSUPPORTED++) { + JSON::Backend::XS + ->support_by_pp(@PPOnlyMethods) if ($JSON::Backend eq $Module_XS); + } + next; + } + elsif ($tag eq '-no_export') { + $no_export++, next; + } + elsif ( $tag eq '-convert_blessed_universally' ) { + eval q| + require B; + *UNIVERSAL::TO_JSON = sub { + my $b_obj = B::svref_2object( $_[0] ); + return $b_obj->isa('B::HV') ? { %{ $_[0] } } + : $b_obj->isa('B::AV') ? [ @{ $_[0] } ] + : undef + ; + } + | if ( !$_UNIV_CONV_BLESSED++ ); + next; + } + push @what_to_export, $tag; + } + + return if ($no_export); + + __PACKAGE__->export_to_level(1, $pkg, @what_to_export); +} + + +# OBSOLETED + +sub jsonToObj { + my $alternative = 'from_json'; + if (defined $_[0] and UNIVERSAL::isa($_[0], 'JSON')) { + shift @_; $alternative = 'decode'; + } + Carp::carp "'jsonToObj' will be obsoleted. Please use '$alternative' instead."; + return JSON::from_json(@_); +}; + +sub objToJson { + my $alternative = 'to_json'; + if (defined $_[0] and UNIVERSAL::isa($_[0], 'JSON')) { + shift @_; $alternative = 'encode'; + } + Carp::carp "'objToJson' will be obsoleted. Please use '$alternative' instead."; + JSON::to_json(@_); +}; + + +# INTERFACES + +sub to_json ($@) { + if ( + ref($_[0]) eq 'JSON' + or (@_ > 2 and $_[0] eq 'JSON') + ) { + Carp::croak "to_json should not be called as a method."; + } + my $json = new JSON; + + if (@_ == 2 and ref $_[1] eq 'HASH') { + my $opt = $_[1]; + for my $method (keys %$opt) { + $json->$method( $opt->{$method} ); + } + } + + $json->encode($_[0]); +} + + +sub from_json ($@) { + if ( ref($_[0]) eq 'JSON' or $_[0] eq 'JSON' ) { + Carp::croak "from_json should not be called as a method."; + } + my $json = new JSON; + + if (@_ == 2 and ref $_[1] eq 'HASH') { + my $opt = $_[1]; + for my $method (keys %$opt) { + $json->$method( $opt->{$method} ); + } + } + + return $json->decode( $_[0] ); +} + + +sub true { $JSON::true } + +sub false { $JSON::false } + +sub null { undef; } + + +sub require_xs_version { $XS_Version; } + +sub backend { + my $proto = shift; + $JSON::Backend; +} + +#*module = *backend; + + +sub is_xs { + return $_[0]->module eq $Module_XS; +} + + +sub is_pp { + return not $_[0]->xs; +} + + +sub pureperl_only_methods { @PPOnlyMethods; } + + +sub property { + my ($self, $name, $value) = @_; + + if (@_ == 1) { + my %props; + for $name (@Properties) { + my $method = 'get_' . $name; + if ($name eq 'max_size') { + my $value = $self->$method(); + $props{$name} = $value == 1 ? 0 : $value; + next; + } + $props{$name} = $self->$method(); + } + return \%props; + } + elsif (@_ > 3) { + Carp::croak('property() can take only the option within 2 arguments.'); + } + elsif (@_ == 2) { + if ( my $method = $self->can('get_' . $name) ) { + if ($name eq 'max_size') { + my $value = $self->$method(); + return $value == 1 ? 0 : $value; + } + $self->$method(); + } + } + else { + $self->$name($value); + } + +} + + + +# INTERNAL + +sub _load_xs { + my $opt = shift; + + $JSON::DEBUG and Carp::carp "Load $Module_XS."; + + # if called after install module, overload is disable.... why? + JSON::Boolean::_overrride_overload($Module_XS); + JSON::Boolean::_overrride_overload($Module_PP); + + eval qq| + use $Module_XS $XS_Version (); + |; + + if ($@) { + if (defined $opt and $opt & $_INSTALL_DONT_DIE) { + $JSON::DEBUG and Carp::carp "Can't load $Module_XS...($@)"; + return 0; + } + Carp::croak $@; + } + + unless (defined $opt and $opt & $_INSTALL_ONLY) { + _set_module( $JSON::Backend = $Module_XS ); + my $data = join("", ); # this code is from Jcode 2.xx. + close(DATA); + eval $data; + JSON::Backend::XS->init; + } + + return 1; +}; + + +sub _load_pp { + my $opt = shift; + my $backend = $_USSING_bpPP ? $Module_bp : $Module_PP; + + $JSON::DEBUG and Carp::carp "Load $backend."; + + # if called after install module, overload is disable.... why? + JSON::Boolean::_overrride_overload($Module_XS); + JSON::Boolean::_overrride_overload($backend); + + if ( $_USSING_bpPP ) { + eval qq| require $backend |; + } + else { + eval qq| use $backend $PP_Version () |; + } + + if ($@) { + if ( $backend eq $Module_PP ) { + $JSON::DEBUG and Carp::carp "Can't load $Module_PP ($@), so try to load $Module_bp"; + $_USSING_bpPP++; + $backend = $Module_bp; + JSON::Boolean::_overrride_overload($backend); + local $^W; # if PP installed but invalid version, backportPP redifines methods. + eval qq| require $Module_bp |; + } + Carp::croak $@ if $@; + } + + unless (defined $opt and $opt & $_INSTALL_ONLY) { + _set_module( $JSON::Backend = $Module_PP ); # even if backportPP, set $Backend with 'JSON::PP' + JSON::Backend::PP->init; + } +}; + + +sub _set_module { + return if defined $JSON::true; + + my $module = shift; + + local $^W; + no strict qw(refs); + + $JSON::true = ${"$module\::true"}; + $JSON::false = ${"$module\::false"}; + + push @JSON::ISA, $module; + push @{"$module\::Boolean::ISA"}, qw(JSON::Boolean); + + *{"JSON::is_bool"} = \&{"$module\::is_bool"}; + + for my $method ($module eq $Module_XS ? @PPOnlyMethods : @XSOnlyMethods) { + *{"JSON::$method"} = sub { + Carp::carp("$method is not supported in $module."); + $_[0]; + }; + } + + return 1; +} + + + +# +# JSON Boolean +# + +package JSON::Boolean; + +my %Installed; + +sub _overrride_overload { + return if ($Installed{ $_[0] }++); + + my $boolean = $_[0] . '::Boolean'; + + eval sprintf(q| + package %s; + use overload ( + '""' => sub { ${$_[0]} == 1 ? 'true' : 'false' }, + 'eq' => sub { + my ($obj, $op) = ref ($_[0]) ? ($_[0], $_[1]) : ($_[1], $_[0]); + if ($op eq 'true' or $op eq 'false') { + return "$obj" eq 'true' ? 'true' eq $op : 'false' eq $op; + } + else { + return $obj ? 1 == $op : 0 == $op; + } + }, + ); + |, $boolean); + + if ($@) { Carp::croak $@; } + + return 1; +} + + +# +# Helper classes for Backend Module (PP) +# + +package JSON::Backend::PP; + +sub init { + local $^W; + no strict qw(refs); # this routine may be called after JSON::Backend::XS init was called. + *{"JSON::decode_json"} = \&{"JSON::PP::decode_json"}; + *{"JSON::encode_json"} = \&{"JSON::PP::encode_json"}; + *{"JSON::PP::is_xs"} = sub { 0 }; + *{"JSON::PP::is_pp"} = sub { 1 }; + return 1; +} + +# +# To save memory, the below lines are read only when XS backend is used. +# + +package JSON; + +1; +__DATA__ + + +# +# Helper classes for Backend Module (XS) +# + +package JSON::Backend::XS; + +use constant INDENT_LENGTH_FLAG => 15 << 12; + +use constant UNSUPPORTED_ENCODE_FLAG => { + ESCAPE_SLASH => 0x00000010, + ALLOW_BIGNUM => 0x00000020, + AS_NONBLESSED => 0x00000040, + EXPANDED => 0x10000000, # for developer's +}; + +use constant UNSUPPORTED_DECODE_FLAG => { + LOOSE => 0x00000001, + ALLOW_BIGNUM => 0x00000002, + ALLOW_BAREKEY => 0x00000004, + ALLOW_SINGLEQUOTE => 0x00000008, + EXPANDED => 0x20000000, # for developer's +}; + + +sub init { + local $^W; + no strict qw(refs); + *{"JSON::decode_json"} = \&{"JSON::XS::decode_json"}; + *{"JSON::encode_json"} = \&{"JSON::XS::encode_json"}; + *{"JSON::XS::is_xs"} = sub { 1 }; + *{"JSON::XS::is_pp"} = sub { 0 }; + return 1; +} + + +sub support_by_pp { + my ($class, @methods) = @_; + + local $^W; + no strict qw(refs); + + my $JSON_XS_encode_orignal = \&JSON::XS::encode; + my $JSON_XS_decode_orignal = \&JSON::XS::decode; + my $JSON_XS_incr_parse_orignal = \&JSON::XS::incr_parse; + + *JSON::XS::decode = \&JSON::Backend::XS::Supportable::_decode; + *JSON::XS::encode = \&JSON::Backend::XS::Supportable::_encode; + *JSON::XS::incr_parse = \&JSON::Backend::XS::Supportable::_incr_parse; + + *{JSON::XS::_original_decode} = $JSON_XS_decode_orignal; + *{JSON::XS::_original_encode} = $JSON_XS_encode_orignal; + *{JSON::XS::_original_incr_parse} = $JSON_XS_incr_parse_orignal; + + push @JSON::Backend::XS::Supportable::ISA, 'JSON'; + + my $pkg = 'JSON::Backend::XS::Supportable'; + + *{JSON::new} = sub { + my $proto = new JSON::XS; $$proto = 0; + bless $proto, $pkg; + }; + + + for my $method (@methods) { + my $flag = uc($method); + my $type |= (UNSUPPORTED_ENCODE_FLAG->{$flag} || 0); + $type |= (UNSUPPORTED_DECODE_FLAG->{$flag} || 0); + + next unless($type); + + $pkg->_make_unsupported_method($method => $type); + } + + push @{"JSON::XS::Boolean::ISA"}, qw(JSON::PP::Boolean); + push @{"JSON::PP::Boolean::ISA"}, qw(JSON::Boolean); + + $JSON::DEBUG and Carp::carp("set -support_by_pp mode."); + + return 1; +} + + + + +# +# Helper classes for XS +# + +package JSON::Backend::XS::Supportable; + +$Carp::Internal{'JSON::Backend::XS::Supportable'} = 1; + +sub _make_unsupported_method { + my ($pkg, $method, $type) = @_; + + local $^W; + no strict qw(refs); + + *{"$pkg\::$method"} = sub { + local $^W; + if (defined $_[1] ? $_[1] : 1) { + ${$_[0]} |= $type; + } + else { + ${$_[0]} &= ~$type; + } + $_[0]; + }; + + *{"$pkg\::get_$method"} = sub { + ${$_[0]} & $type ? 1 : ''; + }; + +} + + +sub _set_for_pp { + JSON::_load_pp( $_INSTALL_ONLY ); + + my $type = shift; + my $pp = new JSON::PP; + my $prop = $_[0]->property; + + for my $name (keys %$prop) { + $pp->$name( $prop->{$name} ? $prop->{$name} : 0 ); + } + + my $unsupported = $type eq 'encode' ? JSON::Backend::XS::UNSUPPORTED_ENCODE_FLAG + : JSON::Backend::XS::UNSUPPORTED_DECODE_FLAG; + my $flags = ${$_[0]} || 0; + + for my $name (keys %$unsupported) { + next if ($name eq 'EXPANDED'); # for developer's + my $enable = ($flags & $unsupported->{$name}) ? 1 : 0; + my $method = lc $name; + $pp->$method($enable); + } + + $pp->indent_length( $_[0]->get_indent_length ); + + return $pp; +} + +sub _encode { # using with PP encod + if (${$_[0]}) { + _set_for_pp('encode' => @_)->encode($_[1]); + } + else { + $_[0]->_original_encode( $_[1] ); + } +} + + +sub _decode { # if unsupported-flag is set, use PP + if (${$_[0]}) { + _set_for_pp('decode' => @_)->decode($_[1]); + } + else { + $_[0]->_original_decode( $_[1] ); + } +} + + +sub decode_prefix { # if unsupported-flag is set, use PP + _set_for_pp('decode' => @_)->decode_prefix($_[1]); +} + + +sub _incr_parse { + if (${$_[0]}) { + _set_for_pp('decode' => @_)->incr_parse($_[1]); + } + else { + $_[0]->_original_incr_parse( $_[1] ); + } +} + + +sub get_indent_length { + ${$_[0]} << 4 >> 16; +} + + +sub indent_length { + my $length = $_[1]; + + if (!defined $length or $length > 15 or $length < 0) { + Carp::carp "The acceptable range of indent_length() is 0 to 15."; + } + else { + local $^W; + $length <<= 12; + ${$_[0]} &= ~ JSON::Backend::XS::INDENT_LENGTH_FLAG; + ${$_[0]} |= $length; + *JSON::XS::encode = \&JSON::Backend::XS::Supportable::_encode; + } + + $_[0]; +} + + +1; +__END__ + +=head1 NAME + +JSON - JSON (JavaScript Object Notation) encoder/decoder + +=head1 SYNOPSIS + + use JSON; # imports encode_json, decode_json, to_json and from_json. + + # simple and fast interfaces (expect/generate UTF-8) + + $utf8_encoded_json_text = encode_json $perl_hash_or_arrayref; + $perl_hash_or_arrayref = decode_json $utf8_encoded_json_text; + + # OO-interface + + $json = JSON->new->allow_nonref; + + $json_text = $json->encode( $perl_scalar ); + $perl_scalar = $json->decode( $json_text ); + + $pretty_printed = $json->pretty->encode( $perl_scalar ); # pretty-printing + + # If you want to use PP only support features, call with '-support_by_pp' + # When XS unsupported feature is enable, using PP (de|en)code instead of XS ones. + + use JSON -support_by_pp; + + # option-acceptable interfaces (expect/generate UNICODE by default) + + $json_text = to_json( $perl_scalar, { ascii => 1, pretty => 1 } ); + $perl_scalar = from_json( $json_text, { utf8 => 1 } ); + + # Between (en|de)code_json and (to|from)_json, if you want to write + # a code which communicates to an outer world (encoded in UTF-8), + # recommend to use (en|de)code_json. + +=head1 VERSION + + 2.53 + +This version is compatible with JSON::XS B<2.27> and later. + + +=head1 NOTE + +JSON::PP was inculded in C distribution. +It comes to be a perl core module in Perl 5.14. +And L will be split away it. + +C distribution will inculde yet another JSON::PP modules. +They are JSNO::backportPP and so on. JSON.pm should work as it did at all. + +=head1 DESCRIPTION + + ************************** CAUTION ******************************** + * This is 'JSON module version 2' and there are many differences * + * to version 1.xx * + * Please check your applications useing old version. * + * See to 'INCOMPATIBLE CHANGES TO OLD VERSION' * + ******************************************************************* + +JSON (JavaScript Object Notation) is a simple data format. +See to L and C(L). + +This module converts Perl data structures to JSON and vice versa using either +L or L. + +JSON::XS is the fastest and most proper JSON module on CPAN which must be +compiled and installed in your environment. +JSON::PP is a pure-Perl module which is bundled in this distribution and +has a strong compatibility to JSON::XS. + +This module try to use JSON::XS by default and fail to it, use JSON::PP instead. +So its features completely depend on JSON::XS or JSON::PP. + +See to L. + +To distinguish the module name 'JSON' and the format type JSON, +the former is quoted by CEE (its results vary with your using media), +and the latter is left just as it is. + +Module name : C + +Format type : JSON + +=head2 FEATURES + +=over + +=item * correct unicode handling + +This module (i.e. backend modules) knows how to handle Unicode, documents +how and when it does so, and even documents what "correct" means. + +Even though there are limitations, this feature is available since Perl version 5.6. + +JSON::XS requires Perl 5.8.2 (but works correctly in 5.8.8 or later), so in older versions +C sholud call JSON::PP as the backend which can be used since Perl 5.005. + +With Perl 5.8.x JSON::PP works, but from 5.8.0 to 5.8.2, because of a Perl side problem, +JSON::PP works slower in the versions. And in 5.005, the Unicode handling is not available. +See to L for more information. + +See also to L +and L. + + +=item * round-trip integrity + +When you serialise a perl data structure using only data types supported +by JSON and Perl, the deserialised data structure is identical on the Perl +level. (e.g. the string "2.0" doesn't suddenly become "2" just because +it looks like a number). There I minor exceptions to this, read the +L section below to learn about those. + + +=item * strict checking of JSON correctness + +There is no guessing, no generating of illegal JSON texts by default, +and only JSON is accepted as input by default (the latter is a security +feature). + +See to L and L. + +=item * fast + +This module returns a JSON::XS object itself if available. +Compared to other JSON modules and other serialisers such as Storable, +JSON::XS usually compares favourably in terms of speed, too. + +If not available, C returns a JSON::PP object instead of JSON::XS and +it is very slow as pure-Perl. + +=item * simple to use + +This module has both a simple functional interface as well as an +object oriented interface interface. + +=item * reasonably versatile output formats + +You can choose between the most compact guaranteed-single-line format possible +(nice for simple line-based protocols), a pure-ASCII format (for when your transport +is not 8-bit clean, still supports the whole Unicode range), or a pretty-printed +format (for when you want to read that stuff). Or you can combine those features +in whatever way you like. + +=back + +=head1 FUNCTIONAL INTERFACE + +Some documents are copied and modified from L. +C and C are additional functions. + +=head2 encode_json + + $json_text = encode_json $perl_scalar + +Converts the given Perl data structure to a UTF-8 encoded, binary string. + +This function call is functionally identical to: + + $json_text = JSON->new->utf8->encode($perl_scalar) + +=head2 decode_json + + $perl_scalar = decode_json $json_text + +The opposite of C: expects an UTF-8 (binary) string and tries +to parse that as an UTF-8 encoded JSON text, returning the resulting +reference. + +This function call is functionally identical to: + + $perl_scalar = JSON->new->utf8->decode($json_text) + + +=head2 to_json + + $json_text = to_json($perl_scalar) + +Converts the given Perl data structure to a json string. + +This function call is functionally identical to: + + $json_text = JSON->new->encode($perl_scalar) + +Takes a hash reference as the second. + + $json_text = to_json($perl_scalar, $flag_hashref) + +So, + + $json_text = to_json($perl_scalar, {utf8 => 1, pretty => 1}) + +equivalent to: + + $json_text = JSON->new->utf8(1)->pretty(1)->encode($perl_scalar) + +If you want to write a modern perl code which communicates to outer world, +you should use C (supposed that JSON data are encoded in UTF-8). + +=head2 from_json + + $perl_scalar = from_json($json_text) + +The opposite of C: expects a json string and tries +to parse it, returning the resulting reference. + +This function call is functionally identical to: + + $perl_scalar = JSON->decode($json_text) + +Takes a hash reference as the second. + + $perl_scalar = from_json($json_text, $flag_hashref) + +So, + + $perl_scalar = from_json($json_text, {utf8 => 1}) + +equivalent to: + + $perl_scalar = JSON->new->utf8(1)->decode($json_text) + +If you want to write a modern perl code which communicates to outer world, +you should use C (supposed that JSON data are encoded in UTF-8). + +=head2 JSON::is_bool + + $is_boolean = JSON::is_bool($scalar) + +Returns true if the passed scalar represents either JSON::true or +JSON::false, two constants that act like C<1> and C<0> respectively +and are also used to represent JSON C and C in Perl strings. + +=head2 JSON::true + +Returns JSON true value which is blessed object. +It C JSON::Boolean object. + +=head2 JSON::false + +Returns JSON false value which is blessed object. +It C JSON::Boolean object. + +=head2 JSON::null + +Returns C. + +See L, below, for more information on how JSON values are mapped to +Perl. + +=head1 HOW DO I DECODE A DATA FROM OUTER AND ENCODE TO OUTER + +This section supposes that your perl vresion is 5.8 or later. + +If you know a JSON text from an outer world - a network, a file content, and so on, +is encoded in UTF-8, you should use C or C module object +with C enable. And the decoded result will contain UNICODE characters. + + # from network + my $json = JSON->new->utf8; + my $json_text = CGI->new->param( 'json_data' ); + my $perl_scalar = $json->decode( $json_text ); + + # from file content + local $/; + open( my $fh, '<', 'json.data' ); + $json_text = <$fh>; + $perl_scalar = decode_json( $json_text ); + +If an outer data is not encoded in UTF-8, firstly you should C it. + + use Encode; + local $/; + open( my $fh, '<', 'json.data' ); + my $encoding = 'cp932'; + my $unicode_json_text = decode( $encoding, <$fh> ); # UNICODE + + # or you can write the below code. + # + # open( my $fh, "<:encoding($encoding)", 'json.data' ); + # $unicode_json_text = <$fh>; + +In this case, C<$unicode_json_text> is of course UNICODE string. +So you B use C nor C module object with C enable. +Instead of them, you use C module object with C disable or C. + + $perl_scalar = $json->utf8(0)->decode( $unicode_json_text ); + # or + $perl_scalar = from_json( $unicode_json_text ); + +Or C and C: + + $perl_scalar = decode_json( encode( 'utf8', $unicode_json_text ) ); + # this way is not efficient. + +And now, you want to convert your C<$perl_scalar> into JSON data and +send it to an outer world - a network or a file content, and so on. + +Your data usually contains UNICODE strings and you want the converted data to be encoded +in UTF-8, you should use C or C module object with C enable. + + print encode_json( $perl_scalar ); # to a network? file? or display? + # or + print $json->utf8->encode( $perl_scalar ); + +If C<$perl_scalar> does not contain UNICODE but C<$encoding>-encoded strings +for some reason, then its characters are regarded as B for perl +(because it does not concern with your $encoding). +You B use C nor C module object with C enable. +Instead of them, you use C module object with C disable or C. +Note that the resulted text is a UNICODE string but no problem to print it. + + # $perl_scalar contains $encoding encoded string values + $unicode_json_text = $json->utf8(0)->encode( $perl_scalar ); + # or + $unicode_json_text = to_json( $perl_scalar ); + # $unicode_json_text consists of characters less than 0x100 + print $unicode_json_text; + +Or C all string values and C: + + $perl_scalar->{ foo } = decode( $encoding, $perl_scalar->{ foo } ); + # ... do it to each string values, then encode_json + $json_text = encode_json( $perl_scalar ); + +This method is a proper way but probably not efficient. + +See to L, L. + + +=head1 COMMON OBJECT-ORIENTED INTERFACE + +=head2 new + + $json = new JSON + +Returns a new C object inherited from either JSON::XS or JSON::PP +that can be used to de/encode JSON strings. + +All boolean flags described below are by default I. + +The mutators for flags all return the JSON object again and thus calls can +be chained: + + my $json = JSON->new->utf8->space_after->encode({a => [1,2]}) + => {"a": [1, 2]} + +=head2 ascii + + $json = $json->ascii([$enable]) + + $enabled = $json->get_ascii + +If $enable is true (or missing), then the encode method will not generate characters outside +the code range 0..127. Any Unicode characters outside that range will be escaped using either +a single \uXXXX or a double \uHHHH\uLLLLL escape sequence, as per RFC4627. + +If $enable is false, then the encode method will not escape Unicode characters unless +required by the JSON syntax or other flags. This results in a faster and more compact format. + +This feature depends on the used Perl version and environment. + +See to L if the backend is PP. + + JSON->new->ascii(1)->encode([chr 0x10401]) + => ["\ud801\udc01"] + +=head2 latin1 + + $json = $json->latin1([$enable]) + + $enabled = $json->get_latin1 + +If $enable is true (or missing), then the encode method will encode the resulting JSON +text as latin1 (or iso-8859-1), escaping any characters outside the code range 0..255. + +If $enable is false, then the encode method will not escape Unicode characters +unless required by the JSON syntax or other flags. + + JSON->new->latin1->encode (["\x{89}\x{abc}"] + => ["\x{89}\\u0abc"] # (perl syntax, U+abc escaped, U+89 not) + +=head2 utf8 + + $json = $json->utf8([$enable]) + + $enabled = $json->get_utf8 + +If $enable is true (or missing), then the encode method will encode the JSON result +into UTF-8, as required by many protocols, while the decode method expects to be handled +an UTF-8-encoded string. Please note that UTF-8-encoded strings do not contain any +characters outside the range 0..255, they are thus useful for bytewise/binary I/O. + +In future versions, enabling this option might enable autodetection of the UTF-16 and UTF-32 +encoding families, as described in RFC4627. + +If $enable is false, then the encode method will return the JSON string as a (non-encoded) +Unicode string, while decode expects thus a Unicode string. Any decoding or encoding +(e.g. to UTF-8 or UTF-16) needs to be done yourself, e.g. using the Encode module. + + +Example, output UTF-16BE-encoded JSON: + + use Encode; + $jsontext = encode "UTF-16BE", JSON::XS->new->encode ($object); + +Example, decode UTF-32LE-encoded JSON: + + use Encode; + $object = JSON::XS->new->decode (decode "UTF-32LE", $jsontext); + +See to L if the backend is PP. + + +=head2 pretty + + $json = $json->pretty([$enable]) + +This enables (or disables) all of the C, C and +C (and in the future possibly more) flags in one call to +generate the most readable (or most compact) form possible. + +Equivalent to: + + $json->indent->space_before->space_after + +The indent space length is three and JSON::XS cannot change the indent +space length. + +=head2 indent + + $json = $json->indent([$enable]) + + $enabled = $json->get_indent + +If C<$enable> is true (or missing), then the C method will use a multiline +format as output, putting every array member or object/hash key-value pair +into its own line, identing them properly. + +If C<$enable> is false, no newlines or indenting will be produced, and the +resulting JSON text is guarenteed not to contain any C. + +This setting has no effect when decoding JSON texts. + +The indent space length is three. +With JSON::PP, you can also access C to change indent space length. + + +=head2 space_before + + $json = $json->space_before([$enable]) + + $enabled = $json->get_space_before + +If C<$enable> is true (or missing), then the C method will add an extra +optional space before the C<:> separating keys from values in JSON objects. + +If C<$enable> is false, then the C method will not add any extra +space at those places. + +This setting has no effect when decoding JSON texts. + +Example, space_before enabled, space_after and indent disabled: + + {"key" :"value"} + + +=head2 space_after + + $json = $json->space_after([$enable]) + + $enabled = $json->get_space_after + +If C<$enable> is true (or missing), then the C method will add an extra +optional space after the C<:> separating keys from values in JSON objects +and extra whitespace after the C<,> separating key-value pairs and array +members. + +If C<$enable> is false, then the C method will not add any extra +space at those places. + +This setting has no effect when decoding JSON texts. + +Example, space_before and indent disabled, space_after enabled: + + {"key": "value"} + + +=head2 relaxed + + $json = $json->relaxed([$enable]) + + $enabled = $json->get_relaxed + +If C<$enable> is true (or missing), then C will accept some +extensions to normal JSON syntax (see below). C will not be +affected in anyway. I. I suggest only to use this option to +parse application-specific files written by humans (configuration files, +resource files etc.) + +If C<$enable> is false (the default), then C will only accept +valid JSON texts. + +Currently accepted extensions are: + +=over 4 + +=item * list items can have an end-comma + +JSON I array elements and key-value pairs with commas. This +can be annoying if you write JSON texts manually and want to be able to +quickly append elements, so this extension accepts comma at the end of +such items not just between them: + + [ + 1, + 2, <- this comma not normally allowed + ] + { + "k1": "v1", + "k2": "v2", <- this comma not normally allowed + } + +=item * shell-style '#'-comments + +Whenever JSON allows whitespace, shell-style comments are additionally +allowed. They are terminated by the first carriage-return or line-feed +character, after which more white-space and comments are allowed. + + [ + 1, # this comment not allowed in JSON + # neither this one... + ] + +=back + + +=head2 canonical + + $json = $json->canonical([$enable]) + + $enabled = $json->get_canonical + +If C<$enable> is true (or missing), then the C method will output JSON objects +by sorting their keys. This is adding a comparatively high overhead. + +If C<$enable> is false, then the C method will output key-value +pairs in the order Perl stores them (which will likely change between runs +of the same script). + +This option is useful if you want the same data structure to be encoded as +the same JSON text (given the same overall settings). If it is disabled, +the same hash might be encoded differently even if contains the same data, +as key-value pairs have no inherent ordering in Perl. + +This setting has no effect when decoding JSON texts. + +=head2 allow_nonref + + $json = $json->allow_nonref([$enable]) + + $enabled = $json->get_allow_nonref + +If C<$enable> is true (or missing), then the C method can convert a +non-reference into its corresponding string, number or null JSON value, +which is an extension to RFC4627. Likewise, C will accept those JSON +values instead of croaking. + +If C<$enable> is false, then the C method will croak if it isn't +passed an arrayref or hashref, as JSON texts must either be an object +or array. Likewise, C will croak if given something that is not a +JSON object or array. + + JSON->new->allow_nonref->encode ("Hello, World!") + => "Hello, World!" + +=head2 allow_unknown + + $json = $json->allow_unknown ([$enable]) + + $enabled = $json->get_allow_unknown + +If $enable is true (or missing), then "encode" will *not* throw an +exception when it encounters values it cannot represent in JSON (for +example, filehandles) but instead will encode a JSON "null" value. +Note that blessed objects are not included here and are handled +separately by c. + +If $enable is false (the default), then "encode" will throw an +exception when it encounters anything it cannot encode as JSON. + +This option does not affect "decode" in any way, and it is +recommended to leave it off unless you know your communications +partner. + +=head2 allow_blessed + + $json = $json->allow_blessed([$enable]) + + $enabled = $json->get_allow_blessed + +If C<$enable> is true (or missing), then the C method will not +barf when it encounters a blessed reference. Instead, the value of the +B option will decide whether C (C +disabled or no C method found) or a representation of the +object (C enabled and C method found) is being +encoded. Has no effect on C. + +If C<$enable> is false (the default), then C will throw an +exception when it encounters a blessed object. + + +=head2 convert_blessed + + $json = $json->convert_blessed([$enable]) + + $enabled = $json->get_convert_blessed + +If C<$enable> is true (or missing), then C, upon encountering a +blessed object, will check for the availability of the C method +on the object's class. If found, it will be called in scalar context +and the resulting scalar will be encoded instead of the object. If no +C method is found, the value of C will decide what +to do. + +The C method may safely call die if it wants. If C +returns other blessed objects, those will be handled in the same +way. C must take care of not causing an endless recursion cycle +(== crash) in this case. The name of C was chosen because other +methods called by the Perl core (== not by the user of the object) are +usually in upper case letters and to avoid collisions with the C +function or method. + +This setting does not yet influence C in any way. + +If C<$enable> is false, then the C setting will decide what +to do when a blessed object is found. + +=over + +=item convert_blessed_universally mode + +If use C with C<-convert_blessed_universally>, the C +subroutine is defined as the below code: + + *UNIVERSAL::TO_JSON = sub { + my $b_obj = B::svref_2object( $_[0] ); + return $b_obj->isa('B::HV') ? { %{ $_[0] } } + : $b_obj->isa('B::AV') ? [ @{ $_[0] } ] + : undef + ; + } + +This will cause that C method converts simple blessed objects into +JSON objects as non-blessed object. + + JSON -convert_blessed_universally; + $json->allow_blessed->convert_blessed->encode( $blessed_object ) + +This feature is experimental and may be removed in the future. + +=back + +=head2 filter_json_object + + $json = $json->filter_json_object([$coderef]) + +When C<$coderef> is specified, it will be called from C each +time it decodes a JSON object. The only argument passed to the coderef +is a reference to the newly-created hash. If the code references returns +a single scalar (which need not be a reference), this value +(i.e. a copy of that scalar to avoid aliasing) is inserted into the +deserialised data structure. If it returns an empty list +(NOTE: I C, which is a valid scalar), the original deserialised +hash will be inserted. This setting can slow down decoding considerably. + +When C<$coderef> is omitted or undefined, any existing callback will +be removed and C will not change the deserialised hash in any +way. + +Example, convert all JSON objects into the integer 5: + + my $js = JSON->new->filter_json_object (sub { 5 }); + # returns [5] + $js->decode ('[{}]'); # the given subroutine takes a hash reference. + # throw an exception because allow_nonref is not enabled + # so a lone 5 is not allowed. + $js->decode ('{"a":1, "b":2}'); + + +=head2 filter_json_single_key_object + + $json = $json->filter_json_single_key_object($key [=> $coderef]) + +Works remotely similar to C, but is only called for +JSON objects having a single key named C<$key>. + +This C<$coderef> is called before the one specified via +C, if any. It gets passed the single value in the JSON +object. If it returns a single value, it will be inserted into the data +structure. If it returns nothing (not even C but the empty list), +the callback from C will be called next, as if no +single-key callback were specified. + +If C<$coderef> is omitted or undefined, the corresponding callback will be +disabled. There can only ever be one callback for a given key. + +As this callback gets called less often then the C +one, decoding speed will not usually suffer as much. Therefore, single-key +objects make excellent targets to serialise Perl objects into, especially +as single-key JSON objects are as close to the type-tagged value concept +as JSON gets (it's basically an ID/VALUE tuple). Of course, JSON does not +support this in any way, so you need to make sure your data never looks +like a serialised Perl hash. + +Typical names for the single object key are C<__class_whatever__>, or +C<$__dollars_are_rarely_used__$> or C<}ugly_brace_placement>, or even +things like C<__class_md5sum(classname)__>, to reduce the risk of clashing +with real hashes. + +Example, decode JSON objects of the form C<< { "__widget__" => } >> +into the corresponding C<< $WIDGET{} >> object: + + # return whatever is in $WIDGET{5}: + JSON + ->new + ->filter_json_single_key_object (__widget__ => sub { + $WIDGET{ $_[0] } + }) + ->decode ('{"__widget__": 5') + + # this can be used with a TO_JSON method in some "widget" class + # for serialisation to json: + sub WidgetBase::TO_JSON { + my ($self) = @_; + + unless ($self->{id}) { + $self->{id} = ..get..some..id..; + $WIDGET{$self->{id}} = $self; + } + + { __widget__ => $self->{id} } + } + + +=head2 shrink + + $json = $json->shrink([$enable]) + + $enabled = $json->get_shrink + +With JSON::XS, this flag resizes strings generated by either +C or C to their minimum size possible. This can save +memory when your JSON texts are either very very long or you have many +short strings. It will also try to downgrade any strings to octet-form +if possible: perl stores strings internally either in an encoding called +UTF-X or in octet-form. The latter cannot store everything but uses less +space in general (and some buggy Perl or C code might even rely on that +internal representation being used). + +With JSON::PP, it is noop about resizing strings but tries +C to the returned string by C. See to L. + +See to L and L. + +=head2 max_depth + + $json = $json->max_depth([$maximum_nesting_depth]) + + $max_depth = $json->get_max_depth + +Sets the maximum nesting level (default C<512>) accepted while encoding +or decoding. If a higher nesting level is detected in JSON text or a Perl +data structure, then the encoder and decoder will stop and croak at that +point. + +Nesting level is defined by number of hash- or arrayrefs that the encoder +needs to traverse to reach a given point or the number of C<{> or C<[> +characters without their matching closing parenthesis crossed to reach a +given character in a string. + +If no argument is given, the highest possible setting will be used, which +is rarely useful. + +Note that nesting is implemented by recursion in C. The default value has +been chosen to be as large as typical operating systems allow without +crashing. (JSON::XS) + +With JSON::PP as the backend, when a large value (100 or more) was set and +it de/encodes a deep nested object/text, it may raise a warning +'Deep recursion on subroutin' at the perl runtime phase. + +See L for more info on why this is useful. + +=head2 max_size + + $json = $json->max_size([$maximum_string_size]) + + $max_size = $json->get_max_size + +Set the maximum length a JSON text may have (in bytes) where decoding is +being attempted. The default is C<0>, meaning no limit. When C +is called on a string that is longer then this many bytes, it will not +attempt to decode the string but throw an exception. This setting has no +effect on C (yet). + +If no argument is given, the limit check will be deactivated (same as when +C<0> is specified). + +See L, below, for more info on why this is useful. + +=head2 encode + + $json_text = $json->encode($perl_scalar) + +Converts the given Perl data structure (a simple scalar or a reference +to a hash or array) to its JSON representation. Simple scalars will be +converted into JSON string or number sequences, while references to arrays +become JSON arrays and references to hashes become JSON objects. Undefined +Perl values (e.g. C) become JSON C values. +References to the integers C<0> and C<1> are converted into C and C. + +=head2 decode + + $perl_scalar = $json->decode($json_text) + +The opposite of C: expects a JSON text and tries to parse it, +returning the resulting simple scalar or reference. Croaks on error. + +JSON numbers and strings become simple Perl scalars. JSON arrays become +Perl arrayrefs and JSON objects become Perl hashrefs. C becomes +C<1> (C), C becomes C<0> (C) and +C becomes C. + +=head2 decode_prefix + + ($perl_scalar, $characters) = $json->decode_prefix($json_text) + +This works like the C method, but instead of raising an exception +when there is trailing garbage after the first JSON object, it will +silently stop parsing there and return the number of characters consumed +so far. + + JSON->new->decode_prefix ("[1] the tail") + => ([], 3) + +See to L + +=head2 property + + $boolean = $json->property($property_name) + +Returns a boolean value about above some properties. + +The available properties are C, C, C, +C,C, C, C, C, +C, C, C, C, +C, C and C. + + $boolean = $json->property('utf8'); + => 0 + $json->utf8; + $boolean = $json->property('utf8'); + => 1 + +Sets the property with a given boolean value. + + $json = $json->property($property_name => $boolean); + +With no argumnt, it returns all the above properties as a hash reference. + + $flag_hashref = $json->property(); + +=head1 INCREMENTAL PARSING + +Most of this section are copied and modified from L. + +In some cases, there is the need for incremental parsing of JSON texts. +This module does allow you to parse a JSON stream incrementally. +It does so by accumulating text until it has a full JSON object, which +it then can decode. This process is similar to using C +to see if a full JSON object is available, but is much more efficient +(and can be implemented with a minimum of method calls). + +The backend module will only attempt to parse the JSON text once it is sure it +has enough text to get a decisive result, using a very simple but +truly incremental parser. This means that it sometimes won't stop as +early as the full parser, for example, it doesn't detect parenthese +mismatches. The only thing it guarantees is that it starts decoding as +soon as a syntactically valid JSON text has been seen. This means you need +to set resource limits (e.g. C) to ensure the parser will stop +parsing in the presence if syntax errors. + +The following methods implement this incremental parser. + +=head2 incr_parse + + $json->incr_parse( [$string] ) # void context + + $obj_or_undef = $json->incr_parse( [$string] ) # scalar context + + @obj_or_empty = $json->incr_parse( [$string] ) # list context + +This is the central parsing function. It can both append new text and +extract objects from the stream accumulated so far (both of these +functions are optional). + +If C<$string> is given, then this string is appended to the already +existing JSON fragment stored in the C<$json> object. + +After that, if the function is called in void context, it will simply +return without doing anything further. This can be used to add more text +in as many chunks as you want. + +If the method is called in scalar context, then it will try to extract +exactly I JSON object. If that is successful, it will return this +object, otherwise it will return C. If there is a parse error, +this method will croak just as C would do (one can then use +C to skip the errornous part). This is the most common way of +using the method. + +And finally, in list context, it will try to extract as many objects +from the stream as it can find and return them, or the empty list +otherwise. For this to work, there must be no separators between the JSON +objects or arrays, instead they must be concatenated back-to-back. If +an error occurs, an exception will be raised as in the scalar context +case. Note that in this case, any previously-parsed JSON texts will be +lost. + +Example: Parse some JSON arrays/objects in a given string and return them. + + my @objs = JSON->new->incr_parse ("[5][7][1,2]"); + +=head2 incr_text + + $lvalue_string = $json->incr_text + +This method returns the currently stored JSON fragment as an lvalue, that +is, you can manipulate it. This I works when a preceding call to +C in I successfully returned an object. Under +all other circumstances you must not call this function (I mean it. +although in simple tests it might actually work, it I fail under +real world conditions). As a special exception, you can also call this +method before having parsed anything. + +This function is useful in two cases: a) finding the trailing text after a +JSON object or b) parsing multiple JSON objects separated by non-JSON text +(such as commas). + + $json->incr_text =~ s/\s*,\s*//; + +In Perl 5.005, C attribute is not available. +You must write codes like the below: + + $string = $json->incr_text; + $string =~ s/\s*,\s*//; + $json->incr_text( $string ); + +=head2 incr_skip + + $json->incr_skip + +This will reset the state of the incremental parser and will remove the +parsed text from the input buffer. This is useful after C +died, in which case the input buffer and incremental parser state is left +unchanged, to skip the text parsed so far and to reset the parse state. + +=head2 incr_reset + + $json->incr_reset + +This completely resets the incremental parser, that is, after this call, +it will be as if the parser had never parsed anything. + +This is useful if you want ot repeatedly parse JSON objects and want to +ignore any trailing data, which means you have to reset the parser after +each successful decode. + +See to L for examples. + + +=head1 JSON::PP SUPPORT METHODS + +The below methods are JSON::PP own methods, so when C works +with JSON::PP (i.e. the created object is a JSON::PP object), available. +See to L in detail. + +If you use C with additonal C<-support_by_pp>, some methods +are available even with JSON::XS. See to L. + + BEING { $ENV{PERL_JSON_BACKEND} = 'JSON::XS' } + + use JSON -support_by_pp; + + my $json = new JSON; + $json->allow_nonref->escape_slash->encode("/"); + + # functional interfaces too. + print to_json(["/"], {escape_slash => 1}); + print from_json('["foo"]', {utf8 => 1}); + +If you do not want to all functions but C<-support_by_pp>, +use C<-no_export>. + + use JSON -support_by_pp, -no_export; + # functional interfaces are not exported. + +=head2 allow_singlequote + + $json = $json->allow_singlequote([$enable]) + +If C<$enable> is true (or missing), then C will accept +any JSON strings quoted by single quotations that are invalid JSON +format. + + $json->allow_singlequote->decode({"foo":'bar'}); + $json->allow_singlequote->decode({'foo':"bar"}); + $json->allow_singlequote->decode({'foo':'bar'}); + +As same as the C option, this option may be used to parse +application-specific files written by humans. + +=head2 allow_barekey + + $json = $json->allow_barekey([$enable]) + +If C<$enable> is true (or missing), then C will accept +bare keys of JSON object that are invalid JSON format. + +As same as the C option, this option may be used to parse +application-specific files written by humans. + + $json->allow_barekey->decode('{foo:"bar"}'); + +=head2 allow_bignum + + $json = $json->allow_bignum([$enable]) + +If C<$enable> is true (or missing), then C will convert +the big integer Perl cannot handle as integer into a L +object and convert a floating number (any) into a L. + +On the contary, C converts C objects and C +objects into JSON numbers with C enable. + + $json->allow_nonref->allow_blessed->allow_bignum; + $bigfloat = $json->decode('2.000000000000000000000000001'); + print $json->encode($bigfloat); + # => 2.000000000000000000000000001 + +See to L aboout the conversion of JSON number. + +=head2 loose + + $json = $json->loose([$enable]) + +The unescaped [\x00-\x1f\x22\x2f\x5c] strings are invalid in JSON strings +and the module doesn't allow to C to these (except for \x2f). +If C<$enable> is true (or missing), then C will accept these +unescaped strings. + + $json->loose->decode(qq|["abc + def"]|); + +See to L. + +=head2 escape_slash + + $json = $json->escape_slash([$enable]) + +According to JSON Grammar, I (U+002F) is escaped. But by default +JSON backend modules encode strings without escaping slash. + +If C<$enable> is true (or missing), then C will escape slashes. + +=head2 indent_length + + $json = $json->indent_length($length) + +With JSON::XS, The indent space length is 3 and cannot be changed. +With JSON::PP, it sets the indent space length with the given $length. +The default is 3. The acceptable range is 0 to 15. + +=head2 sort_by + + $json = $json->sort_by($function_name) + $json = $json->sort_by($subroutine_ref) + +If $function_name or $subroutine_ref are set, its sort routine are used. + + $js = $pc->sort_by(sub { $JSON::PP::a cmp $JSON::PP::b })->encode($obj); + # is($js, q|{"a":1,"b":2,"c":3,"d":4,"e":5,"f":6,"g":7,"h":8,"i":9}|); + + $js = $pc->sort_by('own_sort')->encode($obj); + # is($js, q|{"a":1,"b":2,"c":3,"d":4,"e":5,"f":6,"g":7,"h":8,"i":9}|); + + sub JSON::PP::own_sort { $JSON::PP::a cmp $JSON::PP::b } + +As the sorting routine runs in the JSON::PP scope, the given +subroutine name and the special variables C<$a>, C<$b> will begin +with 'JSON::PP::'. + +If $integer is set, then the effect is same as C on. + +See to L. + +=head1 MAPPING + +This section is copied from JSON::XS and modified to C. +JSON::XS and JSON::PP mapping mechanisms are almost equivalent. + +See to L. + +=head2 JSON -> PERL + +=over 4 + +=item object + +A JSON object becomes a reference to a hash in Perl. No ordering of object +keys is preserved (JSON does not preserver object key ordering itself). + +=item array + +A JSON array becomes a reference to an array in Perl. + +=item string + +A JSON string becomes a string scalar in Perl - Unicode codepoints in JSON +are represented by the same codepoints in the Perl string, so no manual +decoding is necessary. + +=item number + +A JSON number becomes either an integer, numeric (floating point) or +string scalar in perl, depending on its range and any fractional parts. On +the Perl level, there is no difference between those as Perl handles all +the conversion details, but an integer may take slightly less memory and +might represent more values exactly than floating point numbers. + +If the number consists of digits only, C will try to represent +it as an integer value. If that fails, it will try to represent it as +a numeric (floating point) value if that is possible without loss of +precision. Otherwise it will preserve the number as a string value (in +which case you lose roundtripping ability, as the JSON number will be +re-encoded toa JSON string). + +Numbers containing a fractional or exponential part will always be +represented as numeric (floating point) values, possibly at a loss of +precision (in which case you might lose perfect roundtripping ability, but +the JSON number will still be re-encoded as a JSON number). + +Note that precision is not accuracy - binary floating point values cannot +represent most decimal fractions exactly, and when converting from and to +floating point, C only guarantees precision up to but not including +the leats significant bit. + +If the backend is JSON::PP and C is enable, the big integers +and the numeric can be optionally converted into L and +L objects. + +=item true, false + +These JSON atoms become C and C, +respectively. They are overloaded to act almost exactly like the numbers +C<1> and C<0>. You can check wether a scalar is a JSON boolean by using +the C function. + +If C and C are used as strings or compared as strings, +they represent as C and C respectively. + + print JSON::true . "\n"; + => true + print JSON::true + 1; + => 1 + + ok(JSON::true eq 'true'); + ok(JSON::true eq '1'); + ok(JSON::true == 1); + +C will install these missing overloading features to the backend modules. + + +=item null + +A JSON null atom becomes C in Perl. + +C returns C. + +=back + + +=head2 PERL -> JSON + +The mapping from Perl to JSON is slightly more difficult, as Perl is a +truly typeless language, so we can only guess which JSON type is meant by +a Perl value. + +=over 4 + +=item hash references + +Perl hash references become JSON objects. As there is no inherent ordering +in hash keys (or JSON objects), they will usually be encoded in a +pseudo-random order that can change between runs of the same program but +stays generally the same within a single run of a program. C +optionally sort the hash keys (determined by the I flag), so +the same datastructure will serialise to the same JSON text (given same +settings and version of JSON::XS), but this incurs a runtime overhead +and is only rarely useful, e.g. when you want to compare some JSON text +against another for equality. + +In future, the ordered object feature will be added to JSON::PP using C mechanism. + + +=item array references + +Perl array references become JSON arrays. + +=item other references + +Other unblessed references are generally not allowed and will cause an +exception to be thrown, except for references to the integers C<0> and +C<1>, which get turned into C and C atoms in JSON. You can +also use C and C to improve readability. + + to_json [\0,JSON::true] # yields [false,true] + +=item JSON::true, JSON::false, JSON::null + +These special values become JSON true and JSON false values, +respectively. You can also use C<\1> and C<\0> directly if you want. + +JSON::null returns C. + +=item blessed objects + +Blessed objects are not directly representable in JSON. See the +C and C methods on various options on +how to deal with this: basically, you can choose between throwing an +exception, encoding the reference as if it weren't blessed, or provide +your own serialiser method. + +With C mode, C converts blessed +hash references or blessed array references (contains other blessed references) +into JSON members and arrays. + + use JSON -convert_blessed_universally; + JSON->new->allow_blessed->convert_blessed->encode( $blessed_object ); + +See to L. + +=item simple scalars + +Simple Perl scalars (any scalar that is not a reference) are the most +difficult objects to encode: JSON::XS and JSON::PP will encode undefined scalars as +JSON C values, scalars that have last been used in a string context +before encoding as JSON strings, and anything else as number value: + + # dump as number + encode_json [2] # yields [2] + encode_json [-3.0e17] # yields [-3e+17] + my $value = 5; encode_json [$value] # yields [5] + + # used as string, so dump as string + print $value; + encode_json [$value] # yields ["5"] + + # undef becomes null + encode_json [undef] # yields [null] + +You can force the type to be a string by stringifying it: + + my $x = 3.1; # some variable containing a number + "$x"; # stringified + $x .= ""; # another, more awkward way to stringify + print $x; # perl does it for you, too, quite often + +You can force the type to be a number by numifying it: + + my $x = "3"; # some variable containing a string + $x += 0; # numify it, ensuring it will be dumped as a number + $x *= 1; # same thing, the choise is yours. + +You can not currently force the type in other, less obscure, ways. + +Note that numerical precision has the same meaning as under Perl (so +binary to decimal conversion follows the same rules as in Perl, which +can differ to other languages). Also, your perl interpreter might expose +extensions to the floating point numbers of your platform, such as +infinities or NaN's - these cannot be represented in JSON, and it is an +error to pass those in. + +=item Big Number + +If the backend is JSON::PP and C is enable, +C converts C objects and C +objects into JSON numbers. + + +=back + +=head1 JSON and ECMAscript + +See to L. + +=head1 JSON and YAML + +JSON is not a subset of YAML. +See to L. + + +=head1 BACKEND MODULE DECISION + +When you use C, C tries to C JSON::XS. If this call failed, it will +C JSON::PP. The required JSON::XS version is I<2.2> or later. + +The C constructor method returns an object inherited from the backend module, +and JSON::XS object is a blessed scaler reference while JSON::PP is a blessed hash +reference. + +So, your program should not depend on the backend module, especially +returned objects should not be modified. + + my $json = JSON->new; # XS or PP? + $json->{stash} = 'this is xs object'; # this code may raise an error! + +To check the backend module, there are some methods - C, C and C. + + JSON->backend; # 'JSON::XS' or 'JSON::PP' + + JSON->backend->is_pp: # 0 or 1 + + JSON->backend->is_xs: # 1 or 0 + + $json->is_xs; # 1 or 0 + + $json->is_pp; # 0 or 1 + + +If you set an enviornment variable C, The calling action will be changed. + +=over + +=item PERL_JSON_BACKEND = 0 or PERL_JSON_BACKEND = 'JSON::PP' + +Always use JSON::PP + +=item PERL_JSON_BACKEND == 1 or PERL_JSON_BACKEND = 'JSON::XS,JSON::PP' + +(The default) Use compiled JSON::XS if it is properly compiled & installed, +otherwise use JSON::PP. + +=item PERL_JSON_BACKEND == 2 or PERL_JSON_BACKEND = 'JSON::XS' + +Always use compiled JSON::XS, die if it isn't properly compiled & installed. + +=item PERL_JSON_BACKEND = 'JSON::backportPP' + +Always use JSON::backportPP. +JSON::backportPP is JSON::PP back port module. +C includs JSON::backportPP instead of JSON::PP. + +=back + +These ideas come from L mechanism. + +example: + + BEGIN { $ENV{PERL_JSON_BACKEND} = 'JSON::PP' } + use JSON; # always uses JSON::PP + +In future, it may be able to specify another module. + +=head1 USE PP FEATURES EVEN THOUGH XS BACKEND + +Many methods are available with either JSON::XS or JSON::PP and +when the backend module is JSON::XS, if any JSON::PP specific (i.e. JSON::XS unspported) +method is called, it will C and be noop. + +But If you C C passing the optional string C<-support_by_pp>, +it makes a part of those unupported methods available. +This feature is achieved by using JSON::PP in C. + + BEGIN { $ENV{PERL_JSON_BACKEND} = 2 } # with JSON::XS + use JSON -support_by_pp; + my $json = new JSON; + $json->allow_nonref->escape_slash->encode("/"); + +At this time, the returned object is a C +object (re-blessed XS object), and by checking JSON::XS unsupported flags +in de/encoding, can support some unsupported methods - C, C, +C, C, C and C. + +When any unsupported methods are not enable, C will be +used as is. The switch is achieved by changing the symbolic tables. + +C<-support_by_pp> is effective only when the backend module is JSON::XS +and it makes the de/encoding speed down a bit. + +See to L. + +=head1 INCOMPATIBLE CHANGES TO OLD VERSION + +There are big incompatibility between new version (2.00) and old (1.xx). +If you use old C 1.xx in your code, please check it. + +See to L + +=over + +=item jsonToObj and objToJson are obsoleted. + +Non Perl-style name C and C are obsoleted +(but not yet deleted from the source). +If you use these functions in your code, please replace them +with C and C. + + +=item Global variables are no longer available. + +C class variables - C<$JSON::AUTOCONVERT>, C<$JSON::BareKey>, etc... +- are not available any longer. +Instead, various features can be used through object methods. + + +=item Package JSON::Converter and JSON::Parser are deleted. + +Now C bundles with JSON::PP which can handle JSON more properly than them. + +=item Package JSON::NotString is deleted. + +There was C class which represents JSON value C, C, C +and numbers. It was deleted and replaced by C. + +C represents C and C. + +C does not represent C. + +C returns C. + +C makes L and L is-a relation +to L. + +=item function JSON::Number is obsoleted. + +C is now needless because JSON::XS and JSON::PP have +round-trip integrity. + +=item JSONRPC modules are deleted. + +Perl implementation of JSON-RPC protocol - C, C +and C are deleted in this distribution. +Instead of them, there is L which supports JSON-RPC protocol version 1.1. + +=back + +=head2 Transition ways from 1.xx to 2.xx. + +You should set C mode firstly, because +it is always successful for the below codes even with JSON::XS. + + use JSON -support_by_pp; + +=over + +=item Exported jsonToObj (simple) + + from_json($json_text); + +=item Exported objToJson (simple) + + to_json($perl_scalar); + +=item Exported jsonToObj (advanced) + + $flags = {allow_barekey => 1, allow_singlequote => 1}; + from_json($json_text, $flags); + +equivalent to: + + $JSON::BareKey = 1; + $JSON::QuotApos = 1; + jsonToObj($json_text); + +=item Exported objToJson (advanced) + + $flags = {allow_blessed => 1, allow_barekey => 1}; + to_json($perl_scalar, $flags); + +equivalent to: + + $JSON::BareKey = 1; + objToJson($perl_scalar); + +=item jsonToObj as object method + + $json->decode($json_text); + +=item objToJson as object method + + $json->encode($perl_scalar); + +=item new method with parameters + +The C method in 2.x takes any parameters no longer. +You can set parameters instead; + + $json = JSON->new->pretty; + +=item $JSON::Pretty, $JSON::Indent, $JSON::Delimiter + +If C is enable, that means C<$JSON::Pretty> flag set. And +C<$JSON::Delimiter> was substituted by C and C. +In conclusion: + + $json->indent->space_before->space_after; + +Equivalent to: + + $json->pretty; + +To change indent length, use C. + +(Only with JSON::PP, if C<-support_by_pp> is not used.) + + $json->pretty->indent_length(2)->encode($perl_scalar); + +=item $JSON::BareKey + +(Only with JSON::PP, if C<-support_by_pp> is not used.) + + $json->allow_barekey->decode($json_text) + +=item $JSON::ConvBlessed + +use C<-convert_blessed_universally>. See to L. + +=item $JSON::QuotApos + +(Only with JSON::PP, if C<-support_by_pp> is not used.) + + $json->allow_singlequote->decode($json_text) + +=item $JSON::SingleQuote + +Disable. C does not make such a invalid JSON string any longer. + +=item $JSON::KeySort + + $json->canonical->encode($perl_scalar) + +This is the ascii sort. + +If you want to use with your own sort routine, check the C method. + +(Only with JSON::PP, even if C<-support_by_pp> is used currently.) + + $json->sort_by($sort_routine_ref)->encode($perl_scalar) + + $json->sort_by(sub { $JSON::PP::a <=> $JSON::PP::b })->encode($perl_scalar) + +Can't access C<$a> and C<$b> but C<$JSON::PP::a> and C<$JSON::PP::b>. + +=item $JSON::SkipInvalid + + $json->allow_unknown + +=item $JSON::AUTOCONVERT + +Needless. C backend modules have the round-trip integrity. + +=item $JSON::UTF8 + +Needless because C (JSON::XS/JSON::PP) sets +the UTF8 flag on properly. + + # With UTF8-flagged strings + + $json->allow_nonref; + $str = chr(1000); # UTF8-flagged + + $json_text = $json->utf8(0)->encode($str); + utf8::is_utf8($json_text); + # true + $json_text = $json->utf8(1)->encode($str); + utf8::is_utf8($json_text); + # false + + $str = '"' . chr(1000) . '"'; # UTF8-flagged + + $perl_scalar = $json->utf8(0)->decode($str); + utf8::is_utf8($perl_scalar); + # true + $perl_scalar = $json->utf8(1)->decode($str); + # died because of 'Wide character in subroutine' + +See to L. + +=item $JSON::UnMapping + +Disable. See to L. + +=item $JSON::SelfConvert + +This option was deleted. +Instead of it, if a givien blessed object has the C method, +C will be executed with C. + + $json->convert_blessed->encode($bleesed_hashref_or_arrayref) + # if need, call allow_blessed + +Note that it was C in old version, but now not C but C. + +=back + +=head1 TODO + +=over + +=item example programs + +=back + +=head1 THREADS + +No test with JSON::PP. If with JSON::XS, See to L. + + +=head1 BUGS + +Please report bugs relevant to C to Emakamaka[at]cpan.orgE. + + +=head1 SEE ALSO + +Most of the document is copied and modified from JSON::XS doc. + +L, L + +C(L) + +=head1 AUTHOR + +Makamaka Hannyaharamitu, Emakamaka[at]cpan.orgE + +JSON::XS was written by Marc Lehmann + +The relese of this new version owes to the courtesy of Marc Lehmann. + + +=head1 COPYRIGHT AND LICENSE + +Copyright 2005-2011 by Makamaka Hannyaharamitu + +This library is free software; you can redistribute it and/or modify +it under the same terms as Perl itself. + +=cut + diff --git a/soc/Makefile b/soc/Makefile new file mode 100644 index 0000000..e69de29 diff --git a/soc/ahb_sif.sv b/soc/ahb_sif.sv new file mode 100644 index 0000000..50efd39 --- /dev/null +++ b/soc/ahb_sif.sv @@ -0,0 +1,110 @@ +// 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. +// + +module axi_slv #( + TAGW = 1 +) ( + input aclk, + input rst_l, + input arvalid, + output reg arready, + input [ 31:0] araddr, + input [TAGW-1:0] arid, + input [ 7:0] arlen, + input [ 1:0] arburst, + input [ 2:0] arsize, + + output reg rvalid, + input rready, + output reg [ 63:0] rdata, + output reg [ 1:0] rresp, + output reg [TAGW-1:0] rid, + output rlast, + + input awvalid, + output awready, + input [ 31:0] awaddr, + input [TAGW-1:0] awid, + input [ 7:0] awlen, + input [ 1:0] awburst, + input [ 2:0] awsize, + + input [63:0] wdata, + input [ 7:0] wstrb, + input wvalid, + output wready, + + output reg bvalid, + input bready, + output reg [ 1:0] bresp, + output reg [TAGW-1:0] bid +); + + parameter MEM_DEPTH = 17; // memory size = 0x8000 = 32k + + bit [7:0] mem[(1< +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * Simple buffer for passing data between TCP sockets and DPI modules + */ +const int BUFSIZE_BYTE = 25600; + +struct tcp_buf { + unsigned int rptr; + unsigned int wptr; + char buf[BUFSIZE_BYTE]; +}; + +/** + * TCP Server thread context structure + */ +struct tcp_server_ctx { + // Writeable by the host thread + char *display_name; + uint16_t listen_port; + volatile bool socket_run; + // Writeable by the server thread + tcp_buf *buf_in; + tcp_buf *buf_out; + int sfd; // socket fd + int cfd; // client fd + pthread_t sock_thread; +}; + +static bool tcp_buffer_is_full(struct tcp_buf *buf) { + if (buf->wptr >= buf->rptr) { + return (buf->wptr - buf->rptr) == (BUFSIZE_BYTE - 1); + } else { + return (buf->rptr - buf->wptr) == 1; + } +} + +static bool tcp_buffer_is_empty(struct tcp_buf *buf) { + return (buf->wptr == buf->rptr); +} + +static void tcp_buffer_put_byte(struct tcp_buf *buf, char dat) { + bool done = false; + while (!done) { + if (!tcp_buffer_is_full(buf)) { + buf->buf[buf->wptr++] = dat; + buf->wptr %= BUFSIZE_BYTE; + done = true; + } + } +} + +static bool tcp_buffer_get_byte(struct tcp_buf *buf, char *dat) { + if (tcp_buffer_is_empty(buf)) { + return false; + } + *dat = buf->buf[buf->rptr++]; + buf->rptr %= BUFSIZE_BYTE; + return true; +} + +static struct tcp_buf *tcp_buffer_new(void) { + struct tcp_buf *buf_new; + buf_new = (struct tcp_buf *)malloc(sizeof(struct tcp_buf)); + buf_new->rptr = 0; + buf_new->wptr = 0; + return buf_new; +} + +static void tcp_buffer_free(struct tcp_buf **buf) { + free(*buf); + *buf = NULL; +} + +/** + * Start a TCP server + * + * This function creates attempts to create a new TCP socket instance. The + * socket is a non-blocking stream socket, with buffering disabled. + * + * @param ctx context object + * @return 0 on success, -1 in case of an error + */ +static int start(struct tcp_server_ctx *ctx) { + int rv; + + assert(ctx->sfd == 0 && "Server already started."); + + // create socket + int sfd = socket(AF_INET, SOCK_STREAM, 0); + if (sfd == -1) { + fprintf(stderr, "%s: Unable to create socket: %s (%d)\n", ctx->display_name, + strerror(errno), errno); + return -1; + } + + rv = fcntl(sfd, F_SETFL, O_NONBLOCK); + if (rv != 0) { + fprintf(stderr, "%s: Unable to make socket non-blocking: %s (%d)\n", + ctx->display_name, strerror(errno), errno); + return -1; + } + + // reuse existing socket (if existing) + int reuse_socket = 1; + rv = setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse_socket, sizeof(int)); + if (rv != 0) { + fprintf(stderr, "%s: Unable to set socket options: %s (%d)\n", + ctx->display_name, strerror(errno), errno); + return -1; + } + + // stop tcp socket from buffering (buffering prevents timely responses to + // OpenOCD which severly limits debugging performance) + int tcp_nodelay = 1; + rv = setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, &tcp_nodelay, sizeof(int)); + if (rv != 0) { + fprintf(stderr, "%s: Unable to set socket nodelay: %s (%d)\n", + ctx->display_name, strerror(errno), errno); + return -1; + } + + // bind server + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + addr.sin_port = htons(ctx->listen_port); + + rv = bind(sfd, (struct sockaddr *)&addr, sizeof(addr)); + if (rv != 0) { + fprintf(stderr, "%s: Failed to bind socket: %s (%d)\n", ctx->display_name, + strerror(errno), errno); + return -1; + } + + // listen for incoming connections + rv = listen(sfd, 1); + if (rv != 0) { + fprintf(stderr, "%s: Failed to listen on socket: %s (%d)\n", + ctx->display_name, strerror(errno), errno); + return -1; + } + + ctx->sfd = sfd; + assert(ctx->sfd > 0); + + return 0; +} + +/** + * Accept an incoming connection from a client (nonblocking) + * + * The resulting client fd is made non-blocking. + * + * @param ctx context object + * @return 0 on success, any other value indicates an error + */ +static int client_tryaccept(struct tcp_server_ctx *ctx) { + int rv; + + assert(ctx->sfd > 0); + assert(ctx->cfd == 0); + + int cfd = accept(ctx->sfd, NULL, NULL); + + if (cfd == -1 && errno == EAGAIN) { + return -EAGAIN; + } + + if (cfd == -1) { + fprintf(stderr, "%s: Unable to accept incoming connection: %s (%d)\n", + ctx->display_name, strerror(errno), errno); + return -1; + } + + rv = fcntl(cfd, F_SETFL, O_NONBLOCK); + if (rv != 0) { + fprintf(stderr, "%s: Unable to make client socket non-blocking: %s (%d)\n", + ctx->display_name, strerror(errno), errno); + return -1; + } + + ctx->cfd = cfd; + assert(ctx->cfd > 0); + + printf("%s: Accepted client connection\n", ctx->display_name); + + return 0; +} + +/** + * Stop the TCP server + * + * @param ctx context object + */ +static void stop(struct tcp_server_ctx *ctx) { + assert(ctx); + if (!ctx->sfd) { + return; + } + close(ctx->sfd); + ctx->sfd = 0; +} + +/** + * Receive a byte from a connected client + * + * @param ctx context object + * @param cmd byte received + * @return true if a byte was read + */ +static bool get_byte(struct tcp_server_ctx *ctx, char *cmd) { + assert(ctx); + + ssize_t num_read = read(ctx->cfd, cmd, 1); + + if (num_read == 0) { + return false; + } + if (num_read == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + return false; + } else if (errno == EBADF) { + // Possibly client went away? Accept a new connection. + fprintf(stderr, "%s: Client disappeared.\n", ctx->display_name); + tcp_server_client_close(ctx); + return false; + } else { + fprintf(stderr, "%s: Error while reading from client: %s (%d)\n", + ctx->display_name, strerror(errno), errno); + assert(0 && "Error reading from client"); + } + } + assert(num_read == 1); + return true; +} + +/** + * Send a byte to a connected client + * + * @param ctx context object + * @param cmd byte to send + */ +static void put_byte(struct tcp_server_ctx *ctx, char cmd) { + while (1) { + ssize_t num_written = send(ctx->cfd, &cmd, sizeof(cmd), MSG_NOSIGNAL); + if (num_written == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + continue; + } else if (errno == EPIPE) { + printf("%s: Remote disconnected.\n", ctx->display_name); + tcp_server_client_close(ctx); + break; + } else { + fprintf(stderr, "%s: Error while writing to client: %s (%d)\n", + ctx->display_name, strerror(errno), errno); + assert(0 && "Error writing to client."); + } + } + if (num_written >= 1) { + break; + } + } +} + +/** + * Cleanup server context + * + * @param ctx context object + */ +static void ctx_free(struct tcp_server_ctx *ctx) { + // Free the buffers + tcp_buffer_free(&ctx->buf_in); + tcp_buffer_free(&ctx->buf_out); + // Free the display name + free(ctx->display_name); + // Free the ctx + free(ctx); + ctx = NULL; +} + +/** + * Thread function to create a new server instance + * + * @param ctx_void context object + * @return Always returns NULL + */ +static void *server_create(void *ctx_void) { + // Cast to a server struct + struct tcp_server_ctx *ctx = (struct tcp_server_ctx *)ctx_void; + struct timeval timeout; + + // Start the server + int rv = start(ctx); + if (rv != 0) { + fprintf(stderr, "%s: Unable to create TCP server on port %d\n", + ctx->display_name, ctx->listen_port); + goto err_cleanup_return; + } + + // Initialise timeout + timeout.tv_sec = 0; + + // Initialise fd_set + + // Start waiting for connection / data + char xfer_data; + while (ctx->socket_run) { + // Initialise structure of fds + fd_set read_fds; + FD_ZERO(&read_fds); + if (ctx->sfd) { + FD_SET(ctx->sfd, &read_fds); + } + if (ctx->cfd) { + FD_SET(ctx->cfd, &read_fds); + } + // max fd num + int mfd = (ctx->cfd > ctx->sfd) ? ctx->cfd : ctx->sfd; + + // Set timeout - 50us gives good performance + timeout.tv_usec = 50; + + // Wait for socket activity or timeout + rv = select(mfd + 1, &read_fds, NULL, NULL, &timeout); + + if (rv < 0) { + printf("%s: Socket read failed, port: %d\n", ctx->display_name, + ctx->listen_port); + tcp_server_client_close(ctx); + } + + // New connection + if (FD_ISSET(ctx->sfd, &read_fds)) { + client_tryaccept(ctx); + } + + // New client data + if (FD_ISSET(ctx->cfd, &read_fds)) { + while (get_byte(ctx, &xfer_data)) { + tcp_buffer_put_byte(ctx->buf_in, xfer_data); + } + } + + if (ctx->cfd != 0) { + while (tcp_buffer_get_byte(ctx->buf_out, &xfer_data)) { + put_byte(ctx, xfer_data); + } + } + } + +err_cleanup_return: + + // Simulation done - clean up + tcp_server_client_close(ctx); + stop(ctx); + + return NULL; +} + +// Abstract interface functions +tcp_server_ctx *tcp_server_create(const char *display_name, int listen_port) { + struct tcp_server_ctx *ctx = + (struct tcp_server_ctx *)calloc(1, sizeof(struct tcp_server_ctx)); + assert(ctx); + + // Create the buffers + struct tcp_buf *buf_in = tcp_buffer_new(); + struct tcp_buf *buf_out = tcp_buffer_new(); + assert(buf_in); + assert(buf_out); + + // Populate the struct with buffer pointers + ctx->buf_in = buf_in; + ctx->buf_out = buf_out; + + // Set up socket details + ctx->socket_run = true; + ctx->listen_port = listen_port; + ctx->display_name = strdup(display_name); + assert(ctx->display_name); + + if (pthread_create(&ctx->sock_thread, NULL, server_create, (void *)ctx) != + 0) { + fprintf(stderr, "%s: Unable to create TCP socket thread\n", + ctx->display_name); + ctx_free(ctx); + free(ctx); + return NULL; + } + return ctx; +} + +bool tcp_server_read(struct tcp_server_ctx *ctx, char *dat) { + return tcp_buffer_get_byte(ctx->buf_in, dat); +} + +void tcp_server_write(struct tcp_server_ctx *ctx, char dat) { + tcp_buffer_put_byte(ctx->buf_out, dat); +} + +void tcp_server_close(struct tcp_server_ctx *ctx) { + // Shut down the socket thread + ctx->socket_run = false; + pthread_join(ctx->sock_thread, NULL); + ctx_free(ctx); +} + +void tcp_server_client_close(struct tcp_server_ctx *ctx) { + assert(ctx); + + if (!ctx->cfd) { + return; + } + + close(ctx->cfd); + ctx->cfd = 0; +} diff --git a/soc/dpi/common/tcp_server.h b/soc/dpi/common/tcp_server.h new file mode 100644 index 0000000..303c09c --- /dev/null +++ b/soc/dpi/common/tcp_server.h @@ -0,0 +1,69 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +/** + * Functions to create and interact with a threaded TCP server + * + * This is intended to be used by simulation add-on DPI modules to provide + * basic TCP socket communication between a host and simulated peripherals. + */ + +#ifndef TCP_SERVER_H_ +#define TCP_SERVER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +struct tcp_server_ctx; + +/** + * Non-blocking read of a byte from a connected client + * + * @param ctx tcp server context object + * @param dat byte received + * @return true if a byte was read + */ +bool tcp_server_read(struct tcp_server_ctx *ctx, char *dat); + +/** + * Write a byte to a connected client + * + * The write is internally buffered and so does not block if the client is not + * ready to accept data, but does block if the buffer is full. + * + * @param ctx tcp server context object + * @param dat byte to send + */ +void tcp_server_write(struct tcp_server_ctx *ctx, char dat); + +/** + * Create a new TCP server instance + * + * @param display_name C string description of server + * @param listen_port On which port the server should listen + * @return A pointer to the created context struct + */ +tcp_server_ctx *tcp_server_create(const char *display_name, int listen_port); + +/** + * Shut down the server and free all reserved memory + * + * @param ctx tcp server context object + */ +void tcp_server_close(struct tcp_server_ctx *ctx); + +/** + * Instruct the server to disconnect a client + * + * @param ctx tcp server context object + */ +void tcp_server_client_close(struct tcp_server_ctx *ctx); + +#ifdef __cplusplus +} // extern "C" +#endif +#endif // TCP_SERVER_H_ diff --git a/soc/dpi/jtagdpi/jtagdpi.c b/soc/dpi/jtagdpi/jtagdpi.c new file mode 100644 index 0000000..5d1ee6f --- /dev/null +++ b/soc/dpi/jtagdpi/jtagdpi.c @@ -0,0 +1,154 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#include "jtagdpi.h" + +#include +#include +#include +#include +#include + +#include "../common/tcp_server.h" + +struct jtagdpi_ctx { + // Server context + struct tcp_server_ctx *sock; + // Signals + uint8_t tck; + uint8_t tms; + uint8_t tdi; + uint8_t tdo; + uint8_t trst_n; + uint8_t srst_n; +}; + +/** + * Reset the JTAG signals to a "dongle unplugged" state + */ +static void reset_jtag_signals(struct jtagdpi_ctx *ctx) { + assert(ctx); + + ctx->tck = 0; + ctx->tms = 0; + ctx->tdi = 0; + + // trst_n is pulled down (reset active) by default + ctx->trst_n = 0; + + // srst_n is pulled up (reset not active) by default + ctx->srst_n = 1; +} + +/** + * Update the JTAG signals in the context structure + */ +static void update_jtag_signals(struct jtagdpi_ctx *ctx) { + assert(ctx); + + /* + * Documentation pointer: + * The remote_bitbang protocol implemented below is documented in the OpenOCD + * source tree at doc/manual/jtag/drivers/remote_bitbang.txt, or online at + * https://repo.or.cz/openocd.git/blob/HEAD:/doc/manual/jtag/drivers/remote_bitbang.txt + */ + + // read a command byte + char cmd; + if (!tcp_server_read(ctx->sock, &cmd)) { + return; + } + + bool act_send_resp = false; + bool act_quit = false; + + // parse received command byte + if (cmd >= '0' && cmd <= '7') { + // JTAG write + char cmd_bit = cmd - '0'; + ctx->tdi = (cmd_bit >> 0) & 0x1; + ctx->tms = (cmd_bit >> 1) & 0x1; + ctx->tck = (cmd_bit >> 2) & 0x1; + } else if (cmd >= 'r' && cmd <= 'u') { + // JTAG reset (active high from OpenOCD) + char cmd_bit = cmd - 'r'; + ctx->srst_n = !((cmd_bit >> 0) & 0x1); + ctx->trst_n = !((cmd_bit >> 1) & 0x1); + } else if (cmd == 'R') { + // JTAG read + act_send_resp = true; + } else if (cmd == 'B') { + // printf("%s: BLINK ON!\n", ctx->display_name); + } else if (cmd == 'b') { + // printf("%s: BLINK OFF!\n", ctx->display_name); + } else if (cmd == 'Q') { + // quit (client disconnect) + act_quit = true; + } else { + fprintf(stderr, + "JTAG DPI Protocol violation detected: unsupported command %c\n", + cmd); + exit(1); + } + + // send tdo as response + if (act_send_resp) { + char tdo_ascii = ctx->tdo + '0'; + tcp_server_write(ctx->sock, tdo_ascii); + } + + if (act_quit) { + printf("JTAG DPI: Remote disconnected.\n"); + tcp_server_client_close(ctx->sock); + } +} + +void *jtagdpi_create(const char *display_name, int listen_port) { + struct jtagdpi_ctx *ctx = + (struct jtagdpi_ctx *)calloc(1, sizeof(struct jtagdpi_ctx)); + assert(ctx); + + // Create socket + ctx->sock = tcp_server_create(display_name, listen_port); + + reset_jtag_signals(ctx); + + printf( + "\n" + "JTAG: Virtual JTAG interface %s is listening on port %d. Use\n" + "OpenOCD and the following configuration to connect:\n" + " interface remote_bitbang\n" + " remote_bitbang_host localhost\n" + " remote_bitbang_port %d\n", + display_name, listen_port, listen_port); + + return (void *)ctx; +} + +void jtagdpi_close(void *ctx_void) { + struct jtagdpi_ctx *ctx = (struct jtagdpi_ctx *)ctx_void; + if (!ctx) { + return; + } + tcp_server_close(ctx->sock); + free(ctx); +} + +void jtagdpi_tick(void *ctx_void, svBit *tck, svBit *tms, svBit *tdi, + svBit *trst_n, svBit *srst_n, const svBit tdo) { + struct jtagdpi_ctx *ctx = (struct jtagdpi_ctx *)ctx_void; + + ctx->tdo = tdo; + + // TODO: Evaluate moving this functionality into a separate thread + if (ctx) { + update_jtag_signals(ctx); + } + + *tdi = ctx->tdi; + *tms = ctx->tms; + *tck = ctx->tck; + *srst_n = ctx->srst_n; + *trst_n = ctx->trst_n; +} diff --git a/soc/dpi/jtagdpi/jtagdpi.h b/soc/dpi/jtagdpi/jtagdpi.h new file mode 100644 index 0000000..0888871 --- /dev/null +++ b/soc/dpi/jtagdpi/jtagdpi.h @@ -0,0 +1,56 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#ifndef JTAGDPI_H_ +#define JTAGDPI_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct jtagdpi_ctx; + +/** + * Constructor: Create and initialize jtagdpi context object + * + * Call from a initial block. + * + * @param display_name Name of the JTAG interface (for display purposes only) + * @param listen_port Port to listen on + * @return an initialized struct jtagdpi_ctx context object + */ +void *jtagdpi_create(const char *display_name, int listen_port); + +/** + * Destructor: Close all connections and free all resources + * + * Call from a finish block. + * + * @param ctx_void a struct jtagdpi_ctx context object + */ +void jtagdpi_close(void *ctx_void); + +/** + * Drive JTAG signals + * + * Call this function from the simulation at every clock tick to read/write + * from/to the JTAG signals. + * + * @param ctx_void a struct jtagdpi_ctx context object + * @param tck JTAG test clock signal + * @param tms JTAG test mode select signal + * @param tdi JTAG test data input signal + * @param trst_n JTAG test reset signal (active low) + * @param srst_n JTAG system reset signal (active low) + * @param tdo JTAG test data out + */ +void jtagdpi_tick(void *ctx_void, svBit *tck, svBit *tms, svBit *tdi, + svBit *trst_n, svBit *srst_n, const svBit tdo); + +#ifdef __cplusplus +} // extern "C" +#endif +#endif // JTAGDPI_H_ diff --git a/soc/dpi/jtagdpi/jtagdpi.sv b/soc/dpi/jtagdpi/jtagdpi.sv new file mode 100644 index 0000000..3a977a6 --- /dev/null +++ b/soc/dpi/jtagdpi/jtagdpi.sv @@ -0,0 +1,56 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +module jtagdpi #( + parameter string Name = "jtag0", // name of the JTAG interface (display only) + parameter int ListenPort = 44853 // TCP port to listen on +) ( + input logic clk_i, + input logic rst_ni, + + output logic jtag_tck, + output logic jtag_tms, + output logic jtag_tdi, + input logic jtag_tdo, + output logic jtag_trst_n, + output logic jtag_srst_n +); + + import "DPI-C" function chandle jtagdpi_create( + input string name, + input int listen_port + ); + + import "DPI-C" function void jtagdpi_tick( + input chandle ctx, + output bit tck, + output bit tms, + output bit tdi, + output bit trst_n, + output bit srst_n, + input bit tdo + ); + + import "DPI-C" function void jtagdpi_close(input chandle ctx); + + chandle ctx; + + initial begin + ctx = jtagdpi_create(Name, ListenPort); + end + + final begin + jtagdpi_close(ctx); + ctx = 0; + end + + reg [1:0] plit; + always_ff @(posedge clk_i) plit <= plit + 1'b1; + + always_ff @(posedge plit[1], negedge rst_ni) begin + jtagdpi_tick(ctx, jtag_tck, jtag_tms, jtag_tdi, jtag_trst_n, jtag_srst_n, + jtag_tdo); + end + +endmodule diff --git a/soc/soc_sim.mk b/soc/soc_sim.mk new file mode 100644 index 0000000..122456d --- /dev/null +++ b/soc/soc_sim.mk @@ -0,0 +1,9 @@ +-I../design/include +-I./ + +-CFLAGS -lpthread +-LDFLAGS -lpthread + +./dpi/common/tcp_server.c +./dpi/jtagdpi/jtagdpi.sv +./dpi/jtagdpi/jtagdpi.c diff --git a/soc/soc_sim.sv b/soc/soc_sim.sv new file mode 100644 index 0000000..dd65d55 --- /dev/null +++ b/soc/soc_sim.sv @@ -0,0 +1,211 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2020 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. +// + +module soc_sim ( + input bit core_clk +); + + logic rst_l; + logic dbg_rst_l; + + wire jtag_tdo; + wire jtag_tck; + wire jtag_tms; + wire jtag_tdi; + wire jtag_trst_n; + + bit [31:0] cycleCnt; + logic mailbox_data_val; + int commit_count; + + logic wb_valid; + logic [ 4:0] wb_dest; + logic [31:0] wb_data; + + wire [63:0] WriteData; + string abi_reg [32]; // ABI register names + + assign WriteData = rvsoc.lsu_axi_wdata; + assign mailbox_data_val = WriteData[7:0] > 8'h5 && WriteData[7:0] < 8'h7f; + + parameter MAILBOX_ADDR = 32'hD0580000; + logic write; + logic [31:0] laddr; + + wire mailbox_write = rvsoc.lmem_axi_awvalid && rvsoc.lsu_axi_awaddr == MAILBOX_ADDR && rst_l; + always @(posedge core_clk or negedge rst_l) begin + if (~rst_l) begin + laddr <= 32'b0; + write <= 1'b0; + end else begin + if (rvsoc.lsu_hready) begin + laddr <= rvsoc.lsu_haddr; + write <= rvsoc.lsu_hwrite & |rvsoc.lsu_htrans; + end + end + end + + parameter MAX_CYCLES = 10_000_000_0; + + integer fd, tp, el; + + /* verilator lint_off WIDTH */ + /* verilator lint_off CASEINCOMPLETE */ + `include "dasm.svi" + /* verilator lint_on CASEINCOMPLETE */ + /* verilator lint_on WIDTH */ + + always @(posedge core_clk) begin + cycleCnt <= cycleCnt + 1; + + if (cycleCnt == MAX_CYCLES) begin + $display("Hit max cycle count (%0d) .. stopping", cycleCnt); + $finish; + end + if (mailbox_data_val & mailbox_write) begin + $fwrite(fd, "%c", WriteData[7:0]); + $write("%c", WriteData[7:0]); + end + if (mailbox_write && WriteData[7:0] == 8'hff) begin + $display("\nFinished : minstret = %0d, mcycle = %0d", + rvsoc.rvtop.swerv.dec.tlu.minstretl[31:0], + rvsoc.rvtop.swerv.dec.tlu.mcyclel[31:0]); + $display( + "See \"exec.log\" for execution trace with register updates..\n"); + $display("TEST_PASSED"); + $finish; + end else if (mailbox_write && WriteData[7:0] == 8'h1) begin + $display("TEST_FAILED"); + $finish; + end + end + + // trace monitor + always @(posedge core_clk) begin + wb_valid <= rvsoc.rvtop.swerv.dec.dec_i0_wen_r; + wb_dest <= rvsoc.rvtop.swerv.dec.dec_i0_waddr_r; + wb_data <= rvsoc.rvtop.swerv.dec.dec_i0_wdata_r; + if (rvsoc.trace_rv_i_valid_ip) begin + $fwrite(tp, "%b,%h,%h,%0h,%0h,3,%b,%h,%h,%b\n", rvsoc.trace_rv_i_valid_ip, + 0, rvsoc.trace_rv_i_address_ip, 0, rvsoc.trace_rv_i_insn_ip, + rvsoc.trace_rv_i_exception_ip, rvsoc.trace_rv_i_ecause_ip, + rvsoc.trace_rv_i_tval_ip, rvsoc.trace_rv_i_interrupt_ip); + // Basic trace - no exception register updates + // #1 0 ee000000 b0201073 c 0b02 00000000 + commit_count++; + $fwrite(el, "%10d : %8s 0 %h %h%13s ; %s\n", cycleCnt, $sformatf( + "#%0d", commit_count), rvsoc.trace_rv_i_address_ip, + rvsoc.trace_rv_i_insn_ip, (wb_dest != 0 && wb_valid) ? $sformatf( + "%s=%h", abi_reg[wb_dest], wb_data) : " ", dasm( + rvsoc.trace_rv_i_insn_ip, + rvsoc.trace_rv_i_address_ip, + wb_dest & {5{wb_valid}}, + wb_data + )); + end + if (rvsoc.rvtop.swerv.dec.dec_nonblock_load_wen) begin + $fwrite(el, "%10d : %32s=%h ; nbL\n", cycleCnt, + abi_reg[rvsoc.rvtop.swerv.dec.dec_nonblock_load_waddr], + rvsoc.rvtop.swerv.dec.lsu_nonblock_load_data); + soc_sim.gpr[0][rvsoc.rvtop.swerv.dec.dec_nonblock_load_waddr] = rvsoc.rvtop.swerv.dec.lsu_nonblock_load_data; + end + if (rvsoc.rvtop.swerv.dec.exu_div_wren) begin + $fwrite(el, "%10d : %32s=%h ; nbD\n", cycleCnt, + abi_reg[rvsoc.rvtop.swerv.dec.div_waddr_wb], + rvsoc.rvtop.swerv.dec.exu_div_result); + soc_sim.gpr[0][rvsoc.rvtop.swerv.dec.div_waddr_wb] = rvsoc.rvtop.swerv.dec.exu_div_result; + end + end + + initial begin + abi_reg[0] = "zero"; + abi_reg[1] = "ra"; + abi_reg[2] = "sp"; + abi_reg[3] = "gp"; + abi_reg[4] = "tp"; + abi_reg[5] = "t0"; + abi_reg[6] = "t1"; + abi_reg[7] = "t2"; + abi_reg[8] = "s0"; + abi_reg[9] = "s1"; + abi_reg[10] = "a0"; + abi_reg[11] = "a1"; + abi_reg[12] = "a2"; + abi_reg[13] = "a3"; + abi_reg[14] = "a4"; + abi_reg[15] = "a5"; + abi_reg[16] = "a6"; + abi_reg[17] = "a7"; + abi_reg[18] = "s2"; + abi_reg[19] = "s3"; + abi_reg[20] = "s4"; + abi_reg[21] = "s5"; + abi_reg[22] = "s6"; + abi_reg[23] = "s7"; + abi_reg[24] = "s8"; + abi_reg[25] = "s9"; + abi_reg[26] = "s10"; + abi_reg[27] = "s11"; + abi_reg[28] = "t3"; + abi_reg[29] = "t4"; + abi_reg[30] = "t5"; + abi_reg[31] = "t6"; + + tp = $fopen("trace_port.csv", "w"); + el = $fopen("exec.log", "w"); + $fwrite(el, "//Cycle : #inst 0 pc opcode reg regnum value\n"); + fd = $fopen("console.log", "w"); + commit_count = 0; + + end + + assign rst_l = cycleCnt > 20; + assign dbg_rst_l = cycleCnt > 10; + + soc_top rvsoc ( + .clk(core_clk), + .rst(rst_l), + .dbg_rst(dbg_rst_l), + + .jtag_tdo(jtag_tdo), + .jtag_tck(jtag_tck), + .jtag_tms(jtag_tms), + .jtag_tdi(jtag_tdi), + .jtag_trst_n(jtag_trst_n) + ); + + jtagdpi jtagdpi ( + .clk_i (core_clk), + .rst_ni(rst_l), + + .jtag_tck(jtag_tck), + .jtag_tms(jtag_tms), + .jtag_tdi(jtag_tdi), + .jtag_tdo(jtag_tdo), + .jtag_trst_n(jtag_trst_n), + .jtag_srst_n() + ); + + `define DRAM(bank) \ + rvsoc.rvtop.mem.Gen_dccm_enable.dccm.mem_bank[bank].dccm_bank.ram_core + + `define ICCM_PATH `RV_TOP.mem.iccm + `define IRAM0(bk) `ICCM_PATH.mem_bank[bk].iccm_bank_lo0.ram_core + `define IRAM1(bk) `ICCM_PATH.mem_bank[bk].iccm_bank_lo1.ram_core + `define IRAM2(bk) `ICCM_PATH.mem_bank[bk].iccm_bank_hi0.ram_core + `define IRAM3(bk) `ICCM_PATH.mem_bank[bk].iccm_bank_hi1.ram_core + +endmodule diff --git a/soc/soc_top.mk b/soc/soc_top.mk new file mode 100644 index 0000000..a3a37ec --- /dev/null +++ b/soc/soc_top.mk @@ -0,0 +1,51 @@ +../design/include/el2_def.sv + +../design/el2_swerv_wrapper.sv +../design/el2_mem.sv +../design/el2_pic_ctrl.sv +../design/el2_swerv.sv +../design/el2_dma_ctrl.sv +../design/ifu/el2_ifu_aln_ctl.sv +../design/ifu/el2_ifu_compress_ctl.sv +../design/ifu/el2_ifu_ifc_ctl.sv +../design/ifu/el2_ifu_bp_ctl.sv +../design/ifu/el2_ifu_ic_mem.sv +../design/ifu/el2_ifu_mem_ctl.sv +../design/ifu/el2_ifu_iccm_mem.sv +../design/ifu/el2_ifu.sv +../design/dec/el2_dec_decode_ctl.sv +../design/dec/el2_dec_gpr_ctl.sv +../design/dec/el2_dec_ib_ctl.sv +../design/dec/el2_dec_tlu_ctl.sv +../design/dec/el2_dec_trigger.sv +../design/dec/el2_dec.sv +../design/exu/el2_exu_alu_ctl.sv +../design/exu/el2_exu_mul_ctl.sv +../design/exu/el2_exu_div_ctl.sv +../design/exu/el2_exu.sv +../design/lsu/el2_lsu.sv +../design/lsu/el2_lsu_clkdomain.sv +../design/lsu/el2_lsu_addrcheck.sv +../design/lsu/el2_lsu_lsc_ctl.sv +../design/lsu/el2_lsu_stbuf.sv +../design/lsu/el2_lsu_bus_buffer.sv +../design/lsu/el2_lsu_bus_intf.sv +../design/lsu/el2_lsu_ecc.sv +../design/lsu/el2_lsu_dccm_mem.sv +../design/lsu/el2_lsu_dccm_ctl.sv +../design/lsu/el2_lsu_trigger.sv +../design/dbg/el2_dbg.sv +../design/dmi/dmi_wrapper.v +../design/dmi/dmi_jtag_to_core_sync.v +../design/dmi/rvjtag_tap.v + +../design/lib/el2_lib.sv +../design/lib/beh_lib.sv +../design/lib/mem_lib.sv + +../design/lib/ahb_to_axi4.sv +../design/lib/axi4_to_ahb.sv + +./ahb_sif.sv +./axi_lsu_dma_bridge.sv +./soc_top.sv \ No newline at end of file diff --git a/soc/soc_top.sv b/soc/soc_top.sv new file mode 100644 index 0000000..8045e04 --- /dev/null +++ b/soc/soc_top.sv @@ -0,0 +1,698 @@ +module soc_top ( + input clk, + input dbg_rst, + input rst, + output jtag_tdo, + input jtag_tck, + input jtag_tms, + input jtag_tdi, + input jtag_trst_n +); + + logic nmi_int; + + logic [ 31:0] reset_vector; + logic [ 31:0] nmi_vector; + logic [ 31:1] jtag_id; + + logic [ 31:0] ic_haddr; + logic [ 2:0] ic_hburst; + logic ic_hmastlock; + logic [ 3:0] ic_hprot; + logic [ 2:0] ic_hsize; + logic [ 1:0] ic_htrans; + logic ic_hwrite; + logic [ 63:0] ic_hrdata; + logic ic_hready; + logic ic_hresp; + + logic [ 31:0] lsu_haddr; + logic [ 2:0] lsu_hburst; + logic lsu_hmastlock; + logic [ 3:0] lsu_hprot; + logic [ 2:0] lsu_hsize; + logic [ 1:0] lsu_htrans; + logic lsu_hwrite; + logic [ 63:0] lsu_hrdata; + logic [ 63:0] lsu_hwdata; + logic lsu_hready; + logic lsu_hresp; + + logic [ 31:0] sb_haddr; + logic [ 2:0] sb_hburst; + logic sb_hmastlock; + logic [ 3:0] sb_hprot; + logic [ 2:0] sb_hsize; + logic [ 1:0] sb_htrans; + logic sb_hwrite; + + logic [ 63:0] sb_hrdata; + logic [ 63:0] sb_hwdata; + logic sb_hready; + logic sb_hresp; + + logic [ 63:0] trace_rv_i_insn_ip; + logic [ 63:0] trace_rv_i_address_ip; + logic [ 2:0] trace_rv_i_valid_ip; + logic [ 2:0] trace_rv_i_exception_ip; + logic [ 4:0] trace_rv_i_ecause_ip; + logic [ 2:0] trace_rv_i_interrupt_ip; + logic [ 31:0] trace_rv_i_tval_ip; + + logic o_debug_mode_status; + logic [ 1:0] dec_tlu_perfcnt0; + logic [ 1:0] dec_tlu_perfcnt1; + logic [ 1:0] dec_tlu_perfcnt2; + logic [ 1:0] dec_tlu_perfcnt3; + + logic o_cpu_halt_ack; + logic o_cpu_halt_status; + logic o_cpu_run_ack; + + logic mailbox_write; + logic [ 63:0] dma_hrdata; + logic [ 63:0] dma_hwdata; + logic dma_hready; + logic dma_hresp; + + logic mpc_debug_halt_req; + logic mpc_debug_run_req; + logic mpc_reset_run_req; + logic mpc_debug_halt_ack; + logic mpc_debug_run_ack; + logic debug_brkpt_status; + + wire dma_hready_out; + + + //-------------------------- LSU AXI signals-------------------------- + // AXI Write Channels + wire lsu_axi_awvalid; + wire lsu_axi_awready; + wire [`RV_LSU_BUS_TAG-1:0] lsu_axi_awid; + wire [ 31:0] lsu_axi_awaddr; + wire [ 3:0] lsu_axi_awregion; + wire [ 7:0] lsu_axi_awlen; + wire [ 2:0] lsu_axi_awsize; + wire [ 1:0] lsu_axi_awburst; + wire lsu_axi_awlock; + wire [ 3:0] lsu_axi_awcache; + wire [ 2:0] lsu_axi_awprot; + wire [ 3:0] lsu_axi_awqos; + + wire lsu_axi_wvalid; + wire lsu_axi_wready; + wire [ 63:0] lsu_axi_wdata; + wire [ 7:0] lsu_axi_wstrb; + wire lsu_axi_wlast; + + wire lsu_axi_bvalid; + wire lsu_axi_bready; + wire [ 1:0] lsu_axi_bresp; + wire [`RV_LSU_BUS_TAG-1:0] lsu_axi_bid; + + // AXI Read Channels + wire lsu_axi_arvalid; + wire lsu_axi_arready; + wire [`RV_LSU_BUS_TAG-1:0] lsu_axi_arid; + wire [ 31:0] lsu_axi_araddr; + wire [ 3:0] lsu_axi_arregion; + wire [ 7:0] lsu_axi_arlen; + wire [ 2:0] lsu_axi_arsize; + wire [ 1:0] lsu_axi_arburst; + wire lsu_axi_arlock; + wire [ 3:0] lsu_axi_arcache; + wire [ 2:0] lsu_axi_arprot; + wire [ 3:0] lsu_axi_arqos; + + wire lsu_axi_rvalid; + wire lsu_axi_rready; + wire [`RV_LSU_BUS_TAG-1:0] lsu_axi_rid; + wire [ 63:0] lsu_axi_rdata; + wire [ 1:0] lsu_axi_rresp; + wire lsu_axi_rlast; + + //-------------------------- IFU AXI signals-------------------------- + // AXI Write Channels + wire ifu_axi_awvalid; + wire ifu_axi_awready; + wire [`RV_IFU_BUS_TAG-1:0] ifu_axi_awid; + wire [ 31:0] ifu_axi_awaddr; + wire [ 3:0] ifu_axi_awregion; + wire [ 7:0] ifu_axi_awlen; + wire [ 2:0] ifu_axi_awsize; + wire [ 1:0] ifu_axi_awburst; + wire ifu_axi_awlock; + wire [ 3:0] ifu_axi_awcache; + wire [ 2:0] ifu_axi_awprot; + wire [ 3:0] ifu_axi_awqos; + + wire ifu_axi_wvalid; + wire ifu_axi_wready; + wire [ 63:0] ifu_axi_wdata; + wire [ 7:0] ifu_axi_wstrb; + wire ifu_axi_wlast; + + wire ifu_axi_bvalid; + wire ifu_axi_bready; + wire [ 1:0] ifu_axi_bresp; + wire [`RV_IFU_BUS_TAG-1:0] ifu_axi_bid; + + // AXI Read Channels + wire ifu_axi_arvalid; + wire ifu_axi_arready; + wire [`RV_IFU_BUS_TAG-1:0] ifu_axi_arid; + wire [ 31:0] ifu_axi_araddr; + wire [ 3:0] ifu_axi_arregion; + wire [ 7:0] ifu_axi_arlen; + wire [ 2:0] ifu_axi_arsize; + wire [ 1:0] ifu_axi_arburst; + wire ifu_axi_arlock; + wire [ 3:0] ifu_axi_arcache; + wire [ 2:0] ifu_axi_arprot; + wire [ 3:0] ifu_axi_arqos; + + wire ifu_axi_rvalid; + wire ifu_axi_rready; + wire [`RV_IFU_BUS_TAG-1:0] ifu_axi_rid; + wire [ 63:0] ifu_axi_rdata; + wire [ 1:0] ifu_axi_rresp; + wire ifu_axi_rlast; + + //-------------------------- SB AXI signals-------------------------- + // AXI Write Channels + wire sb_axi_awvalid; + wire sb_axi_awready; + wire [ `RV_SB_BUS_TAG-1:0] sb_axi_awid; + wire [ 31:0] sb_axi_awaddr; + wire [ 3:0] sb_axi_awregion; + wire [ 7:0] sb_axi_awlen; + wire [ 2:0] sb_axi_awsize; + wire [ 1:0] sb_axi_awburst; + wire sb_axi_awlock; + wire [ 3:0] sb_axi_awcache; + wire [ 2:0] sb_axi_awprot; + wire [ 3:0] sb_axi_awqos; + + wire sb_axi_wvalid; + wire sb_axi_wready; + wire [ 63:0] sb_axi_wdata; + wire [ 7:0] sb_axi_wstrb; + wire sb_axi_wlast; + + wire sb_axi_bvalid; + wire sb_axi_bready; + wire [ 1:0] sb_axi_bresp; + wire [ `RV_SB_BUS_TAG-1:0] sb_axi_bid; + + // AXI Read Channels + wire sb_axi_arvalid; + wire sb_axi_arready; + wire [ `RV_SB_BUS_TAG-1:0] sb_axi_arid; + wire [ 31:0] sb_axi_araddr; + wire [ 3:0] sb_axi_arregion; + wire [ 7:0] sb_axi_arlen; + wire [ 2:0] sb_axi_arsize; + wire [ 1:0] sb_axi_arburst; + wire sb_axi_arlock; + wire [ 3:0] sb_axi_arcache; + wire [ 2:0] sb_axi_arprot; + wire [ 3:0] sb_axi_arqos; + + wire sb_axi_rvalid; + wire sb_axi_rready; + wire [ `RV_SB_BUS_TAG-1:0] sb_axi_rid; + wire [ 63:0] sb_axi_rdata; + wire [ 1:0] sb_axi_rresp; + wire sb_axi_rlast; + + //-------------------------- DMA AXI signals-------------------------- + // AXI Write Channels + wire dma_axi_awvalid; + wire dma_axi_awready; + wire [`RV_DMA_BUS_TAG-1:0] dma_axi_awid; + wire [ 31:0] dma_axi_awaddr; + wire [ 2:0] dma_axi_awsize; + wire [ 2:0] dma_axi_awprot; + wire [ 7:0] dma_axi_awlen; + wire [ 1:0] dma_axi_awburst; + + + wire dma_axi_wvalid; + wire dma_axi_wready; + wire [ 63:0] dma_axi_wdata; + wire [ 7:0] dma_axi_wstrb; + wire dma_axi_wlast; + + wire dma_axi_bvalid; + wire dma_axi_bready; + wire [ 1:0] dma_axi_bresp; + wire [`RV_DMA_BUS_TAG-1:0] dma_axi_bid; + + // AXI Read Channels + wire dma_axi_arvalid; + wire dma_axi_arready; + wire [`RV_DMA_BUS_TAG-1:0] dma_axi_arid; + wire [ 31:0] dma_axi_araddr; + wire [ 2:0] dma_axi_arsize; + wire [ 2:0] dma_axi_arprot; + wire [ 7:0] dma_axi_arlen; + wire [ 1:0] dma_axi_arburst; + + wire dma_axi_rvalid; + wire dma_axi_rready; + wire [`RV_DMA_BUS_TAG-1:0] dma_axi_rid; + wire [ 63:0] dma_axi_rdata; + wire [ 1:0] dma_axi_rresp; + wire dma_axi_rlast; + + wire lmem_axi_arvalid; + wire lmem_axi_arready; + + wire lmem_axi_rvalid; + wire [`RV_LSU_BUS_TAG-1:0] lmem_axi_rid; + wire [ 1:0] lmem_axi_rresp; + wire [ 63:0] lmem_axi_rdata; + wire lmem_axi_rlast; + wire lmem_axi_rready; + + wire lmem_axi_awvalid; + wire lmem_axi_awready; + + wire lmem_axi_wvalid; + wire lmem_axi_wready; + + wire [ 1:0] lmem_axi_bresp; + wire lmem_axi_bvalid; + wire [`RV_LSU_BUS_TAG-1:0] lmem_axi_bid; + wire lmem_axi_bready; + + + initial begin + jtag_id[31:28] = 4'b1; + jtag_id[27:12] = '0; + jtag_id[11:1] = 11'h45; + reset_vector = `RV_RESET_VEC; + nmi_vector = 32'hee000000; + nmi_int = 0; + + $readmemh("program.hex", lmem.mem); + $readmemh("program.hex", imem.mem); + + end + + el2_swerv_wrapper rvtop ( + .rst_l (rst), + .dbg_rst_l(dbg_rst), + .clk (clk), + .rst_vec (reset_vector[31:1]), + .nmi_int (nmi_int), + .nmi_vec (nmi_vector[31:1]), + .jtag_id (jtag_id[31:1]), + + //-------------------------- LSU AXI signals-------------------------- + // AXI Write Channels + .lsu_axi_awvalid (lsu_axi_awvalid), + .lsu_axi_awready (lsu_axi_awready), + .lsu_axi_awid (lsu_axi_awid), + .lsu_axi_awaddr (lsu_axi_awaddr), + .lsu_axi_awregion(lsu_axi_awregion), + .lsu_axi_awlen (lsu_axi_awlen), + .lsu_axi_awsize (lsu_axi_awsize), + .lsu_axi_awburst (lsu_axi_awburst), + .lsu_axi_awlock (lsu_axi_awlock), + .lsu_axi_awcache (lsu_axi_awcache), + .lsu_axi_awprot (lsu_axi_awprot), + .lsu_axi_awqos (lsu_axi_awqos), + + .lsu_axi_wvalid(lsu_axi_wvalid), + .lsu_axi_wready(lsu_axi_wready), + .lsu_axi_wdata (lsu_axi_wdata), + .lsu_axi_wstrb (lsu_axi_wstrb), + .lsu_axi_wlast (lsu_axi_wlast), + + .lsu_axi_bvalid(lsu_axi_bvalid), + .lsu_axi_bready(lsu_axi_bready), + .lsu_axi_bresp (lsu_axi_bresp), + .lsu_axi_bid (lsu_axi_bid), + + + .lsu_axi_arvalid (lsu_axi_arvalid), + .lsu_axi_arready (lsu_axi_arready), + .lsu_axi_arid (lsu_axi_arid), + .lsu_axi_araddr (lsu_axi_araddr), + .lsu_axi_arregion(lsu_axi_arregion), + .lsu_axi_arlen (lsu_axi_arlen), + .lsu_axi_arsize (lsu_axi_arsize), + .lsu_axi_arburst (lsu_axi_arburst), + .lsu_axi_arlock (lsu_axi_arlock), + .lsu_axi_arcache (lsu_axi_arcache), + .lsu_axi_arprot (lsu_axi_arprot), + .lsu_axi_arqos (lsu_axi_arqos), + + .lsu_axi_rvalid(lsu_axi_rvalid), + .lsu_axi_rready(lsu_axi_rready), + .lsu_axi_rid (lsu_axi_rid), + .lsu_axi_rdata (lsu_axi_rdata), + .lsu_axi_rresp (lsu_axi_rresp), + .lsu_axi_rlast (lsu_axi_rlast), + + //-------------------------- IFU AXI signals-------------------------- + // AXI Write Channels + .ifu_axi_awvalid (ifu_axi_awvalid), + .ifu_axi_awready (ifu_axi_awready), + .ifu_axi_awid (ifu_axi_awid), + .ifu_axi_awaddr (ifu_axi_awaddr), + .ifu_axi_awregion(ifu_axi_awregion), + .ifu_axi_awlen (ifu_axi_awlen), + .ifu_axi_awsize (ifu_axi_awsize), + .ifu_axi_awburst (ifu_axi_awburst), + .ifu_axi_awlock (ifu_axi_awlock), + .ifu_axi_awcache (ifu_axi_awcache), + .ifu_axi_awprot (ifu_axi_awprot), + .ifu_axi_awqos (ifu_axi_awqos), + + .ifu_axi_wvalid(ifu_axi_wvalid), + .ifu_axi_wready(ifu_axi_wready), + .ifu_axi_wdata (ifu_axi_wdata), + .ifu_axi_wstrb (ifu_axi_wstrb), + .ifu_axi_wlast (ifu_axi_wlast), + + .ifu_axi_bvalid(ifu_axi_bvalid), + .ifu_axi_bready(ifu_axi_bready), + .ifu_axi_bresp (ifu_axi_bresp), + .ifu_axi_bid (ifu_axi_bid), + + .ifu_axi_arvalid (ifu_axi_arvalid), + .ifu_axi_arready (ifu_axi_arready), + .ifu_axi_arid (ifu_axi_arid), + .ifu_axi_araddr (ifu_axi_araddr), + .ifu_axi_arregion(ifu_axi_arregion), + .ifu_axi_arlen (ifu_axi_arlen), + .ifu_axi_arsize (ifu_axi_arsize), + .ifu_axi_arburst (ifu_axi_arburst), + .ifu_axi_arlock (ifu_axi_arlock), + .ifu_axi_arcache (ifu_axi_arcache), + .ifu_axi_arprot (ifu_axi_arprot), + .ifu_axi_arqos (ifu_axi_arqos), + + .ifu_axi_rvalid(ifu_axi_rvalid), + .ifu_axi_rready(ifu_axi_rready), + .ifu_axi_rid (ifu_axi_rid), + .ifu_axi_rdata (ifu_axi_rdata), + .ifu_axi_rresp (ifu_axi_rresp), + .ifu_axi_rlast (ifu_axi_rlast), + + //-------------------------- SB AXI signals-------------------------- + // AXI Write Channels + .sb_axi_awvalid (sb_axi_awvalid), + .sb_axi_awready (sb_axi_awready), + .sb_axi_awid (sb_axi_awid), + .sb_axi_awaddr (sb_axi_awaddr), + .sb_axi_awregion(sb_axi_awregion), + .sb_axi_awlen (sb_axi_awlen), + .sb_axi_awsize (sb_axi_awsize), + .sb_axi_awburst (sb_axi_awburst), + .sb_axi_awlock (sb_axi_awlock), + .sb_axi_awcache (sb_axi_awcache), + .sb_axi_awprot (sb_axi_awprot), + .sb_axi_awqos (sb_axi_awqos), + + .sb_axi_wvalid(sb_axi_wvalid), + .sb_axi_wready(sb_axi_wready), + .sb_axi_wdata (sb_axi_wdata), + .sb_axi_wstrb (sb_axi_wstrb), + .sb_axi_wlast (sb_axi_wlast), + + .sb_axi_bvalid(sb_axi_bvalid), + .sb_axi_bready(sb_axi_bready), + .sb_axi_bresp (sb_axi_bresp), + .sb_axi_bid (sb_axi_bid), + + + .sb_axi_arvalid (sb_axi_arvalid), + .sb_axi_arready (sb_axi_arready), + .sb_axi_arid (sb_axi_arid), + .sb_axi_araddr (sb_axi_araddr), + .sb_axi_arregion(sb_axi_arregion), + .sb_axi_arlen (sb_axi_arlen), + .sb_axi_arsize (sb_axi_arsize), + .sb_axi_arburst (sb_axi_arburst), + .sb_axi_arlock (sb_axi_arlock), + .sb_axi_arcache (sb_axi_arcache), + .sb_axi_arprot (sb_axi_arprot), + .sb_axi_arqos (sb_axi_arqos), + + .sb_axi_rvalid(sb_axi_rvalid), + .sb_axi_rready(sb_axi_rready), + .sb_axi_rid (sb_axi_rid), + .sb_axi_rdata (sb_axi_rdata), + .sb_axi_rresp (sb_axi_rresp), + .sb_axi_rlast (sb_axi_rlast), + + //-------------------------- DMA AXI signals-------------------------- + // AXI Write Channels + .dma_axi_awvalid(dma_axi_awvalid), + .dma_axi_awready(dma_axi_awready), + .dma_axi_awid ('0), // ids are not used on DMA since it always responses in order + .dma_axi_awaddr(lsu_axi_awaddr), + .dma_axi_awsize(lsu_axi_awsize), + .dma_axi_awprot('0), + .dma_axi_awlen('0), + .dma_axi_awburst('0), + + + .dma_axi_wvalid(dma_axi_wvalid), + .dma_axi_wready(dma_axi_wready), + .dma_axi_wdata (lsu_axi_wdata), + .dma_axi_wstrb (lsu_axi_wstrb), + .dma_axi_wlast (1'b1), + + .dma_axi_bvalid(dma_axi_bvalid), + .dma_axi_bready(dma_axi_bready), + .dma_axi_bresp (dma_axi_bresp), + .dma_axi_bid (), + + + .dma_axi_arvalid(dma_axi_arvalid), + .dma_axi_arready(dma_axi_arready), + .dma_axi_arid ('0), + .dma_axi_araddr (lsu_axi_araddr), + .dma_axi_arsize (lsu_axi_arsize), + .dma_axi_arprot ('0), + .dma_axi_arlen ('0), + .dma_axi_arburst('0), + + .dma_axi_rvalid(dma_axi_rvalid), + .dma_axi_rready(dma_axi_rready), + .dma_axi_rid (), + .dma_axi_rdata (dma_axi_rdata), + .dma_axi_rresp (dma_axi_rresp), + .dma_axi_rlast (dma_axi_rlast), + + .timer_int (1'b0), + .extintsrc_req('0), + + .lsu_bus_clk_en ( 1'b1 ),// Clock ratio b/w cpu core clk & AHB master interface + .ifu_bus_clk_en ( 1'b1 ),// Clock ratio b/w cpu core clk & AHB master interface + .dbg_bus_clk_en ( 1'b1 ),// Clock ratio b/w cpu core clk & AHB Debug master interface + .dma_bus_clk_en ( 1'b1 ),// Clock ratio b/w cpu core clk & AHB slave interface + + .trace_rv_i_insn_ip (trace_rv_i_insn_ip), + .trace_rv_i_address_ip (trace_rv_i_address_ip), + .trace_rv_i_valid_ip (trace_rv_i_valid_ip), + .trace_rv_i_exception_ip(trace_rv_i_exception_ip), + .trace_rv_i_ecause_ip (trace_rv_i_ecause_ip), + .trace_rv_i_interrupt_ip(trace_rv_i_interrupt_ip), + .trace_rv_i_tval_ip (trace_rv_i_tval_ip), + + .jtag_tck (jtag_tck), + .jtag_tms (jtag_tms), + .jtag_tdi (jtag_tdi), + .jtag_trst_n(jtag_trst_n), + .jtag_tdo (jtag_tdo), + + .mpc_debug_halt_ack(mpc_debug_halt_ack), + .mpc_debug_halt_req(1'b0), + .mpc_debug_run_ack (mpc_debug_run_ack), + .mpc_debug_run_req (1'b1), + .mpc_reset_run_req (1'b1), // Start running after reset + .debug_brkpt_status(debug_brkpt_status), + + .i_cpu_halt_req(1'b0), // Async halt req to CPU + .o_cpu_halt_ack(o_cpu_halt_ack), // core response to halt + .o_cpu_halt_status(o_cpu_halt_status), // 1'b1 indicates core is halted + .i_cpu_run_req(1'b0), // Async restart req to CPU + .o_debug_mode_status(o_debug_mode_status), + .o_cpu_run_ack(o_cpu_run_ack), // Core response to run req + + .dec_tlu_perfcnt0(), + .dec_tlu_perfcnt1(), + .dec_tlu_perfcnt2(), + .dec_tlu_perfcnt3(), + + // remove mems DFT pins for opensource + .dccm_ext_in_pkt ('0), + .iccm_ext_in_pkt ('0), + .ic_data_ext_in_pkt('0), + .ic_tag_ext_in_pkt ('0), + + .soft_int ('0), + .core_id ('0), + .scan_mode (1'b0), // To enable scan mode + .mbist_mode(1'b0) // to enable mbist + + ); + + axi_slv #( + .TAGW(`RV_IFU_BUS_TAG) + ) imem ( + .aclk(clk), + .rst_l(rst), + .arvalid(ifu_axi_arvalid), + .arready(ifu_axi_arready), + .araddr(ifu_axi_araddr), + .arid(ifu_axi_arid), + .arlen(ifu_axi_arlen), + .arburst(ifu_axi_arburst), + .arsize(ifu_axi_arsize), + + .rvalid(ifu_axi_rvalid), + .rready(ifu_axi_rready), + .rdata(ifu_axi_rdata), + .rresp(ifu_axi_rresp), + .rid(ifu_axi_rid), + .rlast(ifu_axi_rlast), + + .awvalid(1'b0), + .awready(), + .awaddr('0), + .awid('0), + .awlen('0), + .awburst('0), + .awsize('0), + + .wdata ('0), + .wstrb ('0), + .wvalid(1'b0), + .wready(), + + .bvalid(), + .bready(1'b0), + .bresp(), + .bid() + ); + + defparam lmem.TAGW = `RV_LSU_BUS_TAG; + + //axi_slv #(.TAGW(`RV_LSU_BUS_TAG)) lmem( + axi_slv lmem ( + .aclk(clk), + .rst_l(rst), + .arvalid(lmem_axi_arvalid), + .arready(lmem_axi_arready), + .araddr(lsu_axi_araddr), + .arid(lsu_axi_arid), + .arlen(lsu_axi_arlen), + .arburst(lsu_axi_arburst), + .arsize(lsu_axi_arsize), + + .rvalid(lmem_axi_rvalid), + .rready(lmem_axi_rready), + .rdata(lmem_axi_rdata), + .rresp(lmem_axi_rresp), + .rid(lmem_axi_rid), + .rlast(lmem_axi_rlast), + + .awvalid(lmem_axi_awvalid), + .awready(lmem_axi_awready), + .awaddr(lsu_axi_awaddr), + .awid(lsu_axi_awid), + .awlen(lsu_axi_awlen), + .awburst(lsu_axi_awburst), + .awsize(lsu_axi_awsize), + + .wdata (lsu_axi_wdata), + .wstrb (lsu_axi_wstrb), + .wvalid(lmem_axi_wvalid), + .wready(lmem_axi_wready), + + .bvalid(lmem_axi_bvalid), + .bready(lmem_axi_bready), + .bresp(lmem_axi_bresp), + .bid(lmem_axi_bid) + ); + + axi_lsu_dma_bridge #(`RV_LSU_BUS_TAG, `RV_LSU_BUS_TAG) bridge ( + .clk(clk), + .reset_l(rst), + + .m_arvalid(lsu_axi_arvalid), + .m_arid(lsu_axi_arid), + .m_araddr(lsu_axi_araddr), + .m_arready(lsu_axi_arready), + + .m_rvalid(lsu_axi_rvalid), + .m_rready(lsu_axi_rready), + .m_rdata(lsu_axi_rdata), + .m_rid(lsu_axi_rid), + .m_rresp(lsu_axi_rresp), + .m_rlast(lsu_axi_rlast), + + .m_awvalid(lsu_axi_awvalid), + .m_awid(lsu_axi_awid), + .m_awaddr(lsu_axi_awaddr), + .m_awready(lsu_axi_awready), + + .m_wvalid(lsu_axi_wvalid), + .m_wready(lsu_axi_wready), + + .m_bresp(lsu_axi_bresp), + .m_bvalid(lsu_axi_bvalid), + .m_bid(lsu_axi_bid), + .m_bready(lsu_axi_bready), + + .s0_arvalid(lmem_axi_arvalid), + .s0_arready(lmem_axi_arready), + + .s0_rvalid(lmem_axi_rvalid), + .s0_rid(lmem_axi_rid), + .s0_rresp(lmem_axi_rresp), + .s0_rdata(lmem_axi_rdata), + .s0_rlast(lmem_axi_rlast), + .s0_rready(lmem_axi_rready), + + .s0_awvalid(lmem_axi_awvalid), + .s0_awready(lmem_axi_awready), + + .s0_wvalid(lmem_axi_wvalid), + .s0_wready(lmem_axi_wready), + .s0_bresp(lmem_axi_bresp), + .s0_bvalid(lmem_axi_bvalid), + .s0_bid(lmem_axi_bid), + .s0_bready(lmem_axi_bready), + + + .s1_arvalid(dma_axi_arvalid), + .s1_arready(dma_axi_arready), + + .s1_rvalid(dma_axi_rvalid), + .s1_rresp (dma_axi_rresp), + .s1_rdata (dma_axi_rdata), + .s1_rlast (dma_axi_rlast), + .s1_rready(dma_axi_rready), + + .s1_awvalid(dma_axi_awvalid), + .s1_awready(dma_axi_awready), + + .s1_wvalid(dma_axi_wvalid), + .s1_wready(dma_axi_wready), + + .s1_bresp (dma_axi_bresp), + .s1_bvalid(dma_axi_bvalid), + .s1_bready(dma_axi_bready) + + ); + + +endmodule diff --git a/soc/swerv.config b/soc/swerv.config new file mode 100755 index 0000000..d333ad5 --- /dev/null +++ b/soc/swerv.config @@ -0,0 +1,2609 @@ +#! /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=8; +$btb_enable=1; +$btb_fullya=0; +$btb_toffset_size=12; +$btb_size=512; +$bht_size=512; +$dccm_enable=1; +$dccm_region="0xf"; +$dccm_offset="0x40000"; #1*256*1024 +$dccm_size=64; +$dccm_num_banks=4; +$iccm_enable=1; +$iccm_region="0xe"; +$top_align_iccm = 1; +$iccm_offset="0xe000000"; #0x380*256*1024 +$iccm_size=64; +$iccm_num_banks=4; +$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=1; +$icache_size=16; +$pic_2cycle=0; +$pic_region="0xf"; +$pic_offset="0xc0000"; # 3*256*1024 +$pic_size=32; +$pic_total_int=31; +$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; +} #}}} + + diff --git a/soc/swerv_config_gen.py b/soc/swerv_config_gen.py new file mode 100644 index 0000000..074d291 --- /dev/null +++ b/soc/swerv_config_gen.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 +from fusesoc.capi2.generator import Generator +import os +import subprocess +import sys + +class SwervConfigGenerator(Generator): + def run(self): + script_root = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '..')) + files = [ + {"common_defines.vh" : { + "copyto" : "config/common_defines.vh", + "file_type" : "systemVerilogSource"}}, + {"el2_pdef.vh" : { + "copyto" : "config/el2_pdef.vh", + "file_type" : "systemVerilogSource"}}, + {"el2_param.vh" : { + "is_include_file" : True, + "file_type" : "systemVerilogSource"}}, + {"pic_map_auto.h" : { + "is_include_file" : True, + "file_type" : "systemVerilogSource"}}] + + env = os.environ.copy() + env['RV_ROOT'] = script_root + env['BUILD_PATH'] = os.getcwd() + args = ['configs/swerv.config'] + self.config.get('args', []) + + rc = subprocess.call(args, cwd=script_root, env=env, stdout=subprocess.DEVNULL) + if rc: + exit(1) + filenames = [] + for f in files: + for k in f: + filenames.append(k) + + self.add_files(files) + +g = SwervConfigGenerator() +g.run() +g.write() diff --git a/tools/program.hex b/tools/program.hex new file mode 100755 index 0000000..1d3de9b --- /dev/null +++ b/tools/program.hex @@ -0,0 +1,26 @@ +@80000000 +73 10 20 B0 73 10 20 B8 B7 00 00 EE 73 90 50 30 +B7 50 55 5F 93 80 50 55 73 90 00 7C B7 01 58 D0 +17 02 00 00 13 02 E2 0E 83 02 02 00 23 80 51 00 +05 02 E3 9B 02 FE B7 01 58 D0 93 02 F0 0F 23 80 +51 00 E3 0A 00 FE 01 00 01 00 01 00 01 00 01 00 +01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00 +01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00 +01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00 +01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00 +01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00 +01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00 +01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00 +01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00 +01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00 +01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00 +01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00 +01 00 01 00 01 00 01 00 01 00 01 00 01 00 +@8000010E +2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D +2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D +2D 2D 0A 48 65 6C 6C 6F 20 57 6F 72 6C 64 20 66 +72 6F 6D 20 53 77 65 52 56 20 45 4C 32 20 40 57 +44 43 20 21 21 0A 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D +2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D +2D 2D 2D 2D 2D 2D 2D 2D 0A 00 diff --git a/tools/snapshots/default/common_defines.vh b/tools/snapshots/default/common_defines.vh new file mode 100644 index 0000000..002eded --- /dev/null +++ b/tools/snapshots/default/common_defines.vh @@ -0,0 +1,247 @@ +// NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE +// This is an automatically generated file by colin on Mon Mar 7 04:09:03 AM UTC 2022 +// +// cmd: swerv -target=default -set build_axi4 +// +`define RV_ROOT "/home/colin/develop/Cores-SweRV-EL2" +`define RV_NMI_VEC 'h11110000 +`define RV_NUMIREGS 32 +`define RV_BHT_GHR_RANGE 7:0 +`define RV_BHT_HASH_STRING {hashin[8+1:2]^ghr[8-1:0]}// cf2 +`define RV_BHT_ADDR_HI 9 +`define RV_BHT_GHR_SIZE 8 +`define RV_BHT_ARRAY_DEPTH 256 +`define RV_BHT_GHR_HASH_1 +`define RV_BHT_SIZE 512 +`define RV_BHT_ADDR_LO 2 +`define RV_RET_STACK_SIZE 8 +`define RV_CONFIG_KEY 32'hdeadbeef +`define RV_TARGET default +`define RV_DCCM_OFFSET 28'h40000 +`define RV_DCCM_REGION 4'hf +`define RV_DCCM_EADR 32'hf004ffff +`define RV_DCCM_SIZE 64 +`define RV_DCCM_SADR 32'hf0040000 +`define RV_DCCM_FDATA_WIDTH 39 +`define RV_DCCM_BANK_BITS 2 +`define RV_DCCM_NUM_BANKS_4 +`define RV_DCCM_ROWS 4096 +`define RV_DCCM_ENABLE 1 +`define RV_DCCM_INDEX_BITS 12 +`define RV_DCCM_BITS 16 +`define RV_DCCM_NUM_BANKS 4 +`define RV_LSU_SB_BITS 16 +`define RV_DCCM_DATA_WIDTH 32 +`define RV_DCCM_DATA_CELL ram_4096x39 +`define RV_DCCM_RESERVED 'h1400 +`define RV_DCCM_SIZE_64 +`define RV_DCCM_ECC_WIDTH 7 +`define RV_DCCM_WIDTH_BITS 2 +`define RV_DCCM_BYTE_WIDTH 4 +`define REGWIDTH 32 +`define RV_RESET_VEC 'h80000000 +`define RV_LSU_STBUF_DEPTH 4 +`define RV_BITMANIP_ZBR 0 +`define RV_BITMANIP_ZBS 1 +`define RV_BITMANIP_ZBF 0 +`define RV_FPGA_OPTIMIZE 1 +`define RV_DMA_BUF_DEPTH 5 +`define RV_BITMANIP_ZBC 1 +`define RV_BITMANIP_ZBE 0 +`define RV_ICCM_ICACHE 1 +`define RV_FAST_INTERRUPT_REDIRECT 1 +`define RV_LSU_NUM_NBLOAD 4 +`define RV_BITMANIP_ZBA 1 +`define RV_BITMANIP_ZBP 0 +`define RV_LSU2DMA 0 +`define RV_LSU_NUM_NBLOAD_WIDTH 2 +`define RV_DIV_BIT 4 +`define RV_BITMANIP_ZBB 1 +`define RV_TIMER_LEGAL_EN 1 +`define RV_DIV_NEW 1 +`define RV_SERIALIO 'hd0580000 +`define RV_EXTERNAL_DATA 'hc0580000 +`define RV_UNUSED_REGION5 'h30000000 +`define RV_UNUSED_REGION4 'h40000000 +`define RV_UNUSED_REGION1 'h70000000 +`define RV_UNUSED_REGION8 'h00000000 +`define RV_UNUSED_REGION2 'h60000000 +`define RV_UNUSED_REGION7 'h10000000 +`define RV_DEBUG_SB_MEM 'ha0580000 +`define RV_UNUSED_REGION6 'h20000000 +`define RV_UNUSED_REGION3 'h50000000 +`define RV_EXTERNAL_DATA_1 'hb0000000 +`define RV_UNUSED_REGION0 'h90000000 +`define RV_ICCM_NUM_BANKS 4 +`define RV_ICCM_BITS 16 +`define RV_ICCM_INDEX_BITS 12 +`define RV_ICCM_ENABLE 1 +`define RV_ICCM_SIZE_64 +`define RV_ICCM_DATA_CELL ram_4096x39 +`define RV_ICCM_RESERVED 'h1000 +`define RV_ICCM_BANK_INDEX_LO 4 +`define RV_ICCM_SADR 32'hee000000 +`define RV_ICCM_EADR 32'hee00ffff +`define RV_ICCM_OFFSET 10'he000000 +`define RV_ICCM_REGION 4'he +`define RV_ICCM_SIZE 64 +`define RV_ICCM_NUM_BANKS_4 +`define RV_ICCM_ROWS 4096 +`define RV_ICCM_BANK_HI 3 +`define RV_ICCM_BANK_BITS 2 +`define RV_PIC_MEIPL_MASK 'hf +`define RV_PIC_MEIPL_COUNT 31 +`define RV_PIC_MEIE_COUNT 31 +`define RV_PIC_MEIP_MASK 'h0 +`define RV_PIC_MEIPT_OFFSET 'h3004 +`define RV_PIC_REGION 4'hf +`define RV_PIC_TOTAL_INT 31 +`define RV_PIC_MEIGWCTRL_OFFSET 'h4000 +`define RV_PIC_MEIP_COUNT 1 +`define RV_PIC_MEIE_MASK 'h1 +`define RV_PIC_MPICCFG_OFFSET 'h3000 +`define RV_PIC_MEIGWCLR_MASK 'h0 +`define RV_PIC_MEIGWCLR_COUNT 31 +`define RV_PIC_INT_WORDS 1 +`define RV_PIC_OFFSET 10'hc0000 +`define RV_PIC_MEIP_OFFSET 'h1000 +`define RV_PIC_BITS 15 +`define RV_PIC_MPICCFG_COUNT 1 +`define RV_PIC_MEIGWCLR_OFFSET 'h5000 +`define RV_PIC_SIZE 32 +`define RV_PIC_MPICCFG_MASK 'h1 +`define RV_PIC_TOTAL_INT_PLUS1 32 +`define RV_PIC_MEIPL_OFFSET 'h0000 +`define RV_PIC_MEIGWCTRL_COUNT 31 +`define RV_PIC_BASE_ADDR 32'hf00c0000 +`define RV_PIC_MEIPT_MASK 'h0 +`define RV_PIC_MEIE_OFFSET 'h2000 +`define RV_PIC_MEIGWCTRL_MASK 'h3 +`define RV_PIC_MEIPT_COUNT 31 +`define RV_INST_ACCESS_ADDR2 'h00000000 +`define RV_DATA_ACCESS_MASK6 'hffffffff +`define RV_DATA_ACCESS_ENABLE0 1'h0 +`define RV_INST_ACCESS_ENABLE4 1'h0 +`define RV_INST_ACCESS_MASK1 'hffffffff +`define RV_INST_ACCESS_ADDR5 'h00000000 +`define RV_INST_ACCESS_ENABLE1 1'h0 +`define RV_INST_ACCESS_MASK4 'hffffffff +`define RV_DATA_ACCESS_ADDR2 'h00000000 +`define RV_INST_ACCESS_MASK6 'hffffffff +`define RV_INST_ACCESS_ENABLE0 1'h0 +`define RV_DATA_ACCESS_ADDR5 'h00000000 +`define RV_DATA_ACCESS_MASK1 'hffffffff +`define RV_DATA_ACCESS_ENABLE4 1'h0 +`define RV_DATA_ACCESS_ENABLE1 1'h0 +`define RV_DATA_ACCESS_MASK4 'hffffffff +`define RV_DATA_ACCESS_ENABLE6 1'h0 +`define RV_INST_ACCESS_MASK7 'hffffffff +`define RV_INST_ACCESS_ENABLE5 1'h0 +`define RV_DATA_ACCESS_MASK0 'hffffffff +`define RV_INST_ACCESS_ADDR3 'h00000000 +`define RV_INST_ACCESS_ENABLE6 1'h0 +`define RV_DATA_ACCESS_MASK7 'hffffffff +`define RV_DATA_ACCESS_ENABLE5 1'h0 +`define RV_INST_ACCESS_MASK0 'hffffffff +`define RV_DATA_ACCESS_ADDR3 'h00000000 +`define RV_DATA_ACCESS_ENABLE3 1'h0 +`define RV_DATA_ACCESS_ADDR0 'h00000000 +`define RV_INST_ACCESS_MASK3 'hffffffff +`define RV_DATA_ACCESS_ENABLE2 1'h0 +`define RV_INST_ACCESS_ADDR7 'h00000000 +`define RV_INST_ACCESS_ENABLE3 1'h0 +`define RV_INST_ACCESS_ADDR0 'h00000000 +`define RV_DATA_ACCESS_MASK3 'hffffffff +`define RV_DATA_ACCESS_ADDR7 'h00000000 +`define RV_INST_ACCESS_ENABLE2 1'h0 +`define RV_INST_ACCESS_MASK5 'hffffffff +`define RV_INST_ACCESS_ADDR1 'h00000000 +`define RV_INST_ACCESS_ADDR4 'h00000000 +`define RV_INST_ACCESS_MASK2 'hffffffff +`define RV_INST_ACCESS_ENABLE7 1'h0 +`define RV_DATA_ACCESS_ADDR6 'h00000000 +`define RV_DATA_ACCESS_ADDR1 'h00000000 +`define RV_DATA_ACCESS_MASK5 'hffffffff +`define RV_DATA_ACCESS_ADDR4 'h00000000 +`define RV_DATA_ACCESS_MASK2 'hffffffff +`define RV_DATA_ACCESS_ENABLE7 1'h0 +`define RV_INST_ACCESS_ADDR6 'h00000000 +`define RV_IFU_BUS_PRTY 2 +`define RV_SB_BUS_PRTY 2 +`define RV_LSU_BUS_ID 1 +`define RV_LSU_BUS_TAG 3 +`define RV_SB_BUS_TAG 1 +`define RV_DMA_BUS_ID 1 +`define RV_DMA_BUS_TAG 1 +`define RV_LSU_BUS_PRTY 2 +`define RV_BUS_PRTY_DEFAULT 2'h3 +`define RV_SB_BUS_ID 1 +`define RV_DMA_BUS_PRTY 2 +`define RV_IFU_BUS_ID 1 +`define RV_IFU_BUS_TAG 3 +`define RV_XLEN 32 +`define RV_BTB_INDEX3_LO 18 +`define RV_BTB_INDEX1_LO 2 +`define RV_BTB_ADDR_HI 9 +`define RV_BTB_INDEX2_LO 10 +`define RV_BTB_SIZE 512 +`define RV_BTB_BTAG_FOLD 0 +`define RV_BTB_ADDR_LO 2 +`define RV_BTB_INDEX2_HI 17 +`define RV_BTB_ENABLE 1 +`define RV_BTB_TOFFSET_SIZE 12 +`define RV_BTB_INDEX3_HI 25 +`define RV_BTB_ARRAY_DEPTH 256 +`define RV_BTB_BTAG_SIZE 5 +`define RV_BTB_INDEX1_HI 9 +`define RV_BTB_FOLD2_INDEX_HASH 0 +`define TEC_RV_ICG clockhdr +`define RV_ASSERT_ON +`define RV_STERR_ROLLBACK 0 +`define RV_BUILD_AXI4 1 +`define SDVT_AHB 0 +`define RV_EXT_DATAWIDTH 64 +`define RV_EXT_ADDRWIDTH 32 +`define TOP tb_top +`define RV_LDERR_ROLLBACK 1 +`define RV_BUILD_AXI_NATIVE 1 +`define RV_TOP `TOP.rvtop +`define CLOCK_PERIOD 100 +`define CPU_TOP `RV_TOP.swerv +`define RV_ICACHE_INDEX_HI 12 +`define RV_ICACHE_TAG_CELL ram_128x25 +`define RV_ICACHE_NUM_BEATS 8 +`define RV_ICACHE_FDATA_WIDTH 71 +`define RV_ICACHE_NUM_BYPASS_WIDTH 2 +`define RV_ICACHE_TAG_DEPTH 128 +`define RV_ICACHE_TAG_BYPASS_ENABLE 1 +`define RV_ICACHE_SIZE 16 +`define RV_ICACHE_TAG_NUM_BYPASS 2 +`define RV_ICACHE_BANK_WIDTH 8 +`define RV_ICACHE_DATA_INDEX_LO 4 +`define RV_ICACHE_2BANKS 1 +`define RV_ICACHE_NUM_LINES_BANK 64 +`define RV_ICACHE_ECC 1 +`define RV_ICACHE_STATUS_BITS 1 +`define RV_ICACHE_TAG_NUM_BYPASS_WIDTH 2 +`define RV_ICACHE_BEAT_BITS 3 +`define RV_ICACHE_DATA_WIDTH 64 +`define RV_ICACHE_BYPASS_ENABLE 1 +`define RV_ICACHE_WAYPACK 1 +`define RV_ICACHE_NUM_BYPASS 2 +`define RV_ICACHE_DATA_DEPTH 512 +`define RV_ICACHE_BEAT_ADDR_HI 5 +`define RV_ICACHE_TAG_LO 13 +`define RV_ICACHE_BANK_BITS 1 +`define RV_ICACHE_ENABLE 1 +`define RV_ICACHE_BANK_HI 3 +`define RV_ICACHE_NUM_LINES 256 +`define RV_ICACHE_TAG_INDEX_LO 6 +`define RV_ICACHE_LN_SZ 64 +`define RV_ICACHE_NUM_LINES_WAY 128 +`define RV_ICACHE_DATA_CELL ram_512x71 +`define RV_ICACHE_BANKS_WAY 2 +`define RV_ICACHE_NUM_WAYS 2 +`define RV_ICACHE_SCND_LAST 6 +`define RV_ICACHE_BANK_LO 3 +`undef RV_ASSERT_ON diff --git a/tools/snapshots/default/defines.h b/tools/snapshots/default/defines.h new file mode 100644 index 0000000..1a96cc2 --- /dev/null +++ b/tools/snapshots/default/defines.h @@ -0,0 +1,176 @@ +// NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE +// This is an automatically generated file by colin on Mon Mar 7 04:09:03 AM UTC 2022 +// +// cmd: swerv -target=default -set build_axi4 +// +#ifndef RV_NMI_VEC +#define RV_NMI_VEC 0x11110000 +#endif +#define RV_TARGET default +#define RV_DCCM_OFFSET 0x40000 +#define RV_DCCM_REGION 0xf +#define RV_DCCM_EADR 0xf004ffff +#define RV_DCCM_SIZE 64 +#define RV_DCCM_SADR 0xf0040000 +#define RV_DCCM_FDATA_WIDTH 39 +#define RV_DCCM_BANK_BITS 2 +#define RV_DCCM_NUM_BANKS_4 +#define RV_DCCM_ROWS 4096 +#define RV_DCCM_ENABLE 1 +#define RV_DCCM_INDEX_BITS 12 +#define RV_DCCM_BITS 16 +#define RV_DCCM_NUM_BANKS 4 +#define RV_LSU_SB_BITS 16 +#define RV_DCCM_DATA_WIDTH 32 +#define RV_DCCM_DATA_CELL ram_4096x39 +#define RV_DCCM_RESERVED 0x1400 +#define RV_DCCM_SIZE_64 +#define RV_DCCM_ECC_WIDTH 7 +#define RV_DCCM_WIDTH_BITS 2 +#define RV_DCCM_BYTE_WIDTH 4 +#ifndef RV_RESET_VEC +#define RV_RESET_VEC 0x80000000 +#endif +#define RV_LSU_STBUF_DEPTH 4 +#define RV_BITMANIP_ZBR 0 +#define RV_BITMANIP_ZBS 1 +#define RV_BITMANIP_ZBF 0 +#define RV_FPGA_OPTIMIZE 1 +#define RV_DMA_BUF_DEPTH 5 +#define RV_BITMANIP_ZBC 1 +#define RV_BITMANIP_ZBE 0 +#define RV_ICCM_ICACHE 1 +#define RV_FAST_INTERRUPT_REDIRECT 1 +#define RV_LSU_NUM_NBLOAD 4 +#define RV_BITMANIP_ZBA 1 +#define RV_BITMANIP_ZBP 0 +#define RV_LSU2DMA 0 +#define RV_LSU_NUM_NBLOAD_WIDTH 2 +#define RV_DIV_BIT 4 +#define RV_BITMANIP_ZBB 1 +#define RV_TIMER_LEGAL_EN 1 +#define RV_DIV_NEW 1 +#ifndef RV_SERIALIO +#define RV_SERIALIO 0xd0580000 +#endif +#ifndef RV_EXTERNAL_DATA +#define RV_EXTERNAL_DATA 0xc0580000 +#endif +#define RV_UNUSED_REGION5 0x30000000 +#define RV_UNUSED_REGION4 0x40000000 +#define RV_UNUSED_REGION1 0x70000000 +#define RV_UNUSED_REGION8 0x00000000 +#define RV_UNUSED_REGION2 0x60000000 +#define RV_UNUSED_REGION7 0x10000000 +#define RV_DEBUG_SB_MEM 0xa0580000 +#define RV_UNUSED_REGION6 0x20000000 +#define RV_UNUSED_REGION3 0x50000000 +#define RV_EXTERNAL_DATA_1 0xb0000000 +#define RV_UNUSED_REGION0 0x90000000 +#define RV_ICCM_NUM_BANKS 4 +#define RV_ICCM_BITS 16 +#define RV_ICCM_INDEX_BITS 12 +#define RV_ICCM_ENABLE 1 +#define RV_ICCM_SIZE_64 +#define RV_ICCM_DATA_CELL ram_4096x39 +#define RV_ICCM_RESERVED 0x1000 +#define RV_ICCM_BANK_INDEX_LO 4 +#define RV_ICCM_SADR 0xee000000 +#define RV_ICCM_EADR 0xee00ffff +#define RV_ICCM_OFFSET 0xe000000 +#define RV_ICCM_REGION 0xe +#define RV_ICCM_SIZE 64 +#define RV_ICCM_NUM_BANKS_4 +#define RV_ICCM_ROWS 4096 +#define RV_ICCM_BANK_HI 3 +#define RV_ICCM_BANK_BITS 2 +#define RV_PIC_MEIPL_MASK 0xf +#define RV_PIC_MEIPL_COUNT 31 +#define RV_PIC_MEIE_COUNT 31 +#define RV_PIC_MEIP_MASK 0x0 +#define RV_PIC_MEIPT_OFFSET 0x3004 +#define RV_PIC_REGION 0xf +#define RV_PIC_TOTAL_INT 31 +#define RV_PIC_MEIGWCTRL_OFFSET 0x4000 +#define RV_PIC_MEIP_COUNT 1 +#define RV_PIC_MEIE_MASK 0x1 +#define RV_PIC_MPICCFG_OFFSET 0x3000 +#define RV_PIC_MEIGWCLR_MASK 0x0 +#define RV_PIC_MEIGWCLR_COUNT 31 +#define RV_PIC_INT_WORDS 1 +#define RV_PIC_OFFSET 0xc0000 +#define RV_PIC_MEIP_OFFSET 0x1000 +#define RV_PIC_BITS 15 +#define RV_PIC_MPICCFG_COUNT 1 +#define RV_PIC_MEIGWCLR_OFFSET 0x5000 +#define RV_PIC_SIZE 32 +#define RV_PIC_MPICCFG_MASK 0x1 +#define RV_PIC_TOTAL_INT_PLUS1 32 +#define RV_PIC_MEIPL_OFFSET 0x0000 +#define RV_PIC_MEIGWCTRL_COUNT 31 +#define RV_PIC_BASE_ADDR 0xf00c0000 +#define RV_PIC_MEIPT_MASK 0x0 +#define RV_PIC_MEIE_OFFSET 0x2000 +#define RV_PIC_MEIGWCTRL_MASK 0x3 +#define RV_PIC_MEIPT_COUNT 31 +#define RV_INST_ACCESS_ADDR2 0x00000000 +#define RV_DATA_ACCESS_MASK6 0xffffffff +#define RV_DATA_ACCESS_ENABLE0 0x0 +#define RV_INST_ACCESS_ENABLE4 0x0 +#define RV_INST_ACCESS_MASK1 0xffffffff +#define RV_INST_ACCESS_ADDR5 0x00000000 +#define RV_INST_ACCESS_ENABLE1 0x0 +#define RV_INST_ACCESS_MASK4 0xffffffff +#define RV_DATA_ACCESS_ADDR2 0x00000000 +#define RV_INST_ACCESS_MASK6 0xffffffff +#define RV_INST_ACCESS_ENABLE0 0x0 +#define RV_DATA_ACCESS_ADDR5 0x00000000 +#define RV_DATA_ACCESS_MASK1 0xffffffff +#define RV_DATA_ACCESS_ENABLE4 0x0 +#define RV_DATA_ACCESS_ENABLE1 0x0 +#define RV_DATA_ACCESS_MASK4 0xffffffff +#define RV_DATA_ACCESS_ENABLE6 0x0 +#define RV_INST_ACCESS_MASK7 0xffffffff +#define RV_INST_ACCESS_ENABLE5 0x0 +#define RV_DATA_ACCESS_MASK0 0xffffffff +#define RV_INST_ACCESS_ADDR3 0x00000000 +#define RV_INST_ACCESS_ENABLE6 0x0 +#define RV_DATA_ACCESS_MASK7 0xffffffff +#define RV_DATA_ACCESS_ENABLE5 0x0 +#define RV_INST_ACCESS_MASK0 0xffffffff +#define RV_DATA_ACCESS_ADDR3 0x00000000 +#define RV_DATA_ACCESS_ENABLE3 0x0 +#define RV_DATA_ACCESS_ADDR0 0x00000000 +#define RV_INST_ACCESS_MASK3 0xffffffff +#define RV_DATA_ACCESS_ENABLE2 0x0 +#define RV_INST_ACCESS_ADDR7 0x00000000 +#define RV_INST_ACCESS_ENABLE3 0x0 +#define RV_INST_ACCESS_ADDR0 0x00000000 +#define RV_DATA_ACCESS_MASK3 0xffffffff +#define RV_DATA_ACCESS_ADDR7 0x00000000 +#define RV_INST_ACCESS_ENABLE2 0x0 +#define RV_INST_ACCESS_MASK5 0xffffffff +#define RV_INST_ACCESS_ADDR1 0x00000000 +#define RV_INST_ACCESS_ADDR4 0x00000000 +#define RV_INST_ACCESS_MASK2 0xffffffff +#define RV_INST_ACCESS_ENABLE7 0x0 +#define RV_DATA_ACCESS_ADDR6 0x00000000 +#define RV_DATA_ACCESS_ADDR1 0x00000000 +#define RV_DATA_ACCESS_MASK5 0xffffffff +#define RV_DATA_ACCESS_ADDR4 0x00000000 +#define RV_DATA_ACCESS_MASK2 0xffffffff +#define RV_DATA_ACCESS_ENABLE7 0x0 +#define RV_INST_ACCESS_ADDR6 0x00000000 +#define RV_XLEN 32 +#define RV_ASSERT_ON +#define RV_STERR_ROLLBACK 0 +#define RV_BUILD_AXI4 1 +#define SDVT_AHB 0 +#define RV_EXT_DATAWIDTH 64 +#define RV_EXT_ADDRWIDTH 32 +#define TOP tb_top +#define RV_LDERR_ROLLBACK 1 +#define RV_BUILD_AXI_NATIVE 1 +#define RV_TOP `TOP.rvtop +#define CLOCK_PERIOD 100 +#define CPU_TOP `RV_TOP.swerv diff --git a/tools/snapshots/default/el2_param.vh b/tools/snapshots/default/el2_param.vh new file mode 100644 index 0000000..2ed3ba7 --- /dev/null +++ b/tools/snapshots/default/el2_param.vh @@ -0,0 +1,175 @@ +parameter el2_param_t pt = '{ + BHT_ADDR_HI : 8'h09 , + BHT_ADDR_LO : 6'h02 , + BHT_ARRAY_DEPTH : 15'h0100 , + BHT_GHR_HASH_1 : 5'h00 , + BHT_GHR_SIZE : 8'h08 , + BHT_SIZE : 16'h0200 , + BITMANIP_ZBA : 5'h01 , + BITMANIP_ZBB : 5'h01 , + BITMANIP_ZBC : 5'h01 , + BITMANIP_ZBE : 5'h00 , + BITMANIP_ZBF : 5'h00 , + BITMANIP_ZBP : 5'h00 , + BITMANIP_ZBR : 5'h00 , + BITMANIP_ZBS : 5'h01 , + BTB_ADDR_HI : 9'h009 , + BTB_ADDR_LO : 6'h02 , + BTB_ARRAY_DEPTH : 13'h0100 , + BTB_BTAG_FOLD : 5'h00 , + BTB_BTAG_SIZE : 9'h005 , + BTB_ENABLE : 5'h01 , + BTB_FOLD2_INDEX_HASH : 5'h00 , + BTB_FULLYA : 5'h00 , + BTB_INDEX1_HI : 9'h009 , + BTB_INDEX1_LO : 9'h002 , + BTB_INDEX2_HI : 9'h011 , + BTB_INDEX2_LO : 9'h00A , + BTB_INDEX3_HI : 9'h019 , + BTB_INDEX3_LO : 9'h012 , + BTB_SIZE : 14'h0200 , + BTB_TOFFSET_SIZE : 9'h00C , + BUILD_AHB_LITE : 4'h0 , + BUILD_AXI4 : 5'h01 , + BUILD_AXI_NATIVE : 5'h01 , + BUS_PRTY_DEFAULT : 6'h03 , + DATA_ACCESS_ADDR0 : 36'h000000000 , + DATA_ACCESS_ADDR1 : 36'h000000000 , + DATA_ACCESS_ADDR2 : 36'h000000000 , + DATA_ACCESS_ADDR3 : 36'h000000000 , + DATA_ACCESS_ADDR4 : 36'h000000000 , + DATA_ACCESS_ADDR5 : 36'h000000000 , + DATA_ACCESS_ADDR6 : 36'h000000000 , + DATA_ACCESS_ADDR7 : 36'h000000000 , + DATA_ACCESS_ENABLE0 : 5'h00 , + DATA_ACCESS_ENABLE1 : 5'h00 , + DATA_ACCESS_ENABLE2 : 5'h00 , + DATA_ACCESS_ENABLE3 : 5'h00 , + DATA_ACCESS_ENABLE4 : 5'h00 , + DATA_ACCESS_ENABLE5 : 5'h00 , + DATA_ACCESS_ENABLE6 : 5'h00 , + DATA_ACCESS_ENABLE7 : 5'h00 , + DATA_ACCESS_MASK0 : 36'h0FFFFFFFF , + DATA_ACCESS_MASK1 : 36'h0FFFFFFFF , + DATA_ACCESS_MASK2 : 36'h0FFFFFFFF , + DATA_ACCESS_MASK3 : 36'h0FFFFFFFF , + DATA_ACCESS_MASK4 : 36'h0FFFFFFFF , + DATA_ACCESS_MASK5 : 36'h0FFFFFFFF , + DATA_ACCESS_MASK6 : 36'h0FFFFFFFF , + DATA_ACCESS_MASK7 : 36'h0FFFFFFFF , + DCCM_BANK_BITS : 7'h02 , + DCCM_BITS : 9'h010 , + DCCM_BYTE_WIDTH : 7'h04 , + DCCM_DATA_WIDTH : 10'h020 , + DCCM_ECC_WIDTH : 7'h07 , + DCCM_ENABLE : 5'h01 , + DCCM_FDATA_WIDTH : 10'h027 , + DCCM_INDEX_BITS : 8'h0C , + DCCM_NUM_BANKS : 9'h004 , + DCCM_REGION : 8'h0F , + DCCM_SADR : 36'h0F0040000 , + DCCM_SIZE : 14'h0040 , + DCCM_WIDTH_BITS : 6'h02 , + DIV_BIT : 7'h04 , + DIV_NEW : 5'h01 , + DMA_BUF_DEPTH : 7'h05 , + DMA_BUS_ID : 9'h001 , + DMA_BUS_PRTY : 6'h02 , + DMA_BUS_TAG : 8'h01 , + FAST_INTERRUPT_REDIRECT : 5'h01 , + ICACHE_2BANKS : 5'h01 , + ICACHE_BANK_BITS : 7'h01 , + ICACHE_BANK_HI : 7'h03 , + ICACHE_BANK_LO : 6'h03 , + ICACHE_BANK_WIDTH : 8'h08 , + ICACHE_BANKS_WAY : 7'h02 , + ICACHE_BEAT_ADDR_HI : 8'h05 , + ICACHE_BEAT_BITS : 8'h03 , + ICACHE_BYPASS_ENABLE : 5'h01 , + ICACHE_DATA_DEPTH : 18'h00200 , + ICACHE_DATA_INDEX_LO : 7'h04 , + ICACHE_DATA_WIDTH : 11'h040 , + ICACHE_ECC : 5'h01 , + ICACHE_ENABLE : 5'h01 , + ICACHE_FDATA_WIDTH : 11'h047 , + ICACHE_INDEX_HI : 9'h00C , + ICACHE_LN_SZ : 11'h040 , + ICACHE_NUM_BEATS : 8'h08 , + ICACHE_NUM_BYPASS : 8'h02 , + ICACHE_NUM_BYPASS_WIDTH : 8'h02 , + ICACHE_NUM_WAYS : 7'h02 , + ICACHE_ONLY : 5'h00 , + ICACHE_SCND_LAST : 8'h06 , + ICACHE_SIZE : 13'h0010 , + ICACHE_STATUS_BITS : 7'h01 , + ICACHE_TAG_BYPASS_ENABLE : 5'h01 , + ICACHE_TAG_DEPTH : 17'h00080 , + ICACHE_TAG_INDEX_LO : 7'h06 , + ICACHE_TAG_LO : 9'h00D , + ICACHE_TAG_NUM_BYPASS : 8'h02 , + ICACHE_TAG_NUM_BYPASS_WIDTH : 8'h02 , + ICACHE_WAYPACK : 5'h01 , + ICCM_BANK_BITS : 7'h02 , + ICCM_BANK_HI : 9'h003 , + ICCM_BANK_INDEX_LO : 9'h004 , + ICCM_BITS : 9'h010 , + ICCM_ENABLE : 5'h01 , + ICCM_ICACHE : 5'h01 , + ICCM_INDEX_BITS : 8'h0C , + ICCM_NUM_BANKS : 9'h004 , + ICCM_ONLY : 5'h00 , + ICCM_REGION : 8'h0E , + ICCM_SADR : 36'h0EE000000 , + ICCM_SIZE : 14'h0040 , + IFU_BUS_ID : 5'h01 , + IFU_BUS_PRTY : 6'h02 , + IFU_BUS_TAG : 8'h03 , + INST_ACCESS_ADDR0 : 36'h000000000 , + INST_ACCESS_ADDR1 : 36'h000000000 , + INST_ACCESS_ADDR2 : 36'h000000000 , + INST_ACCESS_ADDR3 : 36'h000000000 , + INST_ACCESS_ADDR4 : 36'h000000000 , + INST_ACCESS_ADDR5 : 36'h000000000 , + INST_ACCESS_ADDR6 : 36'h000000000 , + INST_ACCESS_ADDR7 : 36'h000000000 , + INST_ACCESS_ENABLE0 : 5'h00 , + INST_ACCESS_ENABLE1 : 5'h00 , + INST_ACCESS_ENABLE2 : 5'h00 , + INST_ACCESS_ENABLE3 : 5'h00 , + INST_ACCESS_ENABLE4 : 5'h00 , + INST_ACCESS_ENABLE5 : 5'h00 , + INST_ACCESS_ENABLE6 : 5'h00 , + INST_ACCESS_ENABLE7 : 5'h00 , + INST_ACCESS_MASK0 : 36'h0FFFFFFFF , + INST_ACCESS_MASK1 : 36'h0FFFFFFFF , + INST_ACCESS_MASK2 : 36'h0FFFFFFFF , + INST_ACCESS_MASK3 : 36'h0FFFFFFFF , + INST_ACCESS_MASK4 : 36'h0FFFFFFFF , + INST_ACCESS_MASK5 : 36'h0FFFFFFFF , + INST_ACCESS_MASK6 : 36'h0FFFFFFFF , + INST_ACCESS_MASK7 : 36'h0FFFFFFFF , + LOAD_TO_USE_PLUS1 : 5'h00 , + LSU2DMA : 5'h00 , + LSU_BUS_ID : 5'h01 , + LSU_BUS_PRTY : 6'h02 , + LSU_BUS_TAG : 8'h03 , + LSU_NUM_NBLOAD : 9'h004 , + LSU_NUM_NBLOAD_WIDTH : 7'h02 , + LSU_SB_BITS : 9'h010 , + LSU_STBUF_DEPTH : 8'h04 , + NO_ICCM_NO_ICACHE : 5'h00 , + PIC_2CYCLE : 5'h00 , + PIC_BASE_ADDR : 36'h0F00C0000 , + PIC_BITS : 9'h00F , + PIC_INT_WORDS : 8'h01 , + PIC_REGION : 8'h0F , + PIC_SIZE : 13'h0020 , + PIC_TOTAL_INT : 12'h01F , + PIC_TOTAL_INT_PLUS1 : 13'h0020 , + RET_STACK_SIZE : 8'h08 , + SB_BUS_ID : 5'h01 , + SB_BUS_PRTY : 6'h02 , + SB_BUS_TAG : 8'h01 , + TIMER_LEGAL_EN : 5'h01 +} +// parameter el2_param_t pt = 2271'h04840400010040010840000020908200002840004808220A0C848200060210C00000000000000000000000000000000000000000000000000000000000000000000000000000000003FFFFFFFC3FFFFFFFC3FFFFFFFC3FFFFFFFC3FFFFFFFC3FFFFFFFC3FFFFFFFC3FFFFFFFC104020401C213860103C3C01000000400820428042010840830C2010281840200081002108E0C0801004040800C01002100400606810104100C0810084300800E0EE00000001002101800000000000000000000000000000000000000000000000000000000000000000000000000000000007FFFFFFF87FFFFFFF87FFFFFFF87FFFFFFF87FFFFFFF87FFFFFFF87FFFFFFF87FFFFFFF8001080C080820080007806000003C043C04003E02008084021 diff --git a/tools/snapshots/default/el2_pdef.vh b/tools/snapshots/default/el2_pdef.vh new file mode 100644 index 0000000..ee6848f --- /dev/null +++ b/tools/snapshots/default/el2_pdef.vh @@ -0,0 +1,175 @@ +typedef struct packed { + bit [7:0] BHT_ADDR_HI; + bit [5:0] BHT_ADDR_LO; + bit [14:0] BHT_ARRAY_DEPTH; + bit [4:0] BHT_GHR_HASH_1; + bit [7:0] BHT_GHR_SIZE; + bit [15:0] BHT_SIZE; + bit [4:0] BITMANIP_ZBA; + bit [4:0] BITMANIP_ZBB; + bit [4:0] BITMANIP_ZBC; + bit [4:0] BITMANIP_ZBE; + bit [4:0] BITMANIP_ZBF; + bit [4:0] BITMANIP_ZBP; + bit [4:0] BITMANIP_ZBR; + bit [4:0] BITMANIP_ZBS; + bit [8:0] BTB_ADDR_HI; + bit [5:0] BTB_ADDR_LO; + bit [12:0] BTB_ARRAY_DEPTH; + bit [4:0] BTB_BTAG_FOLD; + bit [8:0] BTB_BTAG_SIZE; + bit [4:0] BTB_ENABLE; + bit [4:0] BTB_FOLD2_INDEX_HASH; + bit [4:0] BTB_FULLYA; + bit [8:0] BTB_INDEX1_HI; + bit [8:0] BTB_INDEX1_LO; + bit [8:0] BTB_INDEX2_HI; + bit [8:0] BTB_INDEX2_LO; + bit [8:0] BTB_INDEX3_HI; + bit [8:0] BTB_INDEX3_LO; + bit [13:0] BTB_SIZE; + bit [8:0] BTB_TOFFSET_SIZE; + bit BUILD_AHB_LITE; + bit [4:0] BUILD_AXI4; + bit [4:0] BUILD_AXI_NATIVE; + bit [5:0] BUS_PRTY_DEFAULT; + bit [35:0] DATA_ACCESS_ADDR0; + bit [35:0] DATA_ACCESS_ADDR1; + bit [35:0] DATA_ACCESS_ADDR2; + bit [35:0] DATA_ACCESS_ADDR3; + bit [35:0] DATA_ACCESS_ADDR4; + bit [35:0] DATA_ACCESS_ADDR5; + bit [35:0] DATA_ACCESS_ADDR6; + bit [35:0] DATA_ACCESS_ADDR7; + bit [4:0] DATA_ACCESS_ENABLE0; + bit [4:0] DATA_ACCESS_ENABLE1; + bit [4:0] DATA_ACCESS_ENABLE2; + bit [4:0] DATA_ACCESS_ENABLE3; + bit [4:0] DATA_ACCESS_ENABLE4; + bit [4:0] DATA_ACCESS_ENABLE5; + bit [4:0] DATA_ACCESS_ENABLE6; + bit [4:0] DATA_ACCESS_ENABLE7; + bit [35:0] DATA_ACCESS_MASK0; + bit [35:0] DATA_ACCESS_MASK1; + bit [35:0] DATA_ACCESS_MASK2; + bit [35:0] DATA_ACCESS_MASK3; + bit [35:0] DATA_ACCESS_MASK4; + bit [35:0] DATA_ACCESS_MASK5; + bit [35:0] DATA_ACCESS_MASK6; + bit [35:0] DATA_ACCESS_MASK7; + bit [6:0] DCCM_BANK_BITS; + bit [8:0] DCCM_BITS; + bit [6:0] DCCM_BYTE_WIDTH; + bit [9:0] DCCM_DATA_WIDTH; + bit [6:0] DCCM_ECC_WIDTH; + bit [4:0] DCCM_ENABLE; + bit [9:0] DCCM_FDATA_WIDTH; + bit [7:0] DCCM_INDEX_BITS; + bit [8:0] DCCM_NUM_BANKS; + bit [7:0] DCCM_REGION; + bit [35:0] DCCM_SADR; + bit [13:0] DCCM_SIZE; + bit [5:0] DCCM_WIDTH_BITS; + bit [6:0] DIV_BIT; + bit [4:0] DIV_NEW; + bit [6:0] DMA_BUF_DEPTH; + bit [8:0] DMA_BUS_ID; + bit [5:0] DMA_BUS_PRTY; + bit [7:0] DMA_BUS_TAG; + bit [4:0] FAST_INTERRUPT_REDIRECT; + bit [4:0] ICACHE_2BANKS; + bit [6:0] ICACHE_BANK_BITS; + bit [6:0] ICACHE_BANK_HI; + bit [5:0] ICACHE_BANK_LO; + bit [7:0] ICACHE_BANK_WIDTH; + bit [6:0] ICACHE_BANKS_WAY; + bit [7:0] ICACHE_BEAT_ADDR_HI; + bit [7:0] ICACHE_BEAT_BITS; + bit [4:0] ICACHE_BYPASS_ENABLE; + bit [17:0] ICACHE_DATA_DEPTH; + bit [6:0] ICACHE_DATA_INDEX_LO; + bit [10:0] ICACHE_DATA_WIDTH; + bit [4:0] ICACHE_ECC; + bit [4:0] ICACHE_ENABLE; + bit [10:0] ICACHE_FDATA_WIDTH; + bit [8:0] ICACHE_INDEX_HI; + bit [10:0] ICACHE_LN_SZ; + bit [7:0] ICACHE_NUM_BEATS; + bit [7:0] ICACHE_NUM_BYPASS; + bit [7:0] ICACHE_NUM_BYPASS_WIDTH; + bit [6:0] ICACHE_NUM_WAYS; + bit [4:0] ICACHE_ONLY; + bit [7:0] ICACHE_SCND_LAST; + bit [12:0] ICACHE_SIZE; + bit [6:0] ICACHE_STATUS_BITS; + bit [4:0] ICACHE_TAG_BYPASS_ENABLE; + bit [16:0] ICACHE_TAG_DEPTH; + bit [6:0] ICACHE_TAG_INDEX_LO; + bit [8:0] ICACHE_TAG_LO; + bit [7:0] ICACHE_TAG_NUM_BYPASS; + bit [7:0] ICACHE_TAG_NUM_BYPASS_WIDTH; + bit [4:0] ICACHE_WAYPACK; + bit [6:0] ICCM_BANK_BITS; + bit [8:0] ICCM_BANK_HI; + bit [8:0] ICCM_BANK_INDEX_LO; + bit [8:0] ICCM_BITS; + bit [4:0] ICCM_ENABLE; + bit [4:0] ICCM_ICACHE; + bit [7:0] ICCM_INDEX_BITS; + bit [8:0] ICCM_NUM_BANKS; + bit [4:0] ICCM_ONLY; + bit [7:0] ICCM_REGION; + bit [35:0] ICCM_SADR; + bit [13:0] ICCM_SIZE; + bit [4:0] IFU_BUS_ID; + bit [5:0] IFU_BUS_PRTY; + bit [7:0] IFU_BUS_TAG; + bit [35:0] INST_ACCESS_ADDR0; + bit [35:0] INST_ACCESS_ADDR1; + bit [35:0] INST_ACCESS_ADDR2; + bit [35:0] INST_ACCESS_ADDR3; + bit [35:0] INST_ACCESS_ADDR4; + bit [35:0] INST_ACCESS_ADDR5; + bit [35:0] INST_ACCESS_ADDR6; + bit [35:0] INST_ACCESS_ADDR7; + bit [4:0] INST_ACCESS_ENABLE0; + bit [4:0] INST_ACCESS_ENABLE1; + bit [4:0] INST_ACCESS_ENABLE2; + bit [4:0] INST_ACCESS_ENABLE3; + bit [4:0] INST_ACCESS_ENABLE4; + bit [4:0] INST_ACCESS_ENABLE5; + bit [4:0] INST_ACCESS_ENABLE6; + bit [4:0] INST_ACCESS_ENABLE7; + bit [35:0] INST_ACCESS_MASK0; + bit [35:0] INST_ACCESS_MASK1; + bit [35:0] INST_ACCESS_MASK2; + bit [35:0] INST_ACCESS_MASK3; + bit [35:0] INST_ACCESS_MASK4; + bit [35:0] INST_ACCESS_MASK5; + bit [35:0] INST_ACCESS_MASK6; + bit [35:0] INST_ACCESS_MASK7; + bit [4:0] LOAD_TO_USE_PLUS1; + bit [4:0] LSU2DMA; + bit [4:0] LSU_BUS_ID; + bit [5:0] LSU_BUS_PRTY; + bit [7:0] LSU_BUS_TAG; + bit [8:0] LSU_NUM_NBLOAD; + bit [6:0] LSU_NUM_NBLOAD_WIDTH; + bit [8:0] LSU_SB_BITS; + bit [7:0] LSU_STBUF_DEPTH; + bit [4:0] NO_ICCM_NO_ICACHE; + bit [4:0] PIC_2CYCLE; + bit [35:0] PIC_BASE_ADDR; + bit [8:0] PIC_BITS; + bit [7:0] PIC_INT_WORDS; + bit [7:0] PIC_REGION; + bit [12:0] PIC_SIZE; + bit [11:0] PIC_TOTAL_INT; + bit [12:0] PIC_TOTAL_INT_PLUS1; + bit [7:0] RET_STACK_SIZE; + bit [4:0] SB_BUS_ID; + bit [5:0] SB_BUS_PRTY; + bit [7:0] SB_BUS_TAG; + bit [4:0] TIMER_LEGAL_EN; +} el2_param_t; + diff --git a/tools/snapshots/default/link.ld b/tools/snapshots/default/link.ld new file mode 100644 index 0000000..ccf3fc0 --- /dev/null +++ b/tools/snapshots/default/link.ld @@ -0,0 +1,28 @@ +/* + NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE + This is an automatically generated file by colin on Mon Mar 7 04:09:03 AM UTC 2022 + + cmd: swerv -target=default -set build_axi4 + +*/ +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + +SECTIONS +{ + . = 0x80000000; + .text.init . : { *(.text.init) } + + .text . : { *(.text) } + _end = .; + . = 0xd0580000; + .data.io . : { *(.data.io) } + . = 0xf0040000 ; + .data : ALIGN(0x800) { *(.*data) *(.rodata*)} + .bss : {BSS_START = .; *(.*bss)} + BSS_END = .; + STACK = ALIGN(16) + 0x1000; + + . = 0xfffffff8; .data.ctl : { LONG(0xf0040000); LONG(STACK) } +} + diff --git a/tools/snapshots/default/pd_defines.vh b/tools/snapshots/default/pd_defines.vh new file mode 100644 index 0000000..b1fcfad --- /dev/null +++ b/tools/snapshots/default/pd_defines.vh @@ -0,0 +1,10 @@ +// NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE +// This is an automatically generated file by colin on Mon Mar 7 04:09:03 AM UTC 2022 +// +// cmd: swerv -target=default -set build_axi4 +// + +`include "common_defines.vh" +`undef RV_ASSERT_ON +`undef TEC_RV_ICG +`define RV_PHYSICAL 1 diff --git a/tools/snapshots/default/perl_configs.pl b/tools/snapshots/default/perl_configs.pl new file mode 100644 index 0000000..29c1cc3 --- /dev/null +++ b/tools/snapshots/default/perl_configs.pl @@ -0,0 +1,778 @@ +# NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE +# This is an automatically generated file by colin on Mon Mar 7 04:09:03 AM UTC 2022 +# +# cmd: swerv -target=default -set build_axi4 +# +# To use this in a perf script, use 'require $RV_ROOT/configs/config.pl' +# Reference the hash via $config{name}.. + + +%config = ( + 'nmi_vec' => '0x11110000', + 'numiregs' => '32', + '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 + ], + 'bht' => { + 'bht_ghr_range' => '7:0', + 'bht_hash_string' => '{hashin[8+1:2]^ghr[8-1:0]}// cf2', + 'bht_addr_hi' => 9, + 'bht_ghr_size' => 8, + 'bht_array_depth' => 256, + 'bht_ghr_hash_1' => '', + 'bht_size' => 512, + 'bht_addr_lo' => '2' + }, + 'retstack' => { + 'ret_stack_size' => '8' + }, + 'config_key' => '32\'hdeadbeef', + 'even_odd_trigger_chains' => 'true', + 'target' => 'default', + 'dccm' => { + 'dccm_offset' => '0x40000', + 'dccm_region' => '0xf', + 'dccm_eadr' => '0xf004ffff', + 'dccm_size' => 64, + 'dccm_sadr' => '0xf0040000', + 'dccm_fdata_width' => 39, + 'dccm_bank_bits' => 2, + 'dccm_num_banks_4' => '', + 'dccm_rows' => '4096', + 'dccm_enable' => '1', + 'dccm_index_bits' => 12, + 'dccm_bits' => 16, + 'dccm_num_banks' => '4', + 'lsu_sb_bits' => 16, + 'dccm_data_width' => 32, + 'dccm_data_cell' => 'ram_4096x39', + 'dccm_reserved' => '0x1400', + 'dccm_size_64' => '', + 'dccm_ecc_width' => 7, + 'dccm_width_bits' => 2, + 'dccm_byte_width' => '4' + }, + 'max_mmode_perf_event' => '516', + 'regwidth' => '32', + 'reset_vec' => '0x80000000', + 'core' => { + 'lsu_stbuf_depth' => '4', + 'bitmanip_zbr' => 0, + 'bitmanip_zbs' => 1, + 'bitmanip_zbf' => 0, + 'fpga_optimize' => 1, + 'icache_only' => 'derived', + 'dma_buf_depth' => '5', + 'bitmanip_zbc' => 1, + 'bitmanip_zbe' => 0, + 'iccm_icache' => 1, + 'fast_interrupt_redirect' => '1', + 'lsu_num_nbload' => '4', + 'iccm_only' => 'derived', + 'bitmanip_zba' => 1, + 'bitmanip_zbp' => 0, + 'lsu2dma' => 0, + 'lsu_num_nbload_width' => '2', + 'div_bit' => '4', + 'bitmanip_zbb' => 1, + 'no_iccm_no_icache' => 'derived', + 'timer_legal_en' => '1', + 'div_new' => 1 + }, + 'memmap' => { + 'unused_region8' => '0x00000000', + 'unused_region2' => '0x60000000', + 'unused_region1' => '0x70000000', + 'unused_region5' => '0x30000000', + 'unused_region4' => '0x40000000', + 'serialio' => '0xd0580000', + 'external_data' => '0xc0580000', + 'external_data_1' => '0xb0000000', + 'unused_region0' => '0x90000000', + 'unused_region3' => '0x50000000', + 'consoleio' => '0xd0580000', + 'unused_region7' => '0x10000000', + 'debug_sb_mem' => '0xa0580000', + 'unused_region6' => '0x20000000' + }, + 'iccm' => { + 'iccm_num_banks' => '4', + 'iccm_bits' => 16, + 'iccm_index_bits' => 12, + 'iccm_enable' => 1, + 'iccm_size_64' => '', + 'iccm_data_cell' => 'ram_4096x39', + 'iccm_reserved' => '0x1000', + 'iccm_bank_index_lo' => 4, + 'iccm_sadr' => '0xee000000', + 'iccm_eadr' => '0xee00ffff', + 'iccm_offset' => '0xe000000', + 'iccm_region' => '0xe', + 'iccm_size' => 64, + 'iccm_num_banks_4' => '', + 'iccm_rows' => '4096', + 'iccm_bank_hi' => 3, + 'iccm_bank_bits' => 2 + }, + 'pic' => { + 'pic_meipl_mask' => '0xf', + 'pic_meipl_count' => 31, + 'pic_meie_count' => 31, + 'pic_meip_mask' => '0x0', + 'pic_meipt_offset' => '0x3004', + 'pic_region' => '0xf', + 'pic_total_int' => 31, + 'pic_meigwctrl_offset' => '0x4000', + 'pic_meip_count' => 1, + 'pic_meie_mask' => '0x1', + 'pic_mpiccfg_offset' => '0x3000', + 'pic_meigwclr_mask' => '0x0', + 'pic_meigwclr_count' => 31, + 'pic_int_words' => 1, + 'pic_offset' => '0xc0000', + 'pic_meip_offset' => '0x1000', + 'pic_bits' => 15, + 'pic_mpiccfg_count' => 1, + 'pic_meigwclr_offset' => '0x5000', + 'pic_size' => 32, + 'pic_mpiccfg_mask' => '0x1', + 'pic_total_int_plus1' => 32, + 'pic_meipl_offset' => '0x0000', + 'pic_meigwctrl_count' => 31, + 'pic_base_addr' => '0xf00c0000', + 'pic_meipt_mask' => '0x0', + 'pic_meie_offset' => '0x2000', + 'pic_meigwctrl_mask' => '0x3', + 'pic_meipt_count' => 31 + }, + 'protection' => { + 'inst_access_addr2' => '0x00000000', + 'data_access_mask6' => '0xffffffff', + 'data_access_enable0' => '0x0', + 'inst_access_enable4' => '0x0', + 'inst_access_mask1' => '0xffffffff', + 'inst_access_addr5' => '0x00000000', + 'inst_access_enable1' => '0x0', + 'inst_access_mask4' => '0xffffffff', + 'data_access_addr2' => '0x00000000', + 'inst_access_mask6' => '0xffffffff', + 'inst_access_enable0' => '0x0', + 'data_access_addr5' => '0x00000000', + 'data_access_mask1' => '0xffffffff', + 'data_access_enable4' => '0x0', + 'data_access_enable1' => '0x0', + 'data_access_mask4' => '0xffffffff', + 'data_access_enable6' => '0x0', + 'inst_access_mask7' => '0xffffffff', + 'inst_access_enable5' => '0x0', + 'data_access_mask0' => '0xffffffff', + 'inst_access_addr3' => '0x00000000', + 'inst_access_enable6' => '0x0', + 'data_access_mask7' => '0xffffffff', + 'data_access_enable5' => '0x0', + 'inst_access_mask0' => '0xffffffff', + 'data_access_addr3' => '0x00000000', + 'data_access_enable3' => '0x0', + 'data_access_addr0' => '0x00000000', + 'inst_access_mask3' => '0xffffffff', + 'data_access_enable2' => '0x0', + 'inst_access_addr7' => '0x00000000', + 'inst_access_enable3' => '0x0', + 'inst_access_addr0' => '0x00000000', + 'data_access_mask3' => '0xffffffff', + 'data_access_addr7' => '0x00000000', + 'inst_access_enable2' => '0x0', + 'inst_access_mask5' => '0xffffffff', + 'inst_access_addr1' => '0x00000000', + 'inst_access_addr4' => '0x00000000', + 'inst_access_mask2' => '0xffffffff', + 'inst_access_enable7' => '0x0', + 'data_access_addr6' => '0x00000000', + 'data_access_addr1' => '0x00000000', + 'data_access_mask5' => '0xffffffff', + 'data_access_addr4' => '0x00000000', + 'data_access_mask2' => '0xffffffff', + 'data_access_enable7' => '0x0', + 'inst_access_addr6' => '0x00000000' + }, + 'physical' => '1', + 'bus' => { + 'ifu_bus_prty' => '2', + 'sb_bus_prty' => '2', + 'lsu_bus_id' => '1', + 'lsu_bus_tag' => 3, + 'sb_bus_tag' => '1', + 'dma_bus_id' => '1', + 'dma_bus_tag' => '1', + 'lsu_bus_prty' => '2', + 'bus_prty_default' => '3', + 'sb_bus_id' => '1', + 'dma_bus_prty' => '2', + 'ifu_bus_id' => '1', + 'ifu_bus_tag' => '3' + }, + 'harts' => 1, + 'xlen' => 32, + 'btb' => { + 'btb_index3_lo' => 18, + 'btb_index1_lo' => '2', + 'btb_addr_hi' => 9, + 'btb_index2_lo' => 10, + 'btb_size' => 512, + 'btb_btag_fold' => 0, + 'btb_addr_lo' => '2', + 'btb_index2_hi' => 17, + 'btb_enable' => '1', + 'btb_toffset_size' => '12', + 'btb_index3_hi' => 25, + 'btb_array_depth' => 256, + 'btb_btag_size' => 5, + 'btb_index1_hi' => 9, + 'btb_fold2_index_hash' => 0 + }, + 'tec_rv_icg' => 'clockhdr', + 'triggers' => [ + { + 'poke_mask' => [ + '0x081818c7', + '0xffffffff', + '0x00000000' + ], + 'mask' => [ + '0x081818c7', + '0xffffffff', + '0x00000000' + ], + 'reset' => [ + '0x23e00000', + '0x00000000', + '0x00000000' + ] + }, + { + 'poke_mask' => [ + '0x081810c7', + '0xffffffff', + '0x00000000' + ], + 'mask' => [ + '0x081810c7', + '0xffffffff', + '0x00000000' + ], + 'reset' => [ + '0x23e00000', + '0x00000000', + '0x00000000' + ] + }, + { + 'reset' => [ + '0x23e00000', + '0x00000000', + '0x00000000' + ], + 'poke_mask' => [ + '0x081818c7', + '0xffffffff', + '0x00000000' + ], + 'mask' => [ + '0x081818c7', + '0xffffffff', + '0x00000000' + ] + }, + { + 'poke_mask' => [ + '0x081810c7', + '0xffffffff', + '0x00000000' + ], + 'mask' => [ + '0x081810c7', + '0xffffffff', + '0x00000000' + ], + 'reset' => [ + '0x23e00000', + '0x00000000', + '0x00000000' + ] + } + ], + 'num_mmode_perf_regs' => '4', + 'testbench' => { + 'assert_on' => '', + 'sterr_rollback' => '0', + 'build_axi4' => 1, + 'SDVT_AHB' => '0', + 'ext_datawidth' => '64', + 'ext_addrwidth' => '32', + 'TOP' => 'tb_top', + 'lderr_rollback' => '1', + 'build_axi_native' => 1, + 'RV_TOP' => '`TOP.rvtop', + 'clock_period' => '100', + 'CPU_TOP' => '`RV_TOP.swerv' + }, + 'icache' => { + 'icache_index_hi' => 12, + 'icache_tag_cell' => 'ram_128x25', + 'icache_num_beats' => 8, + 'icache_fdata_width' => 71, + 'icache_num_bypass_width' => 2, + 'icache_tag_depth' => 128, + 'icache_tag_bypass_enable' => '1', + 'icache_size' => 16, + 'icache_tag_num_bypass' => '2', + 'icache_bank_width' => 8, + 'icache_data_index_lo' => 4, + 'icache_2banks' => '1', + 'icache_num_lines_bank' => '64', + 'icache_ecc' => '1', + 'icache_status_bits' => 1, + 'icache_tag_num_bypass_width' => 2, + 'icache_beat_bits' => 3, + 'icache_data_width' => 64, + 'icache_bypass_enable' => '1', + 'icache_waypack' => '1', + 'icache_num_bypass' => '2', + 'icache_data_depth' => '512', + 'icache_beat_addr_hi' => 5, + 'icache_tag_lo' => 13, + 'icache_bank_bits' => 1, + 'icache_enable' => 1, + 'icache_bank_hi' => 3, + 'icache_num_lines' => 256, + 'icache_tag_index_lo' => '6', + 'icache_ln_sz' => 64, + 'icache_num_lines_way' => '128', + 'icache_data_cell' => 'ram_512x71', + 'icache_banks_way' => 2, + 'icache_num_ways' => 2, + 'icache_scnd_last' => 6, + 'icache_bank_lo' => 3 + }, + 'csr' => { + 'mip' => { + 'exists' => 'true', + 'mask' => '0x0', + 'poke_mask' => '0x70000888', + 'reset' => '0x0' + }, + 'mscause' => { + 'mask' => '0x0000000f', + 'reset' => '0x0', + 'exists' => 'true', + 'number' => '0x7ff' + }, + 'micect' => { + 'exists' => 'true', + 'number' => '0x7f0', + 'mask' => '0xffffffff', + 'reset' => '0x0' + }, + 'pmpaddr12' => { + 'exists' => 'false' + }, + 'dicago' => { + 'number' => '0x7cb', + 'exists' => 'true', + 'debug' => 'true', + 'comment' => 'Cache diagnostics.', + 'reset' => '0x0', + 'mask' => '0x0' + }, + 'mrac' => { + 'exists' => 'true', + 'reset' => '0x0', + 'comment' => 'Memory region io and cache control.', + 'mask' => '0xffffffff', + 'number' => '0x7c0', + 'shared' => 'true' + }, + 'tselect' => { + 'mask' => '0x3', + 'reset' => '0x0', + 'exists' => 'true' + }, + 'mhpmcounter4' => { + 'reset' => '0x0', + 'mask' => '0xffffffff', + 'exists' => 'true' + }, + 'pmpcfg1' => { + 'exists' => 'false' + }, + 'pmpaddr11' => { + 'exists' => 'false' + }, + 'mimpid' => { + 'mask' => '0x0', + 'reset' => '0x4', + 'exists' => 'true' + }, + 'pmpaddr2' => { + 'exists' => 'false' + }, + 'mhpmevent6' => { + 'exists' => 'true', + 'reset' => '0x0', + 'mask' => '0xffffffff' + }, + 'cycle' => { + 'exists' => 'false' + }, + 'mitcnt1' => { + 'number' => '0x7d5', + 'exists' => 'true', + 'reset' => '0x0', + 'mask' => '0xffffffff' + }, + 'mcpc' => { + 'number' => '0x7c2', + 'exists' => 'true', + 'mask' => '0x0', + 'comment' => 'Core pause', + 'reset' => '0x0' + }, + 'pmpaddr6' => { + 'exists' => 'false' + }, + 'pmpaddr1' => { + 'exists' => 'false' + }, + 'mhpmevent3' => { + 'mask' => '0xffffffff', + 'reset' => '0x0', + 'exists' => 'true' + }, + 'mdccmect' => { + 'mask' => '0xffffffff', + 'reset' => '0x0', + 'number' => '0x7f2', + 'exists' => 'true' + }, + 'mitbnd0' => { + 'number' => '0x7d3', + 'exists' => 'true', + 'mask' => '0xffffffff', + 'reset' => '0xffffffff' + }, + 'instret' => { + 'exists' => 'false' + }, + 'pmpaddr14' => { + 'exists' => 'false' + }, + 'mvendorid' => { + 'exists' => 'true', + 'mask' => '0x0', + 'reset' => '0x45' + }, + 'mhpmcounter3' => { + 'reset' => '0x0', + 'mask' => '0xffffffff', + 'exists' => 'true' + }, + 'mfdhs' => { + 'mask' => '0x00000003', + 'comment' => 'Force Debug Halt Status', + 'reset' => '0x0', + 'number' => '0x7cf', + 'exists' => 'true' + }, + 'dicad1' => { + 'number' => '0x7ca', + 'exists' => 'true', + 'debug' => 'true', + 'comment' => 'Cache diagnostics.', + 'reset' => '0x0', + 'mask' => '0x3' + }, + 'pmpcfg2' => { + 'exists' => 'false' + }, + 'mhpmcounter4h' => { + 'exists' => 'true', + 'mask' => '0xffffffff', + 'reset' => '0x0' + }, + 'mfdht' => { + 'number' => '0x7ce', + 'shared' => 'true', + 'exists' => 'true', + 'reset' => '0x0', + 'comment' => 'Force Debug Halt Threshold', + 'mask' => '0x0000003f' + }, + 'pmpaddr13' => { + 'exists' => 'false' + }, + 'mhpmevent4' => { + 'reset' => '0x0', + 'mask' => '0xffffffff', + 'exists' => 'true' + }, + 'mitctl1' => { + 'mask' => '0x0000000f', + 'reset' => '0x1', + 'exists' => 'true', + 'number' => '0x7d7' + }, + 'pmpaddr4' => { + 'exists' => 'false' + }, + 'mie' => { + 'exists' => 'true', + 'reset' => '0x0', + 'mask' => '0x70000888' + }, + 'mfdc' => { + 'number' => '0x7f9', + 'exists' => 'true', + 'mask' => '0x00071fff', + 'reset' => '0x00070040' + }, + 'pmpaddr9' => { + 'exists' => 'false' + }, + 'pmpaddr0' => { + 'exists' => 'false' + }, + 'mpmc' => { + 'exists' => 'true', + 'number' => '0x7c6', + 'reset' => '0x2', + 'mask' => '0x2' + }, + 'pmpaddr3' => { + 'exists' => 'false' + }, + 'marchid' => { + 'exists' => 'true', + 'reset' => '0x00000010', + 'mask' => '0x0' + }, + 'meicidpl' => { + 'comment' => 'External interrupt claim id priority level.', + 'reset' => '0x0', + 'mask' => '0xf', + 'number' => '0xbcb', + 'exists' => 'true' + }, + 'mhpmcounter3h' => { + 'exists' => 'true', + 'reset' => '0x0', + 'mask' => '0xffffffff' + }, + 'dmst' => { + 'exists' => 'true', + 'number' => '0x7c4', + 'debug' => 'true', + 'reset' => '0x0', + 'comment' => 'Memory synch trigger: Flush caches in debug mode.', + 'mask' => '0x0' + }, + 'mstatus' => { + 'exists' => 'true', + 'mask' => '0x88', + 'reset' => '0x1800' + }, + 'dicad0' => { + 'debug' => 'true', + 'exists' => 'true', + 'number' => '0x7c9', + 'mask' => '0xffffffff', + 'reset' => '0x0', + 'comment' => 'Cache diagnostics.' + }, + 'mcgc' => { + 'reset' => '0x200', + 'poke_mask' => '0x000003ff', + 'mask' => '0x000003ff', + 'number' => '0x7f8', + 'exists' => 'true' + }, + 'mhpmcounter5' => { + 'reset' => '0x0', + 'mask' => '0xffffffff', + 'exists' => 'true' + }, + 'mhpmcounter6h' => { + 'exists' => 'true', + 'reset' => '0x0', + 'mask' => '0xffffffff' + }, + 'mcounteren' => { + 'exists' => 'false' + }, + 'misa' => { + 'exists' => 'true', + 'reset' => '0x40001104', + 'mask' => '0x0' + }, + 'pmpcfg0' => { + 'exists' => 'false' + }, + 'mcountinhibit' => { + 'commnet' => 'Performance counter inhibit. One bit per counter.', + 'exists' => 'true', + 'poke_mask' => '0x7d', + 'mask' => '0x7d', + 'reset' => '0x0' + }, + 'dcsr' => { + 'debug' => 'true', + 'exists' => 'true', + 'mask' => '0x00008c04', + 'poke_mask' => '0x00008dcc', + 'reset' => '0x40000003' + }, + 'time' => { + 'exists' => 'false' + }, + 'mhpmevent5' => { + 'exists' => 'true', + 'mask' => '0xffffffff', + 'reset' => '0x0' + }, + 'pmpaddr8' => { + 'exists' => 'false' + }, + 'pmpcfg3' => { + 'exists' => 'false' + }, + 'mitbnd1' => { + 'mask' => '0xffffffff', + 'reset' => '0xffffffff', + 'exists' => 'true', + 'number' => '0x7d6' + }, + 'mitcnt0' => { + 'reset' => '0x0', + 'mask' => '0xffffffff', + 'number' => '0x7d2', + 'exists' => 'true' + }, + 'miccmect' => { + 'exists' => 'true', + 'number' => '0x7f1', + 'mask' => '0xffffffff', + 'reset' => '0x0' + }, + 'mhpmcounter6' => { + 'exists' => 'true', + 'reset' => '0x0', + 'mask' => '0xffffffff' + }, + 'mhpmcounter5h' => { + 'exists' => 'true', + 'reset' => '0x0', + 'mask' => '0xffffffff' + }, + 'pmpaddr7' => { + 'exists' => 'false' + }, + 'pmpaddr5' => { + 'exists' => 'false' + }, + 'mitctl0' => { + 'number' => '0x7d4', + 'exists' => 'true', + 'mask' => '0x00000007', + 'reset' => '0x1' + }, + 'meicurpl' => { + 'exists' => 'true', + 'number' => '0xbcc', + 'reset' => '0x0', + 'comment' => 'External interrupt current priority level.', + 'mask' => '0xf' + }, + 'pmpaddr10' => { + 'exists' => 'false' + }, + 'meipt' => { + 'exists' => 'true', + 'number' => '0xbc9', + 'reset' => '0x0', + 'comment' => 'External interrupt priority threshold.', + 'mask' => '0xf' + }, + 'pmpaddr15' => { + 'exists' => 'false' + }, + 'dicawics' => { + 'mask' => '0x0130fffc', + 'reset' => '0x0', + 'comment' => 'Cache diagnostics.', + 'debug' => 'true', + 'exists' => 'true', + 'number' => '0x7c8' + }, + 'mhartid' => { + 'exists' => 'true', + 'mask' => '0x0', + 'poke_mask' => '0xfffffff0', + 'reset' => '0x0' + } + } + ); +1; diff --git a/tools/snapshots/default/pic_map_auto.h b/tools/snapshots/default/pic_map_auto.h new file mode 100644 index 0000000..8bf4710 --- /dev/null +++ b/tools/snapshots/default/pic_map_auto.h @@ -0,0 +1,100 @@ +// mask[3:0] = { 4'b1000 - 30b mask,4'b0100 - 31b mask, 4'b0010 - 28b mask, 4'b0001 - 32b mask } +always_comb begin + case (address[14:0]) + 15'b011000000000000 : mask[3:0] = 4'b0100; + 15'b100000000000100 : mask[3:0] = 4'b1000; + 15'b100000000001000 : mask[3:0] = 4'b1000; + 15'b100000000001100 : mask[3:0] = 4'b1000; + 15'b100000000010000 : mask[3:0] = 4'b1000; + 15'b100000000010100 : mask[3:0] = 4'b1000; + 15'b100000000011000 : mask[3:0] = 4'b1000; + 15'b100000000011100 : mask[3:0] = 4'b1000; + 15'b100000000100000 : mask[3:0] = 4'b1000; + 15'b100000000100100 : mask[3:0] = 4'b1000; + 15'b100000000101000 : mask[3:0] = 4'b1000; + 15'b100000000101100 : mask[3:0] = 4'b1000; + 15'b100000000110000 : mask[3:0] = 4'b1000; + 15'b100000000110100 : mask[3:0] = 4'b1000; + 15'b100000000111000 : mask[3:0] = 4'b1000; + 15'b100000000111100 : mask[3:0] = 4'b1000; + 15'b100000001000000 : mask[3:0] = 4'b1000; + 15'b100000001000100 : mask[3:0] = 4'b1000; + 15'b100000001001000 : mask[3:0] = 4'b1000; + 15'b100000001001100 : mask[3:0] = 4'b1000; + 15'b100000001010000 : mask[3:0] = 4'b1000; + 15'b100000001010100 : mask[3:0] = 4'b1000; + 15'b100000001011000 : mask[3:0] = 4'b1000; + 15'b100000001011100 : mask[3:0] = 4'b1000; + 15'b100000001100000 : mask[3:0] = 4'b1000; + 15'b100000001100100 : mask[3:0] = 4'b1000; + 15'b100000001101000 : mask[3:0] = 4'b1000; + 15'b100000001101100 : mask[3:0] = 4'b1000; + 15'b100000001110000 : mask[3:0] = 4'b1000; + 15'b100000001110100 : mask[3:0] = 4'b1000; + 15'b100000001111000 : mask[3:0] = 4'b1000; + 15'b100000001111100 : mask[3:0] = 4'b1000; + 15'b010000000000100 : mask[3:0] = 4'b0100; + 15'b010000000001000 : mask[3:0] = 4'b0100; + 15'b010000000001100 : mask[3:0] = 4'b0100; + 15'b010000000010000 : mask[3:0] = 4'b0100; + 15'b010000000010100 : mask[3:0] = 4'b0100; + 15'b010000000011000 : mask[3:0] = 4'b0100; + 15'b010000000011100 : mask[3:0] = 4'b0100; + 15'b010000000100000 : mask[3:0] = 4'b0100; + 15'b010000000100100 : mask[3:0] = 4'b0100; + 15'b010000000101000 : mask[3:0] = 4'b0100; + 15'b010000000101100 : mask[3:0] = 4'b0100; + 15'b010000000110000 : mask[3:0] = 4'b0100; + 15'b010000000110100 : mask[3:0] = 4'b0100; + 15'b010000000111000 : mask[3:0] = 4'b0100; + 15'b010000000111100 : mask[3:0] = 4'b0100; + 15'b010000001000000 : mask[3:0] = 4'b0100; + 15'b010000001000100 : mask[3:0] = 4'b0100; + 15'b010000001001000 : mask[3:0] = 4'b0100; + 15'b010000001001100 : mask[3:0] = 4'b0100; + 15'b010000001010000 : mask[3:0] = 4'b0100; + 15'b010000001010100 : mask[3:0] = 4'b0100; + 15'b010000001011000 : mask[3:0] = 4'b0100; + 15'b010000001011100 : mask[3:0] = 4'b0100; + 15'b010000001100000 : mask[3:0] = 4'b0100; + 15'b010000001100100 : mask[3:0] = 4'b0100; + 15'b010000001101000 : mask[3:0] = 4'b0100; + 15'b010000001101100 : mask[3:0] = 4'b0100; + 15'b010000001110000 : mask[3:0] = 4'b0100; + 15'b010000001110100 : mask[3:0] = 4'b0100; + 15'b010000001111000 : mask[3:0] = 4'b0100; + 15'b010000001111100 : mask[3:0] = 4'b0100; + 15'b000000000000100 : mask[3:0] = 4'b0010; + 15'b000000000001000 : mask[3:0] = 4'b0010; + 15'b000000000001100 : mask[3:0] = 4'b0010; + 15'b000000000010000 : mask[3:0] = 4'b0010; + 15'b000000000010100 : mask[3:0] = 4'b0010; + 15'b000000000011000 : mask[3:0] = 4'b0010; + 15'b000000000011100 : mask[3:0] = 4'b0010; + 15'b000000000100000 : mask[3:0] = 4'b0010; + 15'b000000000100100 : mask[3:0] = 4'b0010; + 15'b000000000101000 : mask[3:0] = 4'b0010; + 15'b000000000101100 : mask[3:0] = 4'b0010; + 15'b000000000110000 : mask[3:0] = 4'b0010; + 15'b000000000110100 : mask[3:0] = 4'b0010; + 15'b000000000111000 : mask[3:0] = 4'b0010; + 15'b000000000111100 : mask[3:0] = 4'b0010; + 15'b000000001000000 : mask[3:0] = 4'b0010; + 15'b000000001000100 : mask[3:0] = 4'b0010; + 15'b000000001001000 : mask[3:0] = 4'b0010; + 15'b000000001001100 : mask[3:0] = 4'b0010; + 15'b000000001010000 : mask[3:0] = 4'b0010; + 15'b000000001010100 : mask[3:0] = 4'b0010; + 15'b000000001011000 : mask[3:0] = 4'b0010; + 15'b000000001011100 : mask[3:0] = 4'b0010; + 15'b000000001100000 : mask[3:0] = 4'b0010; + 15'b000000001100100 : mask[3:0] = 4'b0010; + 15'b000000001101000 : mask[3:0] = 4'b0010; + 15'b000000001101100 : mask[3:0] = 4'b0010; + 15'b000000001110000 : mask[3:0] = 4'b0010; + 15'b000000001110100 : mask[3:0] = 4'b0010; + 15'b000000001111000 : mask[3:0] = 4'b0010; + 15'b000000001111100 : mask[3:0] = 4'b0010; + default : mask[3:0] = 4'b0001; + endcase +end diff --git a/tools/snapshots/default/whisper.json b/tools/snapshots/default/whisper.json new file mode 100644 index 0000000..33430e3 --- /dev/null +++ b/tools/snapshots/default/whisper.json @@ -0,0 +1,566 @@ +{ + "enable_zbs" : 1, + "nmi_vec" : "0x11110000", + "enable_zbc" : 1, + "effective_address_compatible_with_base" : "true", + "mmode_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 + ], + "even_odd_trigger_chains" : "true", + "max_mmode_perf_event" : "516", + "dccm" : { + "offset" : "0x40000", + "size" : "0x10000", + "region" : "0xf" + }, + "reset_vec" : "0x80000000", + "enable_zbp" : 0, + "enable_zbb" : 1, + "store_error_rollback" : "0", + "memmap" : { + "serialio" : "0xd0580000", + "consoleio" : "0xd0580000" + }, + "harts" : 1, + "xlen" : 32, + "enable_zbe" : 0, + "enable_zbr" : 0, + "amo_illegal_outside_dccm" : "true", + "iccm" : { + "region" : "0xe", + "size" : "0x10000", + "offset" : "0xe000000" + }, + "enable_zba" : 1, + "num_mmode_perf_regs" : "4", + "enable_zbf" : 0, + "load_error_rollback" : "1", + "triggers" : [ + { + "poke_mask" : [ + "0x081818c7", + "0xffffffff", + "0x00000000" + ], + "mask" : [ + "0x081818c7", + "0xffffffff", + "0x00000000" + ], + "reset" : [ + "0x23e00000", + "0x00000000", + "0x00000000" + ] + }, + { + "poke_mask" : [ + "0x081810c7", + "0xffffffff", + "0x00000000" + ], + "mask" : [ + "0x081810c7", + "0xffffffff", + "0x00000000" + ], + "reset" : [ + "0x23e00000", + "0x00000000", + "0x00000000" + ] + }, + { + "reset" : [ + "0x23e00000", + "0x00000000", + "0x00000000" + ], + "poke_mask" : [ + "0x081818c7", + "0xffffffff", + "0x00000000" + ], + "mask" : [ + "0x081818c7", + "0xffffffff", + "0x00000000" + ] + }, + { + "poke_mask" : [ + "0x081810c7", + "0xffffffff", + "0x00000000" + ], + "mask" : [ + "0x081810c7", + "0xffffffff", + "0x00000000" + ], + "reset" : [ + "0x23e00000", + "0x00000000", + "0x00000000" + ] + } + ], + "fast_interrupt_redirect" : "1", + "csr" : { + "mip" : { + "exists" : "true", + "mask" : "0x0", + "poke_mask" : "0x70000888", + "reset" : "0x0" + }, + "mscause" : { + "mask" : "0x0000000f", + "reset" : "0x0", + "exists" : "true", + "number" : "0x7ff" + }, + "micect" : { + "exists" : "true", + "number" : "0x7f0", + "mask" : "0xffffffff", + "reset" : "0x0" + }, + "pmpaddr12" : { + "exists" : "false" + }, + "dicago" : { + "number" : "0x7cb", + "exists" : "true", + "debug" : "true", + "comment" : "Cache diagnostics.", + "reset" : "0x0", + "mask" : "0x0" + }, + "mrac" : { + "exists" : "true", + "reset" : "0x0", + "comment" : "Memory region io and cache control.", + "mask" : "0xffffffff", + "number" : "0x7c0", + "shared" : "true" + }, + "tselect" : { + "mask" : "0x3", + "reset" : "0x0", + "exists" : "true" + }, + "mhpmcounter4" : { + "reset" : "0x0", + "mask" : "0xffffffff", + "exists" : "true" + }, + "pmpcfg1" : { + "exists" : "false" + }, + "pmpaddr11" : { + "exists" : "false" + }, + "mimpid" : { + "mask" : "0x0", + "reset" : "0x4", + "exists" : "true" + }, + "pmpaddr2" : { + "exists" : "false" + }, + "mhpmevent6" : { + "exists" : "true", + "reset" : "0x0", + "mask" : "0xffffffff" + }, + "cycle" : { + "exists" : "false" + }, + "mitcnt1" : { + "number" : "0x7d5", + "exists" : "true", + "reset" : "0x0", + "mask" : "0xffffffff" + }, + "mcpc" : { + "number" : "0x7c2", + "exists" : "true", + "mask" : "0x0", + "comment" : "Core pause", + "reset" : "0x0" + }, + "pmpaddr6" : { + "exists" : "false" + }, + "pmpaddr1" : { + "exists" : "false" + }, + "mhpmevent3" : { + "mask" : "0xffffffff", + "reset" : "0x0", + "exists" : "true" + }, + "mdccmect" : { + "mask" : "0xffffffff", + "reset" : "0x0", + "number" : "0x7f2", + "exists" : "true" + }, + "mitbnd0" : { + "number" : "0x7d3", + "exists" : "true", + "mask" : "0xffffffff", + "reset" : "0xffffffff" + }, + "instret" : { + "exists" : "false" + }, + "pmpaddr14" : { + "exists" : "false" + }, + "mvendorid" : { + "exists" : "true", + "mask" : "0x0", + "reset" : "0x45" + }, + "mhpmcounter3" : { + "reset" : "0x0", + "mask" : "0xffffffff", + "exists" : "true" + }, + "mfdhs" : { + "mask" : "0x00000003", + "comment" : "Force Debug Halt Status", + "reset" : "0x0", + "number" : "0x7cf", + "exists" : "true" + }, + "dicad1" : { + "number" : "0x7ca", + "exists" : "true", + "debug" : "true", + "comment" : "Cache diagnostics.", + "reset" : "0x0", + "mask" : "0x3" + }, + "pmpcfg2" : { + "exists" : "false" + }, + "mhpmcounter4h" : { + "exists" : "true", + "mask" : "0xffffffff", + "reset" : "0x0" + }, + "mfdht" : { + "number" : "0x7ce", + "shared" : "true", + "exists" : "true", + "reset" : "0x0", + "comment" : "Force Debug Halt Threshold", + "mask" : "0x0000003f" + }, + "pmpaddr13" : { + "exists" : "false" + }, + "mhpmevent4" : { + "reset" : "0x0", + "mask" : "0xffffffff", + "exists" : "true" + }, + "mitctl1" : { + "mask" : "0x0000000f", + "reset" : "0x1", + "exists" : "true", + "number" : "0x7d7" + }, + "pmpaddr4" : { + "exists" : "false" + }, + "mie" : { + "exists" : "true", + "reset" : "0x0", + "mask" : "0x70000888" + }, + "mfdc" : { + "number" : "0x7f9", + "exists" : "true", + "mask" : "0x00071fff", + "reset" : "0x00070040" + }, + "pmpaddr9" : { + "exists" : "false" + }, + "pmpaddr0" : { + "exists" : "false" + }, + "mpmc" : { + "exists" : "true", + "number" : "0x7c6", + "reset" : "0x2", + "mask" : "0x2" + }, + "pmpaddr3" : { + "exists" : "false" + }, + "marchid" : { + "exists" : "true", + "reset" : "0x00000010", + "mask" : "0x0" + }, + "meicidpl" : { + "comment" : "External interrupt claim id priority level.", + "reset" : "0x0", + "mask" : "0xf", + "number" : "0xbcb", + "exists" : "true" + }, + "mhpmcounter3h" : { + "exists" : "true", + "reset" : "0x0", + "mask" : "0xffffffff" + }, + "dmst" : { + "exists" : "true", + "number" : "0x7c4", + "debug" : "true", + "reset" : "0x0", + "comment" : "Memory synch trigger: Flush caches in debug mode.", + "mask" : "0x0" + }, + "mstatus" : { + "exists" : "true", + "mask" : "0x88", + "reset" : "0x1800" + }, + "dicad0" : { + "debug" : "true", + "exists" : "true", + "number" : "0x7c9", + "mask" : "0xffffffff", + "reset" : "0x0", + "comment" : "Cache diagnostics." + }, + "mcgc" : { + "reset" : "0x200", + "poke_mask" : "0x000003ff", + "mask" : "0x000003ff", + "number" : "0x7f8", + "exists" : "true" + }, + "mhpmcounter5" : { + "reset" : "0x0", + "mask" : "0xffffffff", + "exists" : "true" + }, + "mhpmcounter6h" : { + "exists" : "true", + "reset" : "0x0", + "mask" : "0xffffffff" + }, + "mcounteren" : { + "exists" : "false" + }, + "misa" : { + "exists" : "true", + "reset" : "0x40001104", + "mask" : "0x0" + }, + "pmpcfg0" : { + "exists" : "false" + }, + "mcountinhibit" : { + "commnet" : "Performance counter inhibit. One bit per counter.", + "exists" : "true", + "poke_mask" : "0x7d", + "mask" : "0x7d", + "reset" : "0x0" + }, + "dcsr" : { + "debug" : "true", + "exists" : "true", + "mask" : "0x00008c04", + "poke_mask" : "0x00008dcc", + "reset" : "0x40000003" + }, + "time" : { + "exists" : "false" + }, + "mhpmevent5" : { + "exists" : "true", + "mask" : "0xffffffff", + "reset" : "0x0" + }, + "pmpaddr8" : { + "exists" : "false" + }, + "pmpcfg3" : { + "exists" : "false" + }, + "mitbnd1" : { + "mask" : "0xffffffff", + "reset" : "0xffffffff", + "exists" : "true", + "number" : "0x7d6" + }, + "mitcnt0" : { + "reset" : "0x0", + "mask" : "0xffffffff", + "number" : "0x7d2", + "exists" : "true" + }, + "miccmect" : { + "exists" : "true", + "number" : "0x7f1", + "mask" : "0xffffffff", + "reset" : "0x0" + }, + "mhpmcounter6" : { + "exists" : "true", + "reset" : "0x0", + "mask" : "0xffffffff" + }, + "mhpmcounter5h" : { + "exists" : "true", + "reset" : "0x0", + "mask" : "0xffffffff" + }, + "pmpaddr7" : { + "exists" : "false" + }, + "pmpaddr5" : { + "exists" : "false" + }, + "mitctl0" : { + "number" : "0x7d4", + "exists" : "true", + "mask" : "0x00000007", + "reset" : "0x1" + }, + "meicurpl" : { + "exists" : "true", + "number" : "0xbcc", + "reset" : "0x0", + "comment" : "External interrupt current priority level.", + "mask" : "0xf" + }, + "pmpaddr10" : { + "exists" : "false" + }, + "meipt" : { + "exists" : "true", + "number" : "0xbc9", + "reset" : "0x0", + "comment" : "External interrupt priority threshold.", + "mask" : "0xf" + }, + "pmpaddr15" : { + "exists" : "false" + }, + "dicawics" : { + "mask" : "0x0130fffc", + "reset" : "0x0", + "comment" : "Cache diagnostics.", + "debug" : "true", + "exists" : "true", + "number" : "0x7c8" + }, + "mhartid" : { + "exists" : "true", + "mask" : "0x0", + "poke_mask" : "0xfffffff0", + "reset" : "0x0" + } + }, + "memory_mapped_registers" : { + "registers" : { + "meigwclr" : { + "mask" : "0x0", + "address" : "0xf00c5004", + "count" : 31 + }, + "meigwctrl" : { + "mask" : "0x3", + "address" : "0xf00c4004", + "count" : 31 + }, + "meip" : { + "mask" : "0x0", + "address" : "0xf00c1000", + "count" : 1 + }, + "meie" : { + "count" : 31, + "address" : "0xf00c2004", + "mask" : "0x1" + }, + "meipl" : { + "mask" : "0xf", + "address" : "0xf00c0004", + "count" : 31 + }, + "mpiccfg" : { + "count" : 1, + "address" : "0xf00c3000", + "mask" : "0x1" + } + }, + "default_mask" : 0, + "address" : "0xf00c0000", + "size" : "0x8000" + } +} diff --git a/tools/verilator-build b/tools/verilator-build new file mode 100644 index 0000000..e69de29