diff --git a/.gitignore b/.gitignore index 89987b1..263eaea 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *.log RCS *~ +.vscode .*.swp .*.swo .DS_Store @@ -46,3 +47,6 @@ unit_level_testbench/pic/workspace/simulation/sim tools/codegenerators/AAPGV2/swerv/asm/out* tools/codegenerators/AAPGV2/swerv/bin/out* tools/codegenerators/AAPGV2/swerv/objdump/out* + +obj_dir +build diff --git a/test/helloworld/JSON.pm b/test/helloworld/JSON.pm new file mode 100644 index 0000000..6fb7a90 --- /dev/null +++ b/test/helloworld/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/test/helloworld/Makefile b/test/helloworld/Makefile new file mode 100644 index 0000000..0570a84 --- /dev/null +++ b/test/helloworld/Makefile @@ -0,0 +1,90 @@ +export RV_ROOT = ${PWD}/../.. +RV_DESIGN = ${RV_ROOT}/design + +TEST_CFLAGS = -g -O3 -funroll-all-loops +ABI = -mabi=ilp32 -march=rv32imc + +# Allow snapshot override +target = default + +# Allow tool override +VERILATOR = verilator +GCC_PREFIX = /opt/riscv/bin/riscv64-unknown-elf +TESTDIR = ${PWD} +BUILD_DIR = ${TESTDIR}/build +SWERV_CONFIG = ${TESTDIR}/swerv.config + +TEST = hello_world + +ifdef debug + DEBUG_PLUS = +dumpon + VERILATOR_DEBUG = --trace +endif + +LINK = $(TESTDIR)/link.ld + +OFILES = $(TEST).o + +VPATH = $(BUILD_DIR) $(TESTDIR) +TESTFILES = $(TESTDIR)/tb_top.sv $(TESTDIR)/ahb_sif.sv + +defines = $(BUILD_DIR)/common_defines.vh ${RV_DESIGN}/include/swerv_types.sv +includes = -I${RV_DESIGN}/include -I${RV_DESIGN}/lib -I${BUILD_DIR} + +# 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 + # *.log *.hex *.dis *.tbl simv* *.map snapshots \ + # verilator* *.exe obj* *.o hello_world.cpp.s ucli.key vc_hdrs.h csrc *.csv \ + # work dataset.asdb library.cfg hello_world.o + +# If define files do not exist, then run swerv.config. +${BUILD_DIR}/defines.h : + BUILD_PATH=${BUILD_DIR} ${SWERV_CONFIG} -target=$(target) -set iccm_enable + +##################### Verilog Builds ##################################### + +verilator-build: ${TESTFILES} ${BUILD_DIR}/defines.h test_tb_top.cpp + echo '`undef ASSERT_ON' >> ${BUILD_DIR}/common_defines.vh + $(VERILATOR) --cc -CFLAGS ${CFLAGS} $(defines) $(includes) \ + -Wno-UNOPTFLAT \ + -I${TESTDIR} \ + -f ${TESTDIR}/flist \ + ${TESTFILES} \ + --top-module tb_top -exe test_tb_top.cpp --autoflush $(VERILATOR_DEBUG) + cp ${TESTDIR}/test_tb_top.cpp obj_dir + $(MAKE) -j -C obj_dir/ -f Vtb_top.mk $(VERILATOR_MAKE_FLAGS) + +##################### Simulation Runs ##################################### + +verilator: program.hex verilator-build + cd build && ../obj_dir/Vtb_top ${DEBUG_PLUS} + +##################### Test Build ##################################### + +program.hex: $(OFILES) $(LINK) + @echo Building $(TEST) + $(GCC_PREFIX)-gcc $(ABI) -Wl,-Map=$(BUILD_DIR)/$(TEST).map -lgcc -T$(LINK) -o $(BUILD_DIR)/$(TEST).exe $(BUILD_DIR)/$(OFILES) -nostartfiles $(TEST_LIBS) + $(GCC_PREFIX)-objcopy -O verilog $(BUILD_DIR)/$(TEST).exe $(BUILD_DIR)/program.hex + $(GCC_PREFIX)-objdump -S $(BUILD_DIR)/$(TEST).exe > $(BUILD_DIR)/$(TEST).dis + @echo Completed building $(TEST) + +%.o : %.s ${BUILD_DIR}/defines.h + $(GCC_PREFIX)-cpp -I${BUILD_DIR} $< > $(BUILD_DIR)/$*.cpp.s + $(GCC_PREFIX)-as $(ABI) $(BUILD_DIR)/$*.cpp.s -o $(BUILD_DIR)/$@ + +%.o : %.c ${BUILD_DIR}/defines.h + $(GCC_PREFIX)-gcc -I${BUILD_DIR} ${TEST_CFLAGS} ${ABI} -nostdlib -c $< -o $(BUILD_DIR)/$@ + +help: + @echo Possible targets: verilator help clean all verilator-build program.hex + +.PHONY: help clean verilator diff --git a/test/helloworld/ahb_sif copy.sv b/test/helloworld/ahb_sif copy.sv new file mode 100644 index 0000000..9143016 --- /dev/null +++ b/test/helloworld/ahb_sif copy.sv @@ -0,0 +1,225 @@ +// 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. +// +`ifdef RV_BUILD_AHB_LITE + +module ahb_sif ( +input logic [63:0] HWDATA, +input logic HCLK, +input logic HSEL, +input logic [3:0] HPROT, +input logic HWRITE, +input logic [1:0] HTRANS, +input logic [2:0] HSIZE, +input logic HREADY, +input logic HRESETn, +input logic [31:0] HADDR, +input logic [2:0] HBURST, + +output logic HREADYOUT, +output logic HRESP, +output logic [63:0] HRDATA +); + +parameter MAILBOX_ADDR = 32'hD0580000; + +logic write; +logic [31:0] laddr, addr; +logic [7:0] strb_lat; +logic [63:0] rdata; + +bit [7:0] mem [bit[31:0]]; +bit [7:0] wscnt; +int dws = 0; +int iws = 0; +bit dws_rand; +bit iws_rand; +bit ok; + +// Wires +wire [63:0] WriteData = HWDATA; +wire [7:0] strb = HSIZE == 3'b000 ? 8'h1 << HADDR[2:0] : + HSIZE == 3'b001 ? 8'h3 << {HADDR[2:1],1'b0} : + HSIZE == 3'b010 ? 8'hf << {HADDR[2],2'b0} : 8'hff; + + +wire mailbox_write = write && laddr==MAILBOX_ADDR; + + +initial begin + if ($value$plusargs("iws=%d", iws)); + if ($value$plusargs("dws=%d", dws)); + dws_rand = dws < 0; + iws_rand = iws < 0; +end + + + +always @ (negedge HCLK ) begin + if(HREADY) + addr = HADDR; + if (write & HREADY) begin + if(strb_lat[7]) mem[{laddr[31:3],3'd7}] = HWDATA[63:56]; + if(strb_lat[6]) mem[{laddr[31:3],3'd6}] = HWDATA[55:48]; + if(strb_lat[5]) mem[{laddr[31:3],3'd5}] = HWDATA[47:40]; + if(strb_lat[4]) mem[{laddr[31:3],3'd4}] = HWDATA[39:32]; + if(strb_lat[3]) mem[{laddr[31:3],3'd3}] = HWDATA[31:24]; + if(strb_lat[2]) mem[{laddr[31:3],3'd2}] = HWDATA[23:16]; + if(strb_lat[1]) mem[{laddr[31:3],3'd1}] = HWDATA[15:08]; + if(strb_lat[0]) mem[{laddr[31:3],3'd0}] = HWDATA[07:00]; + end + if(HREADY & HSEL & |HTRANS) begin +`ifdef VERILATOR + if(iws_rand & ~HPROT[0]) + iws = $random & 15; + if(dws_rand & HPROT[0]) + dws = $random & 15; +`else + if(iws_rand & ~HPROT[0]) + ok = std::randomize(iws) with {iws dist {0:=10, [1:3]:/2, [4:15]:/1};}; + if(dws_rand & HPROT[0]) + ok = std::randomize(dws) with {dws dist {0:=10, [1:3]:/2, [4:15]:/1};}; +`endif + end +end + + +assign HRDATA = HREADY ? rdata : ~rdata; +assign HREADYOUT = wscnt == 0; +assign HRESP = 0; + +always @(posedge HCLK or negedge HRESETn) begin + if(~HRESETn) begin + laddr <= 32'b0; + write <= 1'b0; + rdata <= '0; + wscnt <= 0; + end + else begin + if(HREADY & HSEL) begin + laddr <= HADDR; + write <= HWRITE & |HTRANS; + if(|HTRANS & ~HWRITE) + rdata <= {mem[{addr[31:3],3'd7}], + mem[{addr[31:3],3'd6}], + mem[{addr[31:3],3'd5}], + mem[{addr[31:3],3'd4}], + mem[{addr[31:3],3'd3}], + mem[{addr[31:3],3'd2}], + mem[{addr[31:3],3'd1}], + mem[{addr[31:3],3'd0}]}; + strb_lat <= strb; + end + end + if(HREADY & HSEL & |HTRANS) + wscnt <= HPROT[0] ? dws[7:0] : iws[7:0]; + else if(wscnt != 0) + wscnt <= wscnt-1; +end + + +endmodule +`endif + +`ifdef RV_BUILD_AXI4 +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 MAILBOX_ADDR = 32'hD0580000; +parameter MEM_SIZE_DW = 8192; + +bit [7:0] mem [bit[31:0]]; +bit [63:0] memdata; +wire [63:0] WriteData; +wire mailbox_write; + + +assign mailbox_write = awvalid && awaddr==MAILBOX_ADDR && rst_l; +assign WriteData = wdata; + +always @ ( posedge aclk or negedge rst_l) begin + if(!rst_l) begin + rvalid <= 0; + bvalid <= 0; + end + else begin + bid <= awid; + rid <= arid; + rvalid <= arvalid; + bvalid <= awvalid; + rdata <= memdata; + end +end + +always @ ( negedge aclk) begin + if(arvalid) memdata <= {mem[araddr+7], mem[araddr+6], mem[araddr+5], mem[araddr+4], + mem[araddr+3], mem[araddr+2], mem[araddr+1], mem[araddr]}; + if(awvalid) begin + if(wstrb[7]) mem[awaddr+7] = wdata[63:56]; + if(wstrb[6]) mem[awaddr+6] = wdata[55:48]; + if(wstrb[5]) mem[awaddr+5] = wdata[47:40]; + if(wstrb[4]) mem[awaddr+4] = wdata[39:32]; + if(wstrb[3]) mem[awaddr+3] = wdata[31:24]; + if(wstrb[2]) mem[awaddr+2] = wdata[23:16]; + if(wstrb[1]) mem[awaddr+1] = wdata[15:08]; + if(wstrb[0]) mem[awaddr+0] = wdata[07:00]; + end +end + + +assign arready = 1'b1; +assign awready = 1'b1; +assign wready = 1'b1; +assign rresp = 2'b0; +assign bresp = 2'b0; +assign rlast = 1'b1; + +endmodule +`endif + diff --git a/test/helloworld/ahb_sif.sv b/test/helloworld/ahb_sif.sv new file mode 100644 index 0000000..9143016 --- /dev/null +++ b/test/helloworld/ahb_sif.sv @@ -0,0 +1,225 @@ +// 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. +// +`ifdef RV_BUILD_AHB_LITE + +module ahb_sif ( +input logic [63:0] HWDATA, +input logic HCLK, +input logic HSEL, +input logic [3:0] HPROT, +input logic HWRITE, +input logic [1:0] HTRANS, +input logic [2:0] HSIZE, +input logic HREADY, +input logic HRESETn, +input logic [31:0] HADDR, +input logic [2:0] HBURST, + +output logic HREADYOUT, +output logic HRESP, +output logic [63:0] HRDATA +); + +parameter MAILBOX_ADDR = 32'hD0580000; + +logic write; +logic [31:0] laddr, addr; +logic [7:0] strb_lat; +logic [63:0] rdata; + +bit [7:0] mem [bit[31:0]]; +bit [7:0] wscnt; +int dws = 0; +int iws = 0; +bit dws_rand; +bit iws_rand; +bit ok; + +// Wires +wire [63:0] WriteData = HWDATA; +wire [7:0] strb = HSIZE == 3'b000 ? 8'h1 << HADDR[2:0] : + HSIZE == 3'b001 ? 8'h3 << {HADDR[2:1],1'b0} : + HSIZE == 3'b010 ? 8'hf << {HADDR[2],2'b0} : 8'hff; + + +wire mailbox_write = write && laddr==MAILBOX_ADDR; + + +initial begin + if ($value$plusargs("iws=%d", iws)); + if ($value$plusargs("dws=%d", dws)); + dws_rand = dws < 0; + iws_rand = iws < 0; +end + + + +always @ (negedge HCLK ) begin + if(HREADY) + addr = HADDR; + if (write & HREADY) begin + if(strb_lat[7]) mem[{laddr[31:3],3'd7}] = HWDATA[63:56]; + if(strb_lat[6]) mem[{laddr[31:3],3'd6}] = HWDATA[55:48]; + if(strb_lat[5]) mem[{laddr[31:3],3'd5}] = HWDATA[47:40]; + if(strb_lat[4]) mem[{laddr[31:3],3'd4}] = HWDATA[39:32]; + if(strb_lat[3]) mem[{laddr[31:3],3'd3}] = HWDATA[31:24]; + if(strb_lat[2]) mem[{laddr[31:3],3'd2}] = HWDATA[23:16]; + if(strb_lat[1]) mem[{laddr[31:3],3'd1}] = HWDATA[15:08]; + if(strb_lat[0]) mem[{laddr[31:3],3'd0}] = HWDATA[07:00]; + end + if(HREADY & HSEL & |HTRANS) begin +`ifdef VERILATOR + if(iws_rand & ~HPROT[0]) + iws = $random & 15; + if(dws_rand & HPROT[0]) + dws = $random & 15; +`else + if(iws_rand & ~HPROT[0]) + ok = std::randomize(iws) with {iws dist {0:=10, [1:3]:/2, [4:15]:/1};}; + if(dws_rand & HPROT[0]) + ok = std::randomize(dws) with {dws dist {0:=10, [1:3]:/2, [4:15]:/1};}; +`endif + end +end + + +assign HRDATA = HREADY ? rdata : ~rdata; +assign HREADYOUT = wscnt == 0; +assign HRESP = 0; + +always @(posedge HCLK or negedge HRESETn) begin + if(~HRESETn) begin + laddr <= 32'b0; + write <= 1'b0; + rdata <= '0; + wscnt <= 0; + end + else begin + if(HREADY & HSEL) begin + laddr <= HADDR; + write <= HWRITE & |HTRANS; + if(|HTRANS & ~HWRITE) + rdata <= {mem[{addr[31:3],3'd7}], + mem[{addr[31:3],3'd6}], + mem[{addr[31:3],3'd5}], + mem[{addr[31:3],3'd4}], + mem[{addr[31:3],3'd3}], + mem[{addr[31:3],3'd2}], + mem[{addr[31:3],3'd1}], + mem[{addr[31:3],3'd0}]}; + strb_lat <= strb; + end + end + if(HREADY & HSEL & |HTRANS) + wscnt <= HPROT[0] ? dws[7:0] : iws[7:0]; + else if(wscnt != 0) + wscnt <= wscnt-1; +end + + +endmodule +`endif + +`ifdef RV_BUILD_AXI4 +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 MAILBOX_ADDR = 32'hD0580000; +parameter MEM_SIZE_DW = 8192; + +bit [7:0] mem [bit[31:0]]; +bit [63:0] memdata; +wire [63:0] WriteData; +wire mailbox_write; + + +assign mailbox_write = awvalid && awaddr==MAILBOX_ADDR && rst_l; +assign WriteData = wdata; + +always @ ( posedge aclk or negedge rst_l) begin + if(!rst_l) begin + rvalid <= 0; + bvalid <= 0; + end + else begin + bid <= awid; + rid <= arid; + rvalid <= arvalid; + bvalid <= awvalid; + rdata <= memdata; + end +end + +always @ ( negedge aclk) begin + if(arvalid) memdata <= {mem[araddr+7], mem[araddr+6], mem[araddr+5], mem[araddr+4], + mem[araddr+3], mem[araddr+2], mem[araddr+1], mem[araddr]}; + if(awvalid) begin + if(wstrb[7]) mem[awaddr+7] = wdata[63:56]; + if(wstrb[6]) mem[awaddr+6] = wdata[55:48]; + if(wstrb[5]) mem[awaddr+5] = wdata[47:40]; + if(wstrb[4]) mem[awaddr+4] = wdata[39:32]; + if(wstrb[3]) mem[awaddr+3] = wdata[31:24]; + if(wstrb[2]) mem[awaddr+2] = wdata[23:16]; + if(wstrb[1]) mem[awaddr+1] = wdata[15:08]; + if(wstrb[0]) mem[awaddr+0] = wdata[07:00]; + end +end + + +assign arready = 1'b1; +assign awready = 1'b1; +assign wready = 1'b1; +assign rresp = 2'b0; +assign bresp = 2'b0; +assign rlast = 1'b1; + +endmodule +`endif + diff --git a/test/helloworld/axi_lsu_dma_bridge.sv b/test/helloworld/axi_lsu_dma_bridge.sv new file mode 100644 index 0000000..2c3b844 --- /dev/null +++ b/test/helloworld/axi_lsu_dma_bridge.sv @@ -0,0 +1,201 @@ + +// connects LSI master to external AXI slave and DMA slave +module axi_lsu_dma_bridge +#( +parameter M_ID_WIDTH = 8, +parameter S0_ID_WIDTH = 8 +) +( +input clk, +input reset_l, + +// master read bus +input m_arvalid, +input [M_ID_WIDTH-1:0] m_arid, +input[31:0] m_araddr, +output m_arready, + +output m_rvalid, +input m_rready, +output [63:0] m_rdata, +output [M_ID_WIDTH-1:0] m_rid, +output [1:0] m_rresp, +output m_rlast, + +// master write bus +input m_awvalid, +input [M_ID_WIDTH-1:0] m_awid, +input[31:0] m_awaddr, +output m_awready, + +input m_wvalid, +output m_wready, + +output[1:0] m_bresp, +output m_bvalid, +output[M_ID_WIDTH-1:0] m_bid, +input m_bready, + +// slave 0 if general ext memory +output s0_arvalid, +input s0_arready, + +input s0_rvalid, +input[S0_ID_WIDTH-1:0] s0_rid, +input[1:0] s0_rresp, +input[63:0] s0_rdata, +input s0_rlast, +output s0_rready, + +output s0_awvalid, +input s0_awready, + +output s0_wvalid, +input s0_wready, + +input[1:0] s0_bresp, +input s0_bvalid, +input[S0_ID_WIDTH-1:0] s0_bid, +output s0_bready, + +// slave 1 if DMA port +output s1_arvalid, +input s1_arready, + +input s1_rvalid, +input[1:0] s1_rresp, +input[63:0] s1_rdata, +input s1_rlast, +output s1_rready, + +output s1_awvalid, +input s1_awready, + +output s1_wvalid, +input s1_wready, + +input[1:0] s1_bresp, +input s1_bvalid, +output s1_bready +); + +parameter ICCM_BASE = `RV_ICCM_BITS; // in LSBs +localparam IDFIFOSZ = $clog2(`RV_DMA_BUF_DEPTH); +bit[31:0] iccm_real_base_addr = `RV_ICCM_SADR ; + +wire ar_slave_select; +wire aw_slave_select; +wire w_slave_select; + +wire rresp_select; +wire bresp_select; +wire ar_iccm_select; +wire aw_iccm_select; + +reg [1:0] wsel_iptr, wsel_optr; +reg [2:0] wsel_count; +reg [3:0] wsel; + + +reg [M_ID_WIDTH-1:0] arid [1< VALUE | LIST | HASH +# +# Special name "inside" followed by list .. values must be one of provided list +# Special name "derive" followed by equation to derive +# + +# Dump verilog/assembly macros in upper case +my $defines_case = "U"; + +# Include these macros in verilog (pattern matched) +my @verilog_vars = qw (xlen reset_vec numiregs nmi_vec protection.* icg target testbench.* dccm.* retstack core.* iccm.* btb.* bht.* icache.* pic.* regwidth memmap bus.*); + +# Include these macros in assembly (pattern matched) +my @asm_vars = qw (xlen reset_vec nmi_vec target dccm.* iccm.* pic.* memmap bus.* testbench.* protection.*); +my @asm_overridable = qw (reset_vec nmi_vec) ; + +# Include these macros in PD (pattern matched) +my @pd_vars = qw (physical retstack target btb.* bht.* dccm.* iccm.* icache.* pic.* reset_vec nmi_vec build_ahb_lite datawidth bus.*); + +# Dump non-derived/settable vars/values for these vars in stdout : +my @dvars = qw(retstack btb bht core dccm iccm icache pic bus.* reset_vec nmi_vec memmap bus); + + +# Prefix all macros with +my $prefix = "RV_"; +# No prefix if keyword has +my $no_prefix = 'RV|TOP|^tec|regwidth|clock_period|assert_on|^datawidth|^physical|verilator|SDVT_AHB'; + +my $vlog_use__wh = 1; + +my %regions_used = (); + +# Cmd Line options#{{{ +our %sets; +our %unsets; +my $help; +my @sets = (); +my @unsets = (); + +#Configurations may be changed via the -set option +# +# -set=name=value : Change the default config parameter value (lowercase)\n"; +# -unset=name : Remove the default config parameter (lowercase)\n"; +# : Do not prepend RV_ prefex to -set/-unset variables\n"; +# : multiple -set/-unset options accepted\n\n"; +# + +my $helpusage = " + +Main configuration database for SWERV + +This script documents, and generates the {`#} define/include files for verilog/assembly/backend flows + + +User options: + + -target = { default, default_ahb, default_pd, high_perf} + use default settings for one of the targets + + -set=var=value + set arbitrary variable to a value + -unset=var + unset any definitions for var + -snapshot=name + name the configuration (only if no -target specified) + +Direct options for the following parameters exist: + + -ret_stack_size = {2, 3, 4, ... 8} + size of return stack + -btb_size = { 32, 48, 64, 128, 256, 512 } + size of branch target buffer + -dccm_region = { 0x0, 0x1, ... 0xf } + number of 256Mb memory region containig DCCM + -dccm_offset = hexadecimal + offset (in bytes) of DCCM witin dccm_region + dccm address will be: 256M * dccm_region + dccm_offset\", and that must be aligned + to the dccm size or the next larger power of 2 if size is not a power of 2 + -dccm_size = { 4, 8, 16, 32, 48, 64, 128, 256, 512 } kB + size of DCCM + -iccm_enable = { 0, 1 } + whether or not ICCM is enabled + -icache_enable = { 0, 1 } + whether or not icache is enabled + -icache_ecc = { 0, 1 } + whether or not icache has ecc - EXPENSIVE 30% sram growth + default: icache_ecc==0 (parity) + -iccm_region = { 0x0, 0x1, ... 0xf } + number of 256Mb memory region containing ICCM + -iccm_offset = hexadecimal + offcet (in bytes) of ICCM within iccm_region + iccm address will be: \"256M * iccm_region + iccm_offset\", and that must be aligned + to the iccm size or the next larger power of 2 if size is not a power of 2 + -iccm_size = { 4 , 8 , 16 , 32, 64, 128, 256, 512 } kB + size of ICCM + -icache_size = { 16, 32, 64, 128, 256 } kB + size of icache + -pic_2cycle = { 0, 1 } + whether or not 2-cycle PIC is enabled (2 cycle pic may result + in an overall smaller cycle time) + -pic_region = { 0x0, 0x1, ... 0xf } + nuber of 256Mb memory region containing PIC memory-mapped registers + -pic_offset = hexadecial + offset (in bytes) of PIC within pic_region + pic address will be: \"256M * pic_region + pic_offset\", and that must be aligned + to the pic size or the next larger power of 2 if size is not a power of 2 + -pic_size = { 32, 64, 128, 256 } kB + size of PIC + -pic_total_int = { 1, 2, 3, ..., 255 } + number of interrupt sources in PIC + -ahb_lite + build with AHB-lite bus interface + default is AXI4 + -fpga_optimize = { 0, 1 } + if 1, minimize clock-gating to facilitate FPGA builds +"; + + +my $ret_stack_size; +my $btb_size; +my $bht_size; +my $dccm_region; +my $dccm_offset; +my $dccm_size; +my $iccm_enable; +my $icache_enable; +my $icache_ecc; +my $iccm_region; +my $iccm_offset; +my $iccm_size; +my $icache_size; +my $pic_2cycle; +my $pic_region; +my $pic_offset; +my $pic_size; +my $pic_total_int; +my $ahb_lite; +my $fpga_optimize; + +my $top_align_iccm = 0; + +my $target = "default"; +my $snapshot ; +my $build_path ; + +GetOptions( + "help" => \$help, + "target=s" => \$target, + "snapshot=s" => \$snapshot, + "verbose" => \$verbose, + "ret_stack_size=s" => \$ret_stack_size, + "btb_size=s" => \$btb_size, + "bht_size=s" => \$bht_size, + "dccm_enable=s" => \$dccm_enable, + "dccm_region=s" => \$dccm_region, + "dccm_offset=s" => \$dccm_offset, + "dccm_size=s" => \$dccm_size, + "iccm_enable=s" => \$iccm_enable, + "icache_enable=s" => \$icache_enable, + "icache_ecc=s" => \$icache_ecc, + "iccm_region=s" => \$iccm_region, + "iccm_offset=s" => \$iccm_offset, + "iccm_size=s" => \$iccm_size, + "pic_2cycle=s" => \$pic_2cycle, + "pic_region=s" => \$pic_region, + "pic_offset=s" => \$pic_offset, + "pic_size=s" => \$pic_size, + "pic_total_int=s" => \$pic_total_int, + "icache_size=s" => \$icache_size, + "ahb_lite" => \$ahb_lite, + "fpga_optimize" => \$fpga_optimize, + "set=s@" => \@sets, + "unset=s@" => \@unsets, +) || die("$helpusage"); + +if ($help) { + print "$helpusage\n"; + exit; +} + +if (!defined $snapshot ) { + $snapshot = $target; +} + +if (!defined $ENV{BUILD_PATH}) { + $build_path = "$ENV{PWD}/snapshots/$snapshot" ; +} else { + $build_path = $ENV{BUILD_PATH}; +} + +if (! -d "$build_path") { + system ("mkdir -p $build_path"); +} + +# Verilog defines file path +my $vlogfile = "$build_path/common_defines.vh"; + +# Assembly defines file path +my $asmfile = "$build_path/defines.h"; + +# PD defines file path +my $pdfile = "$build_path/pd_defines.vh"; + +# Whisper config file path +my $whisperfile = "$build_path/whisper.json"; + +# Default linker file +my $linkerfile = "$build_path/link.ld"; + +# Perl defines file path +my $perlfile = "$build_path/perl_configs.pl"; + +my $no_secondary_alu=0; + +if ($target eq "default") { + if (!defined($ret_stack_size)) { $ret_stack_size=4; } + if (!defined($btb_size)) { $btb_size=32; } + if (!defined($bht_size)) { $bht_size=128; } + if (!defined($dccm_enable)) { $dccm_enable=1; } + if (!defined($dccm_region)) { $dccm_region="0xf"; } + if (!defined($dccm_offset)) { $dccm_offset="0x40000"; } #1*256*1024 + if (!defined($dccm_size)) { $dccm_size=64; } + if (!defined($dccm_num_banks)) { $dccm_num_banks=8; } + if (!defined($iccm_enable)) { $iccm_enable=0; } + if (!defined($iccm_region)) { $iccm_region="0xe"; } + if (!defined($iccm_offset)) { $iccm_offset="0xe000000"; } #0x380*256*1024 + if (!defined($iccm_size)) { $iccm_size=512; } + if (!defined($iccm_num_banks)) { $iccm_num_banks=8; } + if (!defined($icache_enable)) { $icache_enable=1; } + if (!defined($icache_ecc)) { $icache_ecc=0; } + if (!defined($icache_size)) { $icache_size=16; } + if (!defined($pic_2cycle)) { $pic_2cycle=0; } + if (!defined($pic_region)) { $pic_region="0xf"; } + if (!defined($pic_offset)) { $pic_offset="0xc0000"; } # 3*256*1024 + if (!defined($pic_size)) { $pic_size=32; } + if (!defined($pic_total_int)) { $pic_total_int=8; } + if (!defined($fpga_optimize)) { $fpga_optimize=1; } + + # default is AXI bus +} +elsif ($target eq "default_ahb") { + if (!defined($ret_stack_size)) { $ret_stack_size=4; } + if (!defined($btb_size)) { $btb_size=32; } + if (!defined($bht_size)) { $bht_size=128; } + if (!defined($dccm_enable)) { $dccm_enable=1; } + if (!defined($dccm_region)) { $dccm_region="0xf"; } + if (!defined($dccm_offset)) { $dccm_offset="0x40000"; } #1*256*1024 + if (!defined($dccm_size)) { $dccm_size=64; } + if (!defined($dccm_num_banks)) { $dccm_num_banks=8; } + if (!defined($iccm_enable)) { $iccm_enable=0; } + if (!defined($iccm_region)) { $iccm_region="0xe"; } + if (!defined($iccm_offset)) { $iccm_offset="0xe000000"; } #0x380*256*1024 + if (!defined($iccm_size)) { $iccm_size=512; } + if (!defined($iccm_num_banks)) { $iccm_num_banks=8; } + if (!defined($icache_enable)) { $icache_enable=1; } + if (!defined($icache_ecc)) { $icache_ecc=0; } + if (!defined($icache_size)) { $icache_size=16; } + if (!defined($pic_2cycle)) { $pic_2cycle=0; } + if (!defined($pic_region)) { $pic_region="0xf"; } + if (!defined($pic_offset)) { $pic_offset="0xc0000"; } # 3*256*1024 + if (!defined($pic_size)) { $pic_size=32; } + if (!defined($pic_total_int)) { $pic_total_int=8; } + if (!defined($fpga_optimize)) { $fpga_optimize=1; } + $ahb_lite = 1; + +} elsif ($target eq "default_pd") { + if (!defined($ret_stack_size)) { $ret_stack_size=4; } + if (!defined($btb_size)) { $btb_size=32; } + if (!defined($bht_size)) { $bht_size=128; } + if (!defined($dccm_enable)) { $dccm_enable=1; } + if (!defined($dccm_region)) { $dccm_region="0xf"; } + if (!defined($dccm_offset)) { $dccm_offset="0x40000"; } #1*256*1024 + if (!defined($dccm_size)) { $dccm_size=32; } + if (!defined($dccm_num_banks)) { $dccm_num_banks=8; } + if (!defined($iccm_enable)) { $iccm_enable=0; } + if (!defined($iccm_region)) { $iccm_region="0xe"; } + if (!defined($iccm_offset)) { $iccm_offset="0xe000000"; } #0x380*256*1024 + if (!defined($iccm_size)) { $iccm_size=512; } + if (!defined($iccm_num_banks)) { $iccm_num_banks=8; } + if (!defined($icache_enable)) { $icache_enable=1; } + if (!defined($icache_ecc)) { $icache_ecc=0; } + if (!defined($icache_size)) { $icache_size=16; } + if (!defined($pic_2cycle)) { $pic_2cycle=0; } + if (!defined($pic_region)) { $pic_region="0xf"; } + if (!defined($pic_offset)) { $pic_offset="0xc0000"; } # 3*256*1024 + if (!defined($pic_size)) { $pic_size=32; } + if (!defined($pic_total_int)) { $pic_total_int=8; } + if (!defined($fpga_optimize)) { $fpga_optimize=0; } + +} elsif ($target eq "high_perf") { + if (!defined($ret_stack_size)) { $ret_stack_size=4; } + if (!defined($btb_size)) { $btb_size=512; } + if (!defined($bht_size)) { $bht_size=2048; } + if (!defined($dccm_enable)) { $dccm_enable=1; } + if (!defined($dccm_region)) { $dccm_region="0xf"; } + if (!defined($dccm_offset)) { $dccm_offset="0x40000"; } #1*256*1024 + if (!defined($dccm_size)) { $dccm_size=64; } + if (!defined($dccm_num_banks)) { $dccm_num_banks=8; } + if (!defined($iccm_enable)) { $iccm_enable=0; } + if (!defined($iccm_region)) { $iccm_region="0xe"; } + if (!defined($iccm_offset)) { $iccm_offset="0xe000000"; } #0x380*256*1024 + if (!defined($iccm_size)) { $iccm_size=512; } + if (!defined($iccm_num_banks)) { $iccm_num_banks=8; } + if (!defined($icache_enable)) { $icache_enable=1; } + if (!defined($icache_ecc)) { $icache_ecc=0; } + if (!defined($icache_size)) { $icache_size=32; } + if (!defined($pic_2cycle)) { $pic_2cycle=0; } + if (!defined($pic_region)) { $pic_region="0xf"; } + if (!defined($pic_offset)) { $pic_offset="0xc0000"; } # 3*256*1024 + if (!defined($pic_size)) { $pic_size=32; } + if (!defined($pic_total_int)) { $pic_total_int=8; } + if (!defined($fpga_optimize)) { $fpga_optimize=1; } + +} else { + die "$self: ERROR! Unsupported target \"$target\". Supported targets are: \"default, default_ahb, default_pd, high_perf\"!\n"; +} + +# general stuff - can't set from command line other than -set + +if (!defined($lsu_stbuf_depth)) { $lsu_stbuf_depth=8; } +if (!defined($dma_buf_depth)) { $dma_buf_depth=4; } +if (!defined($lsu_num_nbload)) { $lsu_num_nbload=8; } +if (!defined($dec_instbuf_depth)) { $dec_instbuf_depth=4; } + + +# Configure triggers +our @triggers = (#{{{ + { + "reset" => ["0x23e00000", "0x00000000", "0x00000000"], + "mask" => ["0x081818c7", "0xffffffff", "0x00000000"], + "poke_mask" => ["0x081818c7", "0xffffffff", "0x00000000"] + }, + { + "reset" => ["0x23e00000", "0x00000000", "0x00000000"], + "mask" => ["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", + }, + "mvendorid" => { + "reset" => "0x45", + "mask" => "0x0", + "exists" => "true", + }, + "marchid" => { + "reset" => "0x0000000b", + "mask" => "0x0", + "exists" => "true", + }, + "mimpid" => { + "reset" => "0x6", + "mask" => "0x0", + "exists" => "true", + }, + "misa" => { + "reset" => "0x40001104", + "mask" => "0x0", + "exists" => "true", + }, + "tselect" => { + "reset" => "0x0", + "mask" => "0x3", # Four triggers + "exists" => "true", + }, + "dcsr" => { + "reset" => "0x40000003", + "mask" => "0x00008c04", + "poke_mask" => "0x00008dcc", # cause field modifiable, nmip modifiable + "exists" => "true", + }, + "cycle" => { + "exists" => "false", + }, + "time" => { + "exists" => "false", + }, + "instret" => { + "exists" => "false", + }, + "mcountinhibit" => { + "exists" => "false", + }, + "mcounteren" => { + "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", + }, + "mgpmc" => { + "number" => "0x7d0", + "reset" => "0x1", + "mask" => "0x1", + "exists" => "true", + }, + "mitcnt0" => { + "number" => "0x7d2", + "reset" => "0x0", + "mask" => "0xffffffff", + "exists" => "true", + }, + "mitbnd0" => { + "number" => "0x7d3", + "reset" => "0xffffffff", + "mask" => "0xffffffff", + "exists" => "true", + }, + "mitctl0" => { + "number" => "0x7d4", + "reset" => "0x1", + "mask" => "0x00000007", + "exists" => "true", + }, + "mitcnt1" => { + "number" => "0x7d5", + "reset" => "0x0", + "mask" => "0xffffffff", + "exists" => "true", + }, + "mitbnd1" => { + "number" => "0x7d6", + "reset" => "0xffffffff", + "mask" => "0xffffffff", + "exists" => "true", + }, + "mitctl1" => { + "number" => "0x7d7", + "reset" => "0x1", + "mask" => "0x00000007", + "exists" => "true", + }, + "mcpc" => { + "number" => "0x7c2", + "reset" => "0x0", + "mask" => "0x0", + "exists" => "true", + }, + "mpmc" => { + "comment" => "FWHALT", + "number" => "0x7c6", + "reset" => "0x2", + "mask" => "0x2", + "poke_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" => "0x0", + "mask" => "0x000001ff", + "poke_mask" => "0x000001ff", + "exists" => "true", + }, + "mfdc" => { + "number" => "0x7f9", + "reset" => "0x00070000", + "mask" => "0x000727ff", + "exists" => "true", + }, + "dmst" => { + "comment" => "Memory synch trigger: Flush caches in debug mode.", + "number" => "0x7c4", + "reset" => "0x0", + "mask" => "0x0", + "exists" => "true", + "debug" => "true", + }, + "dicawics" => { + "comment" => "Cache diagnostics.", + "number" => "0x7c8", + "reset" => "0x0", + "mask" => "0x0130fffc", + "exists" => "true", + "debug" => "true", + }, + "dicad0" => { + "comment" => "Cache diagnostics.", + "number" => "0x7c9", + "reset" => "0x0", + "mask" => "0xffffffff", + "exists" => "true", + "debug" => "true", + }, + "dicad1" => { + "comment" => "Cache diagnostics.", + "number" => "0x7ca", + "reset" => "0x0", + "mask" => "0x3", + "exists" => "true", + "debug" => "true", + }, + "dicago" => { + "comment" => "Cache diagnostics.", + "number" => "0x7cb", + "reset" => "0x0", + "mask" => "0x0", + "exists" => "true", + "debug" => "true", + }, + "meipt" => { + "comment" => "External interrupt priority threshold.", + "number" => "0xbc9", + "reset" => "0x0", + "mask" => "0xf", + "exists" => "true", + }, + "meicpct" => { + "comment" => "External claim id/priority capture.", + "number" => "0xbca", + "reset" => "0x0", + "mask" => "0x0", + "exists" => "true", + }, + "meicidpl" => { + "comment" => "External interrupt claim id priority level.", + "number" => "0xbcb", + "reset" => "0x0", + "mask" => "0xf", + "exists" => "true", + }, + "meicurpl" => { + "comment" => "External interrupt current priority level.", + "number" => "0xbcc", + "reset" => "0x0", + "mask" => "0xf", + "exists" => "true", + }, + +);#}}} + + +foreach my $i (0 .. 3) { + $csr{"pmpcfg$i"} = { "exists" => "false" }; +} + +foreach my $i (0 .. 15) { + $csr{"pmpaddr$i"} = { "exists" => "false" }; +} + + + +# }}} +# Main config hash, with default values +# +# Hash can be hierarchical with arbitrary levels +# Hexadecimal values are prefixed with 0x +# +# For verilog, if bit width is expected, add to %width hash below +our %config = (#{{{ + "harts" => "1", + "xlen" => "32", + "numiregs" => "32", + "regwidth" => "32", + "reset_vec" => "0x80000000", + "nmi_vec" => "0x11110000", + "physical" => "1", + "num_mmode_perf_regs" => "4", # Whisper only + "max_mmode_perf_event" => "50", # Whisper only: performance counters event ids will be clamped to this + "target" => $target, + "tec_rv_icg" => "clockhdr", + "verilator" => "$verilator", + + "retstack" => { + "ret_stack_size" => "$ret_stack_size", + }, + + "btb" => { + "btb_size" => "$btb_size", + "btb_index1_hi" => "derived", + "btb_index1_lo" => "4", + "btb_index2_hi" => "derived", + "btb_index2_lo" => "derived", + "btb_index3_hi" => "derived", + "btb_index3_lo" => "derived", + "btb_addr_hi" => "derived", + "btb_array_depth" => "derived", + "btb_addr_lo" => "4", + "btb_btag_size" => "derived", + }, + "bht" => { + "bht_size" => "$bht_size", + "bht_addr_hi" => "derived", + "bht_addr_lo" => "4", + "bht_array_depth" => "derived", + "bht_ghr_size" => "derived", + "bht_ghr_range" => "derived", + "bht_ghr_pad" => "derived", + "bht_ghr_pad2" => "derived", + "bht_hash_string" => "derived", + + }, + + "core" => { + "dec_instbuf_depth" => "$dec_instbuf_depth", + "lsu_stbuf_depth" => "$lsu_stbuf_depth", + "dma_buf_depth" => "$dma_buf_depth", + "lsu_num_nbload" => "$lsu_num_nbload", + "no_secondary_alu" => "$no_secondary_alu", + "fpga_optimize" => "$fpga_optimize" + }, + + "dccm" => { + "dccm_enable" => "$dccm_enable", # Comment this out if no DCCM + "dccm_region" => "$dccm_region", # 256M region number + "dccm_offset" => "$dccm_offset", # 256K offset number + "dccm_size" => "$dccm_size", # Size in Kbytes + "dccm_num_banks" => "$dccm_num_banks", + "dccm_sadr" => 'derived', + "dccm_eadr" => 'derived', + "dccm_bits" => 'derived', + "dccm_bank_bits" => 'derived', + "dccm_data_width" => 'derived', + "dccm_fdata_width" => 'derived', + "dccm_byte_width" => 'derived', + "dccm_width_bits" => 'derived', + "dccm_index_bits" => 'derived', + "dccm_ecc_width" => 'derived', + "lsu_sb_bits" => 'derived', + "dccm_data_cell" => 'derived', + "dccm_rows" => 'derived', + "dccm_reserved" => 'derived', # reserve dccm space for SW/stack - no random r/w + }, + + + "iccm" => { + "iccm_enable" => "$iccm_enable", # Comment this out if no ICCM + "iccm_region" => "$iccm_region", # 256M region number + "iccm_offset" => "$iccm_offset", # 256K offset number + "iccm_size" => "$iccm_size", # Size in Kbytes + "iccm_num_banks" => "$iccm_num_banks", + "iccm_bank_bits" => 'derived', + "iccm_index_bits" => 'derived', + "iccm_rows" => 'derived', + "iccm_data_cell" => 'derived', + "iccm_sadr" => 'derived', + "iccm_eadr" => 'derived', + "iccm_reserved" => 'derived', # reserve iccm space for SW/handlers - no random r/w + }, + "icache" => { + "icache_enable" => "$icache_enable", + "icache_size" => "$icache_size", + "icache_data_cell" => 'derived', + "icache_tag_cell" => 'derived', + "icache_taddr_high" => 'derived', + "icache_tag_high" => 'derived', + "icache_tag_depth" => 'derived', + "icache_ic_depth" => 'derived', + "icache_ic_rows" => 'derived', + "icache_ic_index" => 'derived', + "icache_tag_low" => '6', + "icache_ecc" => "$icache_ecc", + }, + "pic" => { + "pic_2cycle" => "$pic_2cycle", # two cycle PIC for timing reasons + "pic_region" => "$pic_region", # 256M region number + "pic_offset" => "$pic_offset", # 256K offset number + "pic_size" => "$pic_size", # Size in Kbytes + "pic_base_addr" => 'derived', # base_addr = pic_region + offset + "pic_total_int_plus1" => 'derived', # pic_total_int + 1 + "pic_total_int" => "$pic_total_int",# number of interrupt pins (Smax) + "pic_int_words" => 'derived', # number of 32 bit words for packed registers (Xmax) + "pic_bits" => 'derived', # of bits needs to address the PICM + "pic_meipl_offset" => '0x0000', # Offset of meipl relative to pic_base_addr + "pic_meip_offset" => '0x1000', # Offset of meip relative to pic_base_addr + "pic_meie_offset" => '0x2000', # Offset of meie relative to pic_base_addr + "pic_mpiccfg_offset" => '0x3000', # Offset of mpiccfg relative to pic_base_addr + "pic_meipt_offset" => '0x3004', # Offset of meipt relative to pic_base_addr -- deprecated + "pic_meigwctrl_offset" => '0x4000', # gateway control regs relative to pic_base_addr + "pic_meigwclr_offset" => '0x5000', # gateway clear regs relative to pic_base_addr + "pic_meipl_mask" => '0xf', + "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" => $pic_total_int, + "pic_meip_count" => 4, + "pic_meie_count" => $pic_total_int, + "pic_mpiccfg_count" => 1, + "pic_meipt_count" => $pic_total_int, + "pic_meigwctrl_count" => $pic_total_int, + "pic_meigwclr_count" => $pic_total_int + }, + "testbench" => { + "TOP" => "tb_top", + "RV_TOP" => "`TOP.rvtop", + "CPU_TOP" => "`RV_TOP.swerv", + "clock_period" => "100", + "build_ahb_lite" => "$ahb_lite", # one and only one bus build arg will ever be defined + "build_axi4" => "1", + "assert_on" => "", + "datawidth" => "64", # deprecate this !! FIXME + "ext_datawidth" => "64", + "ext_addrwidth" => "32", + "sterr_rollback" => "0", + "lderr_rollback" => "1", + "SDVT_AHB" => "1", + }, + "protection" => { + "inst_access_enable0" => "0x0", + "inst_access_addr0" => "0x00000000", + "inst_access_mask0" => "0xffffffff", + "inst_access_enable1" => "0x0", + "inst_access_addr1" => "0x00000000", + "inst_access_mask1" => "0xffffffff", + "inst_access_enable2" => "0x0", + "inst_access_addr2" => "0x00000000", + "inst_access_mask2" => "0xffffffff", + "inst_access_enable3" => "0x0", + "inst_access_addr3" => "0x00000000", + "inst_access_mask3" => "0xffffffff", + "inst_access_enable4" => "0x0", + "inst_access_addr4" => "0x00000000", + "inst_access_mask4" => "0xffffffff", + "inst_access_enable5" => "0x0", + "inst_access_addr5" => "0x00000000", + "inst_access_mask5" => "0xffffffff", + "inst_access_enable6" => "0x0", + "inst_access_addr6" => "0x00000000", + "inst_access_mask6" => "0xffffffff", + "inst_access_enable7" => "0x0", + "inst_access_addr7" => "0x00000000", + "inst_access_mask7" => "0xffffffff", + "data_access_enable0" => "0x0", + "data_access_addr0" => "0x00000000", + "data_access_mask0" => "0xffffffff", + "data_access_enable1" => "0x0", + "data_access_addr1" => "0x00000000", + "data_access_mask1" => "0xffffffff", + "data_access_enable2" => "0x0", + "data_access_addr2" => "0x00000000", + "data_access_mask2" => "0xffffffff", + "data_access_enable3" => "0x0", + "data_access_addr3" => "0x00000000", + "data_access_mask3" => "0xffffffff", + "data_access_enable4" => "0x0", + "data_access_addr4" => "0x00000000", + "data_access_mask4" => "0xffffffff", + "data_access_enable5" => "0x0", + "data_access_addr5" => "0x00000000", + "data_access_mask5" => "0xffffffff", + "data_access_enable6" => "0x0", + "data_access_addr6" => "0x00000000", + "data_access_mask6" => "0xffffffff", + "data_access_enable7" => "0x0", + "data_access_addr7" => "0x00000000", + "data_access_mask7" => "0xffffffff", + }, + "memmap" => { # Testbench only + "serialio" => 'derived, overridable', # Testbench only + "external_data" => 'derived, overridable', # Testbench only + "external_prog" => 'derived, overridable', # Testbench only + "debug_sb_mem" => 'derived, overridable', # Testbench only + "external_data_1" => 'derived, overridable', # Testbench only + "external_mem_hole" => 'default disabled', # Testbench only +# "consoleio" => 'derived', # Part of serial io. + }, + "bus" => { + "lsu_bus_tag" => 'derived', + "dma_bus_tag" => '1', + "sb_bus_tag" => '1', + "ifu_bus_tag" => '3', + }, + "triggers" => \@triggers, + "csr" => \%csr, + "even_odd_trigger_chains" => "true", +); + +if (($fpga_optimize==0) && !grep(/fpga_optimize/, @sets)) { delete $config{"core"}{"fpga_optimize"}; } +if (($iccm_enable==0) && !grep(/iccm_enable/, @sets)) { delete $config{"iccm"}{"iccm_enable"}; } +if (($dccm_enable==0) && !grep(/dccm_enable/, @sets)) { delete $config{"dccm"}{"dccm_enable"}; } +if (($icache_enable==0) && !grep(/icache_enable/, @sets)) { delete $config{"icache"}{"icache_enable"}; } +if (($verilator==0) && !grep(/verilator/, @sets)) { delete $config{"core"}{"verilator"}; } +if (($no_secondary_alu==0) && !grep(/no_secondary_alu/, @sets)) { delete $config{"core"}{"no_secondary_alu"}; } +if (($pic_2cycle==0) && !grep(/pic_2cycle/, @sets)) { delete $config{"pic"}{"pic_2cycle"}; } +if (($icache_ecc==0) && !grep(/icache_ecc/, @sets)) { delete $config{"icache"}{"icache_ecc"}; } + + + +# Perform any overrides first before derived values +map_set_unset(); +gen_define("","", \%config,[]); +print "\nSweRV configuration for target=$target\n\n"; +dump_define("","", \%config,[]); + + +# perform final checks +my $c; +$c=$config{retstack}{ret_stack_size}; if (!($c >=2 && $c <=8)) { die("$helpusage\n\nFAIL: ret_stack_size == $c; ILLEGAL !!!\n\n"); } +$c=$config{btb}{btb_size}; if (!($c==32||$c==48||$c==64||$c==128||$c==256||$c==512)){ die("$helpusage\n\nFAIL: btb_size == $c; ILLEGAL !!!\n\n"); } +$c=$config{iccm}{iccm_region}; if (!($c>=0 && $c<16)) { die("$helpusage\n\nFAIL: iccm_region == $c ILLEGAL !!!\n\n"); } +$c=$config{iccm}{iccm_offset}; if (!($c>=0 && $c<256*1024*1024 && ($c&0xfff)==0)) { die("$helpusage\n\nFAIL: iccm_offset == $c ILLEGAL !!!\n\n"); } +$c=$config{iccm}{iccm_size}; if (!($c==4||$c==8||$c==16||$c==32||$c==64||$c==128||$c==256||$c==512)) { die("$helpusage\n\nFAIL: iccm_size == $c ILLEGAL !!!\n\n"); } +$c=$config{iccm}{iccm_num_banks}; if (!($c==4 || $c==8 || ($c==16 && $config{iccm}{iccm_size} != 4))) { die("$helpusage\n\nFAIL: iccm_num_banks == $c ILLEGAL !!!\n\n"); } +$c=$config{iccm}{iccm_enable}; if (!($c==0 || $c==1)) { die("$helpusage\n\nFAIL: iccm_enable == $c ILLEGAL !!!\n\n"); } +$c=$config{dccm}{dccm_region}; if (!($c>=0 && $c<16)) { die("$helpusage\n\nFAIL: iccm_region == $c ILLEGAL !!!\n\n"); } +$c=$config{dccm}{dccm_num_banks}; if (!($c==4 || $c==8 || ($c==16 && $config{dccm}{dccm_size} != 4) )) { die("$helpusage\n\nFAIL: dccm_num_banks == $c ILLEGAL !!!\n\n"); } +$c=$config{dccm}{dccm_offset}; if (!($c>=0 && $c<256*1024*1024 && ($c&0xfff)==0)) { die("$helpusage\n\nFAIL: iccm_offset == $c ILLEGAL !!!\n\n"); } +$c=$config{dccm}{dccm_size}; if (!($c==4||$c==8||$c==16||$c==32||$c==48||$c==64||$c==128||$c==256||$c==512)) { die("$helpusage\n\nFAIL: iccm_size == $c ILLEGAL !!!\n\n"); } +$c=$config{pic}{pic_2cycle}; if (!($c==0 || $c==1)) { die("$helpusage\n\nFAIL: pic_2cycle == $c ILLEGAL !!!\n\n"); } +$c=$config{pic}{pic_region}; if (!($c>=0 && $c<16)) { die("$helpusage\n\nFAIL: pic_region == $c ILLEGAL !!!\n\n"); } +$c=$config{pic}{pic_offset}; if (!($c>=0 && $c<256*1024*1024 && ($c&0xfff)==0)) { die("$helpusage\n\nFAIL: pic_offset == $c ILLEGAL !!!\n\n"); } +$c=$config{pic}{pic_size}; if (!($c==32 || $c==64 || $c==128 || $c==256)) { die("$helpusage\n\nFAIL: pic_size == $c ILLEGAL !!!\n\n"); } +$c=$config{pic}{pic_total_int}; if ( $c<1 || $c>255) { die("$helpusage\n\nFAIL: pic_total_int == $c ILLEGAL !!!\n\n"); } +$c=$config{icache}{icache_enable}; if (!($c==0 || $c==1)) { die("$helpusage\n\nFAIL: icache_enable == $c ILLEGAL !!!\n\n"); } +$c=$config{icache}{icache_size}; if (!($c==16 || $c==32 || $c==64 || $c==128 || $c==256)) { die("$helpusage\n\nFAIL: icache_size == $c ILLEGAL !!!\n\n"); } +$c=$config{core}{dec_instbuf_depth}; if (!($c==2 || $c==4)) { die("$helpusage\n\nFAIL: dec_instbuf_depth == $c ILLEGAL !!!\n\n"); } +$c=$config{core}{lsu_stbuf_depth}; if (!($c==2 || $c==4 || $c==8)) { die("$helpusage\n\nFAIL: lsu_stbuf_depth == $c ILLEGAL !!!\n\n"); } +$c=$config{core}{dma_buf_depth}; if (!($c==2 || $c==4)) { die("$helpusage\n\nFAIL: dma_buf_depth == $c ILLEGAL !!!\n\n"); } +$c=$config{core}{lsu_num_nbload}; if (!($c==2 || $c==4 || $c==8)) { die("$helpusage\n\nFAIL: lsu_num_nbload == $c ILLEGAL !!!\n\n"); } + +$c=$config{protection}{inst_access_addr0}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: inst_access_addr0 lower 6b must be 0s $c !!!\n\n"); } +$c=$config{protection}{inst_access_addr1}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: inst_access_addr1 lower 6b must be 0s !!!\n\n"); } +$c=$config{protection}{inst_access_addr2}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: inst_access_addr2 lower 6b must be 0s !!!\n\n"); } +$c=$config{protection}{inst_access_addr3}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: inst_access_addr3 lower 6b must be 0s !!!\n\n"); } +$c=$config{protection}{inst_access_addr4}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: inst_access_addr4 lower 6b must be 0s !!!\n\n"); } +$c=$config{protection}{inst_access_addr5}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: inst_access_addr5 lower 6b must be 0s !!!\n\n"); } +$c=$config{protection}{inst_access_addr6}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: inst_access_addr6 lower 6b must be 0s !!!\n\n"); } +$c=$config{protection}{inst_access_addr7}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: inst_access_addr7 lower 6b must be 0s !!!\n\n"); } +$c=$config{protection}{inst_access_mask0}; if ((hex($c)&0x3f) != 63) { die("$helpusage\n\nFAIL: inst_access_mask0 lower 6b must be 1s !!!\n\n"); } +$c=$config{protection}{inst_access_mask1}; if ((hex($c)&0x3f) != 63) { die("$helpusage\n\nFAIL: inst_access_mask1 lower 6b must be 1s !!!\n\n"); } +$c=$config{protection}{inst_access_mask2}; if ((hex($c)&0x3f) != 63) { die("$helpusage\n\nFAIL: inst_access_mask2 lower 6b must be 1s !!!\n\n"); } +$c=$config{protection}{inst_access_mask3}; if ((hex($c)&0x3f) != 63) { die("$helpusage\n\nFAIL: inst_access_mask3 lower 6b must be 1s !!!\n\n"); } +$c=$config{protection}{inst_access_mask4}; if ((hex($c)&0x3f) != 63) { die("$helpusage\n\nFAIL: inst_access_mask4 lower 6b must be 1s !!!\n\n"); } +$c=$config{protection}{inst_access_mask5}; if ((hex($c)&0x3f) != 63) { die("$helpusage\n\nFAIL: inst_access_mask5 lower 6b must be 1s !!!\n\n"); } +$c=$config{protection}{inst_access_mask6}; if ((hex($c)&0x3f) != 63) { die("$helpusage\n\nFAIL: inst_access_mask6 lower 6b must be 1s !!!\n\n"); } +$c=$config{protection}{inst_access_mask7}; if ((hex($c)&0x3f) != 63) { die("$helpusage\n\nFAIL: inst_access_mask7 lower 6b must be 1s !!!\n\n"); } +$c=$config{protection}{data_access_addr0}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: data_access_addr0 lower 6b must be 0s !!!\n\n"); } +$c=$config{protection}{data_access_addr1}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: data_access_addr1 lower 6b must be 0s !!!\n\n"); } +$c=$config{protection}{data_access_addr2}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: data_access_addr2 lower 6b must be 0s !!!\n\n"); } +$c=$config{protection}{data_access_addr3}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: data_access_addr3 lower 6b must be 0s !!!\n\n"); } +$c=$config{protection}{data_access_addr4}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: data_access_addr4 lower 6b must be 0s !!!\n\n"); } +$c=$config{protection}{data_access_addr5}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: data_access_addr5 lower 6b must be 0s !!!\n\n"); } +$c=$config{protection}{data_access_addr6}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: data_access_addr6 lower 6b must be 0s !!!\n\n"); } +$c=$config{protection}{data_access_addr7}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: data_access_addr7 lower 6b must be 0s !!!\n\n"); } +$c=$config{protection}{data_access_mask0}; if ((hex($c)&0x3f) != 63) { die("$helpusage\n\nFAIL: data_access_mask0 lower 6b must be 1s !!!\n\n"); } +$c=$config{protection}{data_access_mask1}; if ((hex($c)&0x3f) != 63) { die("$helpusage\n\nFAIL: data_access_mask1 lower 6b must be 1s !!!\n\n"); } +$c=$config{protection}{data_access_mask2}; if ((hex($c)&0x3f) != 63) { die("$helpusage\n\nFAIL: data_access_mask2 lower 6b must be 1s !!!\n\n"); } +$c=$config{protection}{data_access_mask3}; if ((hex($c)&0x3f) != 63) { die("$helpusage\n\nFAIL: data_access_mask3 lower 6b must be 1s !!!\n\n"); } +$c=$config{protection}{data_access_mask4}; if ((hex($c)&0x3f) != 63) { die("$helpusage\n\nFAIL: data_access_mask4 lower 6b must be 1s !!!\n\n"); } +$c=$config{protection}{data_access_mask5}; if ((hex($c)&0x3f) != 63) { die("$helpusage\n\nFAIL: data_access_mask5 lower 6b must be 1s !!!\n\n"); } +$c=$config{protection}{data_access_mask6}; if ((hex($c)&0x3f) != 63) { die("$helpusage\n\nFAIL: data_access_mask6 lower 6b must be 1s !!!\n\n"); } +$c=$config{protection}{data_access_mask7}; if ((hex($c)&0x3f) != 63) { die("$helpusage\n\nFAIL: data_access_mask7 lower 6b must be 1s !!!\n\n"); } + + + +if (($config{testbench}{build_ahb_lite} ne "")) { + delete $config{testbench}{build_axi4}; +} +else { # default is AXI bus + delete $config{testbench}{build_ahb_lite}; +} + + +# Over-ride MFDC reset value for AXI. +if (exists($config{testbench}{build_axi4}) ) { + $config{csr}{mfdc}{reset} = "0x00070040" if exists $config{csr}{mfdc}; +} + + + +# Fill in derived configuration entries. + +if($config{btb}{btb_size}==512){ + $config{btb}{btb_index1_hi} = 9; + $config{btb}{btb_index2_hi} = 15; + $config{btb}{btb_index3_hi} = 21; + $config{btb}{btb_array_depth}= 64; + $config{btb}{btb_btag_size} = 5; +} elsif($config{btb}{btb_size}==256){ + $config{btb}{btb_index1_hi} = 8; + $config{btb}{btb_index2_hi} = 13; + $config{btb}{btb_index3_hi} = 18; + $config{btb}{btb_array_depth}= 32; + $config{btb}{btb_btag_size} = 6; +} elsif($config{btb}{btb_size}==128){ + $config{btb}{btb_index1_hi} = 7; + $config{btb}{btb_index2_hi} = 11; + $config{btb}{btb_index3_hi} = 15; + $config{btb}{btb_array_depth}= 16; + $config{btb}{btb_btag_size} = 7; +} elsif($config{btb}{btb_size}==64){ + $config{btb}{btb_index1_hi} = 6; + $config{btb}{btb_index2_hi} = 9; + $config{btb}{btb_index3_hi} = 12; + $config{btb}{btb_array_depth}= 8; + $config{btb}{btb_btag_size} = 8; +} elsif($config{btb}{btb_size}==48){ + $config{btb}{btb_index1_hi} = 5; + $config{btb}{btb_index2_hi} = 7; + $config{btb}{btb_index3_hi} = 9; + $config{btb}{btb_array_depth}= 4; + $config{btb}{btb_48}= 1; + $config{btb}{btb_fold2_index_hash} = 1; + $config{btb}{btb_btag_size} = 9; + $config{btb}{btb_btag_fold} = 1; +} elsif($config{btb}{btb_size}==32){ + $config{btb}{btb_index1_hi} = 5; + $config{btb}{btb_index2_hi} = 7; + $config{btb}{btb_index3_hi} = 9; + $config{btb}{btb_array_depth}= 4; + $config{btb}{btb_btag_size} = 9; + $config{btb}{btb_btag_fold} = 1; +} + +$config{btb}{btb_index2_lo} = $config{btb}{btb_index1_hi}+1; +$config{btb}{btb_index3_lo} = $config{btb}{btb_index2_hi}+1; +$config{btb}{btb_addr_hi} = $config{btb}{btb_index1_hi}; + +# BHT index is a hash of the GHR and PC_HASH +sub ghrhash{ + my($btb_index_hi,$ghr_size) = @_; + + $btb_addr_width = $btb_index_hi - 3; + + $ghr_hi = $ghr_size - 1; + $ghr_lo = $btb_addr_width; + + $ghr_start = "{"; + if($ghr_size > $btb_addr_width){ + if($ghr_size-1 == $btb_addr_width){ + $string= "{ghr[$ghr_hi:$ghr_lo] ^ ghr[$ghr_hi+1],hashin[$config{btb}{btb_index1_hi}:4]^ghr[$ghr_lo-1:0]}"; + } + else{ + $string = "{ghr[$ghr_hi:$ghr_lo] ^ {ghr[$ghr_hi+1], {$ghr_size-1-$btb_addr_width\{1'b0} } },hashin[$config{btb}{btb_index1_hi}:4]^ghr[$ghr_lo-1:0]}"; + } + } + elsif($ghr_size < $btb_addr_width){ + $string = "{hashin[$ghr_size+3:4]^ghr[$ghr_size-1:0]^{ghr[$ghr_hi+1], {$ghr_hi\{1'b0} } }}"; + } + else{ $string = "{hashin[$config{btb}{btb_index1_hi}:4]^ghr[$ghr_lo-1:0]^{ghr[$ghr_hi+1], {$btb_addr_width-1\{1'b0} } } }"} + return $string; + +} + + +if($config{bht}{bht_size}==2048){ + $config{bht}{bht_ghr_size}= 9; + $config{bht}{bht_ghr_range}= "8:0"; + $config{bht}{bht_ghr_pad}= "fghr[8:4],3'b0"; + $config{bht}{bht_ghr_pad2}= "fghr[8:3],2'b0"; + $config{bht}{bht_array_depth}= 256; + $config{bht}{bht_addr_hi}= 11; +} elsif($config{bht}{bht_size}==1024){ + $config{bht}{bht_ghr_size}= 8; + $config{bht}{bht_ghr_range}= "7:0"; + $config{bht}{bht_ghr_pad}= "fghr[7:4],3'b0"; + $config{bht}{bht_ghr_pad2}= "fghr[7:3],2'b0"; + $config{bht}{bht_array_depth}= 128; + $config{bht}{bht_addr_hi}= 10; +} elsif($config{bht}{bht_size}==512){ + $config{bht}{bht_ghr_size}= 7; + $config{bht}{bht_ghr_range}= "6:0"; + $config{bht}{bht_ghr_pad}= "fghr[6:4],3'b0"; + $config{bht}{bht_ghr_pad2}= "fghr[6:3],2'b0"; + $config{bht}{bht_array_depth}= 64; + $config{bht}{bht_addr_hi}= 9; +} elsif($config{bht}{bht_size}==256){ + $config{bht}{bht_ghr_size}= 6; + $config{bht}{bht_ghr_range}= "5:0"; + $config{bht}{bht_ghr_pad}= "fghr[5:4],3'b0"; + $config{bht}{bht_ghr_pad2}= "fghr[5:3],2'b0"; + $config{bht}{bht_addr_hi} = 8; + $config{bht}{bht_array_depth}= 32; +} elsif($config{bht}{bht_size}==128){ + $config{bht}{bht_ghr_size}= 5; + $config{bht}{bht_ghr_range}= "4:0"; + $config{bht}{bht_ghr_pad}= "fghr[4],3'b0"; + $config{bht}{bht_ghr_pad2}= "fghr[4:3],2'b0"; + $config{bht}{bht_addr_hi} = 7; + $config{bht}{bht_array_depth}= 16; +} elsif($config{bht}{bht_size}==64){ + $config{bht}{bht_ghr_size}= 4; + $config{bht}{bht_ghr_range}= "3:0"; + $config{bht}{bht_ghr_pad}= "3'b0 "; + $config{bht}{bht_ghr_pad2}= "fghr[3],2'b0"; + $config{bht}{bht_addr_hi} = 6; + $config{bht}{bht_array_depth}= 8; +} elsif($config{bht}{bht_size}==32){ + $config{bht}{bht_ghr_size}= 3; + $config{bht}{bht_ghr_range}= "2:0"; + $config{bht}{bht_ghr_pad}= "2'b0 "; + $config{bht}{bht_ghr_pad2}= "2'b0"; + $config{bht}{bht_addr_hi} = 5; + $config{bht}{bht_array_depth}= 4; +} + +$config{bht}{bht_hash_string} = &ghrhash($config{btb}{btb_index1_hi}, $config{bht}{bht_ghr_size}-1); + +$config{pic}{pic_base_addr} = (hex($config{pic}{pic_region})<<28) + + (hex($config{pic}{pic_offset})); +$config{pic}{pic_base_addr} = sprintf("0x%x", $config{pic}{pic_base_addr}); + +$config{pic}{pic_int_words} = int($config{pic}{pic_total_int}/32 +0.9); +$config{pic}{pic_bits} = 10 + log2($config{pic}{pic_size}); + +$config{core}{lsu_num_nbload_width} = log2($config{core}{lsu_num_nbload}); + +$config{bus}{lsu_bus_tag} = log2($config{core}{lsu_num_nbload}) + 1; + +$config{dccm}{dccm_sadr} = (hex($config{dccm}{dccm_region})<<28) + + (hex($config{dccm}{dccm_offset})); +$config{dccm}{dccm_sadr} = sprintf("0x%x", $config{dccm}{dccm_sadr}); + +$config{dccm}{dccm_eadr} = (hex($config{dccm}{dccm_region})<<28) + + (hex($config{dccm}{dccm_offset})) + size($config{dccm}{dccm_size})-1; +$config{dccm}{dccm_eadr} = sprintf("0x%x", $config{dccm}{dccm_eadr}); + +$config{dccm}{dccm_reserved} = sprintf("0x%x", ($config{dccm}{dccm_size}>30)? 4096 : ($config{dccm}{dccm_size}*1024)/4); + +$config{dccm}{dccm_bits} = ($config{dccm}{dccm_size}==48 ) ? 16 : 10 + log2($config{dccm}{dccm_size}); + +$config{dccm}{dccm_bank_bits} = log2($config{dccm}{dccm_num_banks}); +$config{dccm}{dccm_data_width} = 32; +$config{dccm}{dccm_fdata_width} = $config{dccm}{dccm_data_width} + log2($config{dccm}{dccm_data_width}) + 2; +$config{dccm}{dccm_byte_width} = $config{dccm}{dccm_data_width}/8; + +$config{dccm}{dccm_width_bits} = log2($config{dccm}{dccm_byte_width}); +$config{dccm}{dccm_index_bits} = $config{dccm}{dccm_bits} - $config{dccm}{dccm_bank_bits} - $config{dccm}{dccm_width_bits}; + +$config{dccm}{dccm_ecc_width} = log2($config{dccm}{dccm_data_width}) + 2; +$config{dccm}{lsu_sb_bits} = (($config{dccm}{dccm_bits}) > ($config{pic}{pic_bits})) ? ($config{dccm}{dccm_bits}) : ($config{pic}{pic_bits}); +$config{dccm}{dccm_rows} = ($config{dccm}{dccm_size}==48 ) ? (2**($config{dccm}{dccm_index_bits}-1) + 2**$config{dccm}{dccm_index_bits})/2 : 2**$config{dccm}{dccm_index_bits}; +$config{dccm}{dccm_data_cell} = "ram_$config{dccm}{dccm_rows}x39"; + + +$config{icache}{icache_tag_high} = (($config{icache}{icache_size}==256) ? 16 : + ($config{icache}{icache_size}==128) ? 15 : + ($config{icache}{icache_size}==64) ? 14 : + ($config{icache}{icache_size}==32) ? 13 : 12); + +$config{icache}{icache_tag_depth} = (($config{icache}{icache_size}==256) ? 1024 : + ($config{icache}{icache_size}==128) ? 512 : + ($config{icache}{icache_size}==64) ? 256 : + ($config{icache}{icache_size}==32) ? 128 : 64); + + +$config{icache}{icache_ic_depth} = log2($config{icache}{icache_size}) + 4; +$config{icache}{icache_ic_index} = log2($config{icache}{icache_size}) + 4; +$config{icache}{icache_ic_rows} = 2**$config{icache}{icache_ic_depth}; + + +$config{icache}{icache_taddr_high} = log2($config{icache}{icache_tag_depth}) - 1; + +if (defined($config{icache}{icache_ecc})) { +$config{icache}{icache_data_cell} = "ram_$config{icache}{icache_ic_rows}x42"; +$config{icache}{icache_tag_cell} = "ram_$config{icache}{icache_tag_depth}x25"; + +} +else { +$config{icache}{icache_data_cell} = "ram_$config{icache}{icache_ic_rows}x34"; +$config{icache}{icache_tag_cell} = "ram_$config{icache}{icache_tag_depth}x21"; +} +$config{pic}{pic_total_int_plus1} = $config{pic}{pic_total_int} + 1; +# Defines with explicit values in the macro name +$config{dccm}{"dccm_num_banks_$config{dccm}{dccm_num_banks}"} = ""; +$config{dccm}{"dccm_size_$config{dccm}{dccm_size}"} = ""; + +# If ICCM offset not explicitly provided, align to TOP of the region +if ($top_align_iccm && ($config{iccm}{iccm_offset} eq $iccm_offset) && ($config{iccm}{iccm_size} < 32)) { + $config{iccm}{iccm_region} = "0xa"; + print "$self: Setting default iccm region to region $config{iccm}{iccm_region}\n"; + $config{iccm}{iccm_offset} = sprintf("0x%08x",256*1024*1024-size($config{iccm}{iccm_size})); + print "$self: Aligning default iccm offset to top of region @ $config{iccm}{iccm_offset}\n"; +} +$config{iccm}{iccm_sadr} = (hex($config{iccm}{iccm_region})<<28) + + (hex($config{iccm}{iccm_offset})); +$config{iccm}{iccm_sadr} = sprintf("0x%08x", $config{iccm}{iccm_sadr}); + +$config{iccm}{iccm_eadr} = (hex($config{iccm}{iccm_region})<<28) + + (hex($config{iccm}{iccm_offset})) + size($config{iccm}{iccm_size})-1; +$config{iccm}{iccm_eadr} = sprintf("0x%08x", $config{iccm}{iccm_eadr}); + +$config{iccm}{iccm_reserved} = sprintf("0x%x", ($config{iccm}{iccm_size}>30)? 4096 : ($config{iccm}{iccm_size}*1024)/4); + +$config{iccm}{iccm_bits} = 10 + log2($config{iccm}{iccm_size}); +$config{iccm}{iccm_bank_bits} = log2($config{iccm}{iccm_num_banks}); //-1; +$config{iccm}{iccm_index_bits} = $config{iccm}{iccm_bits} - $config{iccm}{iccm_bank_bits} - 2; # always 4 bytes +$config{iccm}{iccm_rows} = 2**$config{iccm}{iccm_index_bits}; +$config{iccm}{iccm_data_cell} = "ram_$config{iccm}{iccm_rows}x39"; +# Defines with explicit values in the macro name +$config{iccm}{"iccm_num_banks_$config{iccm}{iccm_num_banks}"} = ""; +$config{iccm}{"iccm_size_$config{iccm}{iccm_size}"} = ""; + +delete $config{core}{fpga_optimize} if ($config{core}{fpga_optimize} == 0); + +# Track used regions + +$regions_used{hex($config{iccm}{iccm_region})} = 1; +$regions_used{hex($config{dccm}{dccm_region})} = 1; +$regions_used{hex($config{pic}{pic_region})} = 1; +$regions_used{hex($config{reset_vec})>>28} = 1; + +# Find an unused region for serial IO +for (my $rgn = 15;$rgn >= 0; $rgn--) { + if (($rgn != hex($config{iccm}{iccm_region})) && + ($rgn != hex($config{dccm}{dccm_region})) && + ($rgn != (hex($config{pic}{pic_region})))) { + $config{memmap}{serialio} = ($rgn << 28) + (22<<18); + $regions_used{$rgn} = 1; + last; + } +} + +$config{memmap}{serialio} = sprintf("0x%08x", $config{memmap}{serialio}); + +# Find an unused region for external data +for (my $rgn = 15;$rgn >= 0; $rgn--) { + if (($rgn != hex($config{iccm}{iccm_region})) && + ($rgn != hex($config{dccm}{dccm_region})) && + ($rgn != (hex($config{memmap}{serialio})>>28)) && + ($rgn != (hex($config{pic}{pic_region})))) { + $config{memmap}{external_data} = ($rgn << 28) + (22<<18); + $regions_used{$rgn} = 1; + last; + } +} +$config{memmap}{external_data} = sprintf("0x%08x", $config{memmap}{external_data}); +# +# Find an unused region for external prog +for (my $rgn = 15;$rgn >= 0; $rgn--) { + if (($rgn != hex($config{iccm}{iccm_region})) && + ($rgn != hex($config{dccm}{dccm_region})) && + ($rgn != (hex($config{memmap}{serialio})>>28)) && + ($rgn != (hex($config{memmap}{external_data})>>28)) && + ($rgn != (hex($config{pic}{pic_region})))) { + $config{memmap}{external_prog} = ($rgn << 28); + $regions_used{$rgn} = 1; + last; + } +} +$config{memmap}{external_prog} = sprintf("0x%08x", $config{memmap}{external_prog}); + +# Unused region for second data +for (my $rgn = 15;$rgn >= 0; $rgn--) { + if (($rgn != hex($config{iccm}{iccm_region})) && + ($rgn != hex($config{dccm}{dccm_region})) && + ($rgn != (hex($config{memmap}{serialio})>>28)) && + ($rgn != (hex($config{memmap}{external_data})>>28)) && + ($rgn != (hex($config{memmap}{external_prog})>>28) && + ($rgn != (hex($config{pic}{pic_region}))) + )) { + $config{memmap}{external_data_1} = ($rgn << 28); + $regions_used{$rgn} = 1; + last; + } +} +$config{memmap}{external_data_1} = sprintf("0x%08x", $config{memmap}{data_1}); + + +#$config{memmap}{consoleio} = hex($config{memmap}{serialio}) + 0x100; +#$config{memmap}{consoleio} = sprintf("0x%x", $config{memmap}{consoleio}); + +# Find an unused region for debug_sb_memory data +for (my $rgn = 15;$rgn >= 0; $rgn--) { + if (($rgn != hex($config{iccm}{iccm_region})) && + ($rgn != hex($config{dccm}{dccm_region})) && + ($rgn != (hex($config{memmap}{serialio})>>28)) && + ($rgn != (hex($config{memmap}{external_data})>>28)) && + ($rgn != (hex($config{memmap}{external_data_1})>>28)) && + ($rgn != (hex($config{pic}{pic_region})))) { + $config{memmap}{debug_sb_mem} = ($rgn << 28) + (22<<18); + $regions_used{$rgn} = 1; + last; + } +} +$config{memmap}{debug_sb_mem} = sprintf("0x%08x", $config{memmap}{debug_sb_mem}); + + +# Create the memory map hole for random testing +# Only do this if masks are not enabled already +if (hex($config{protection}{data_access_enable0}) > 0 || + hex($config{protection}{data_access_enable1}) > 0 || + hex($config{protection}{data_access_enable2}) > 0 || + hex($config{protection}{data_access_enable3}) > 0 || + hex($config{protection}{data_access_enable4}) > 0 || + hex($config{protection}{data_access_enable5}) > 0 || + hex($config{protection}{data_access_enable6}) > 0 || + hex($config{protection}{data_access_enable7}) > 0 || + hex($config{protection}{inst_access_enable0}) > 0 || + hex($config{protection}{inst_access_enable1}) > 0 || + hex($config{protection}{inst_access_enable2}) > 0 || + hex($config{protection}{inst_access_enable3}) > 0 || + hex($config{protection}{inst_access_enable4}) > 0 || + hex($config{protection}{inst_access_enable5}) > 0 || + hex($config{protection}{inst_access_enable6}) > 0 || + hex($config{protection}{inst_access_enable7}) > 0 || + $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 + +foreach my $unr (reverse(0 .. 15)) { + if (!defined($regions_used{$unr})) { + $config{memmap}{"unused_region$unr"} = sprintf("0x%08x",($unr << 28)); + $regions_used{$unr} = 1; + } +} + +if ($target eq "baseline") { + $config{reset_vec} = $config{iccm}{iccm_sadr}; + $config{testbench}{magellan} = 1; + print "$self: Setting reset_vec = ICCM start address for Baseline\n"; +} + + +# Output bit-width specifiers for these variables +our %widths = ( + "dccm_region" => "4", + "dccm_offset" => "28", + "dccm_sadr" => "32", + "dccm_eadr" => "32", + "pic_region" => "4", + "pic_offset" => "10", + "pic_base_addr" => "32", + "iccm_region" => "4", + "iccm_offset" => "10", + "iccm_sadr" => "32", + "iccm_eadr" => "32", + "bus_prty_default" => "2", + "inst_access_enable0" => "1", + "inst_access_enable1" => "1", + "inst_access_enable2" => "1", + "inst_access_enable3" => "1", + "inst_access_enable4" => "1", + "inst_access_enable5" => "1", + "inst_access_enable6" => "1", + "inst_access_enable7" => "1", + "data_access_enable0" => "1", + "data_access_enable1" => "1", + "data_access_enable2" => "1", + "data_access_enable3" => "1", + "data_access_enable4" => "1", + "data_access_enable5" => "1", + "data_access_enable6" => "1", + "data_access_enable7" => "1", +); +#}}} + + +#-----------------------Reset Vector MPU check-----------------------# +$flag_pass=0; +if(!(hex($config{reset_vec}) >= ((hex($config{iccm}{iccm_region})<<28) + (hex($config{iccm}{iccm_offset}))) && (hex($config{reset_vec}) < ((hex($config{iccm}{iccm_region})<<28) + (hex($config{iccm}{iccm_offset})) + size($config{iccm}{iccm_size})-1)))) +{ + for(my $i=0; $i<8; $i++) + { + $inst_access_enable = "inst_access_enable$i"; + $inst_access_addr = "inst_access_addr$i"; + $inst_access_mask = "inst_access_mask$i"; + if(hex($config{protection}{$inst_access_enable})) + { + if((hex($config{reset_vec})>= hex($config{protection}{$inst_access_addr})) && (hex($config{reset_vec})< (hex($config{protection}{$inst_access_addr}) | hex($config{protection}{$inst_access_mask})))) + { + $flag_pass++; + last; + } + } + else {$enable_check++;} + } + +if($flag_pass == 0 & $enable_check < 8) { die("$helpusage\n\nFAIL: RESET_VECTOR not in any of MPU enabled instruction access windows or ICCM !!!\n\n");} +} +#-----------------------Reset Vector MPU check-----------------------# + +#print Dumper(\%config); +#print Dumper(\%width); + +#print Dumper(\%sets); +#print Dumper(\%unsets); + +# Sanity checks +check_addr_align("dccm", hex($config{dccm}{dccm_sadr}), $config{dccm}{dccm_size}*1024); +check_addr_align("iccm", hex($config{iccm}{iccm_sadr}), $config{iccm}{iccm_size}*1024); +check_addr_align("pic", hex($config{pic}{pic_base_addr}), $config{pic}{pic_size}*1024); + +# Prevent overlap of internal memories +if ((hex($config{pic}{pic_region}) == hex($config{iccm}{iccm_region})) && (hex($config{pic}{pic_offset}) == hex($config{iccm}{iccm_offset}))) { + die "$self: ERROR! PIC and ICCM blocks collide (region $config{iccm}{iccm_region}, offset $config{pic}{pic_offset})!\n"; +} +if ((hex($config{pic}{pic_region}) == hex($config{dccm}{dccm_region})) && (hex($config{pic}{pic_offset}) == hex($config{dccm}{dccm_offset}))) { + die "$self: ERROR! PIC and DCCM blocks collide (region $config{dccm}{dccm_region}, offset $config{pic}{pic_offset})!\n"; +} +if ((hex($config{iccm}{iccm_region}) == hex($config{dccm}{dccm_region})) && (hex($config{iccm}{iccm_offset}) == hex($config{dccm}{dccm_offset}))) { + die "$self: ERROR! ICCM and DCCM blocks collide (region $config{iccm}{iccm_region}, offset $config{dccm}{dccm_offset})!\n"; +} + +##################### Add dumper routines here ########################## +# +# Dump Verilog $RV_ROOT/configs/common_defines.vh +print "$self: Writing $vlogfile\n"; +open (FILE, ">$vlogfile") || die "Cannot open $vlogfile for writing $!\n"; +print_header("//"); +gen_define("","`", \%config, \@verilog_vars); +close FILE; + +print "$self: Writing $asmfile\n"; +open (FILE, ">$asmfile") || die "Cannot open $asmfile for writing $!\n"; +# Dump ASM/C $RV_ROOT/diags/env/defines.h +print_header("//"); +gen_define("","#", \%config, \@asm_vars, \@asm_overridable); +close FILE; + +# add `define PHYSICAL 1 +# remove `undef RV_ICCM_ENABLE + +my $pddata=' +`include "common_defines.vh" +`undef ASSERT_ON +`undef TEC_RV_ICG +`define TEC_RV_ICG CKLNQD12BWP35P140 +`define PHYSICAL 1 +'; + + +print "$self: Writing $pdfile\n"; +open (FILE, ">$pdfile") || die "Cannot open $pdfile for writing $!\n"; +# Dump PD $RV_ROOT/$RV_ROOT/configs/pd_defines.vh +print_header("//"); +printf (FILE "$pddata"); +close FILE; + +print "$self: Writing $whisperfile\n"; +dump_whisper_config(\%config, $whisperfile); + + +# change this to use config version +#`$ENV{RV_ROOT}/tools/picmap -t $config{pic}{pic_total_int} > $ENV{RV_ROOT}/design/include/pic_map_auto.h`; +`$ENV{RV_ROOT}/tools/picmap -t $config{pic}{pic_total_int} > $build_path/pic_map_auto.h`; +#`$ENV{RV_ROOT}/tools/unrollforverilator $config{pic}{pic_total_int_plus1} > $ENV{RV_ROOT}/design/include/pic_ctrl_verilator_unroll.sv`; +`$ENV{RV_ROOT}/tools/unrollforverilator $config{pic}{pic_total_int_plus1} > $build_path/pic_ctrl_verilator_unroll.sv`; + +# Perl vars for use by scripts +print "$self: Writing $perlfile\n"; +open (FILE, ">$perlfile") || die "Cannot open $perlfile for writing $!\n"; +print_header("# "); +print FILE "# To use this in a perf script, use 'require \$RV_ROOT/configs/config.pl'\n"; +print FILE "# Reference the hash via \$config{name}..\n\n\n"; +print FILE Data::Dumper->Dump([\%config], [ qw(*config) ]); +print FILE "1;\n"; +close FILE; + +# 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 @printvars = @{@_[1]}; + my @overridable = @{@_[2]}; + my $re = join("|",@printvars); + $re = qr/($re)/; + #print Dumper($hash); + foreach my $key (keys %$hash) { + next if $key eq "csr"; + #print "looking at $key:$matched ($re)\n"; + if (defined($unsets{$key})) { + print "$self:unsetting $key\n"; + delete($config{$key}); + next + } + if (defined($sets{$key}) && $sets{$key} ne $$hash{$key}) { + if (($$hash{$key} =~ /derived/i) && ($$hash{$key} !~ /overridable/i)) { + die ("$self: ERROR! $key is a derived and non-overridable parameter!\n"); + } else { + print "$self: Overriding $key value $$hash{$key} with $sets{$key}\n"; + $$hash{$key} = $sets{$key}; + } + } + my $value = $$hash{$key}; + if (ref($value) eq "HASH") { + if ($key =~ /$re/) { + $matched = 1; + } + gen_define($matched,$prefix, $value, \@printvars, \@overridable); + $matched = 0; + } elsif (ref($value) eq "ARRAY") { + # print "$key : @{$value}\n"; + $matched = 0; + } else { + if ($matched eq "1" || $key =~ /$re/) { + if($value =~ /derive\(.*\)/o) { + $value = eval($value); + } + $override = grep(/^$key$/, @overridable); + print_define($prefix, $key, $value, $override); + } + } + } +}#}}} + +sub dump_define {#{{{ + my $matched = shift; + my $prefix = shift; + my $hash = @_[0]; + my @printvars = @{@_[1]}; + my @overridable = @{@_[2]}; + my $re = join("|",@printvars); + $re = qr/($re)/; + #print Dumper($hash); + foreach my $key (keys %$hash) { + next if $key eq "csr"; + next unless $matched || grep(/^$key$/,@dvars); + #print "looking at $key:$matched ($re)\n"; + if (defined($unsets{$key})) { + print "$self:unsetting $key\n"; + delete($config{$key}); + next + } + if (defined($sets{$key}) && $sets{$key} ne $$hash{$key}) { + if (($$hash{$key} =~ /derived/i) && ($$hash{$key} !~ /overridable/i)) { + die ("$self: ERROR! $key is a derived and non-overridable parameter!\n"); + } else { + print "$self: Overriding $key value $$hash{$key} with $sets{$key}\n"; + $$hash{$key} = $sets{$key}; + } + } + my $value = $$hash{$key}; + if (ref($value) eq "HASH") { + if ($key =~ /$re/) { + $matched = 1; + } + dump_define($matched,$prefix, $value, \@printvars, \@overridable); + $matched = 0; + } elsif (ref($value) eq "ARRAY") { + # print "$key : @{$value}\n"; + $matched = 0; + } else { + if ($matched eq "1" || $key =~ /$re/) { + if($value =~ /derive\(.*\)/o) { + $value = eval($value); + } + printf ("swerv: %-30s = $value\n",$key) if ($value !~ /derived/); + } + } + } +}#}}} + +# Perform cmd line set/unset ############################################{{{ +sub map_set_unset { + if (scalar(@sets)) { + print "$self: Set(s) requested : @sets\n"; + foreach (@sets) { + my ($key,$value) = m/(\w+)=*(\w+)*/o; + $value = 1 if (!defined($value)); + $sets{$key} = $value; + } + } + if (scalar(@unsets)) { + print "$self: Unset(s) requested : @sets\n"; + foreach (@unsets) { + $unsets{$_} = 1; + } + } +} #}}} +#}}} + + +# If arg looks like a hexadecimal string, then convert it to decimal.#{{{ +# Otherwise, return arg. +sub decimal { + my ($x) = @_; + return hex($x) if $x =~ /^0x/o; + return $x; +}#}}} + +# Collect memory protection specs (array of address pairs) in the given +# resutls array. Tag is either "data" or "inst". +sub collect_mem_protection { + my ($tag, $config, $results) = @_; + return unless exists $config{protection}; + + my $prot = $config{protection}; + + my $enable_tag = $tag . "_access_enable"; + my $addr_tag = $tag . "_access_addr"; + my $mask_tag = $tag . "_access_mask"; + + foreach my $key (keys %{$prot}) { + next unless $key =~ /^$enable_tag(\d+)$/; + my $ix = $1; + + my $enable = $prot->{$key}; + if ($enable !~ /[01]$/) { + warn("Invalid value for protection entry $key: $enable\n"); + next; + } + + next unless ($enable eq "1" or $enable eq "1'b1"); + + if (! exists $prot->{"$addr_tag$ix"}) { + warn("Missing $addr_tag$ix\n"); + next; + } + + if (! exists $prot->{"$mask_tag$ix"}) { + warn("Missing $mask_tag$ix\n"); + next; + } + + my $addr = $prot->{"$addr_tag$ix"}; + my $mask = $prot->{"$mask_tag$ix"}; + + if ($addr !~ /^0x[0-9a-fA-F]+$/) { + warn("Invalid $addr_tag$ix: $addr\n"); + next; + } + + if ($mask !~ /^0x[0-9a-fA-F]+$/) { + warn("Invalid $mask_tag$ix: $mask\n"); + next; + } + + if ((hex($addr) & hex($mask)) != 0) { + warn("Protection mask bits overlap address bits in mask $mask and addr $addr\n"); + } + + if ($mask !~ /^0x0*[137]?f*$/) { + warn("Protection $tag mask ($mask) must have all its one bits to the right of its zero bits\n"); + next; + } + + my $start = hex($addr) & ~hex($mask) & 0xffffffff; + my $end = (hex($addr) | hex($mask)) & 0xffffffff; + + $start = sprintf("0x%08x", $start); + $end = sprintf("0x%08x", $end); + + push(@{$results}, [ $start, $end ]); + } +} + +# Collect memory protection specs (array of address pairs) in the given +# resutls array. Tag is either "data" or "inst". +sub collect_mem_protection { + my ($tag, $config, $results) = @_; + return unless exists $config{protection}; + + my $prot = $config{protection}; + + my $enable_tag = $tag . "_access_enable"; + my $addr_tag = $tag . "_access_addr"; + my $mask_tag = $tag . "_access_mask"; + + foreach my $key (keys %{$prot}) { + next unless $key =~ /^$enable_tag(\d+)$/; + my $ix = $1; + + my $enable = $prot->{$key}; + if ($enable !~ /[01]$/) { + warn("Invalid value for protection entry $key: $enable\n"); + next; + } + + next unless ($enable eq "1" or $enable eq "1'b1"); + + if (! exists $prot->{"$addr_tag$ix"}) { + warn("Missing $addr_tag$ix\n"); + next; + } + + if (! exists $prot->{"$mask_tag$ix"}) { + warn("Missing $mask_tag$ix\n"); + next; + } + + my $addr = $prot->{"$addr_tag$ix"}; + my $mask = $prot->{"$mask_tag$ix"}; + + if ($addr !~ /^0x[0-9a-fA-F]+$/) { + warn("Invalid $addr_tag$ix: $addr\n"); + next; + } + + if ($mask !~ /^0x[0-9a-fA-F]+$/) { + warn("Invalid $mask_tag$ix: $mask\n"); + next; + } + + if ((hex($addr) & hex($mask)) != 0) { + warn("Protection mask bits overlap address bits in mask $mask and addr $addr\n"); + } + + if ($mask !~ /^0x0*[137]?f*$/) { + warn("Protection mask ($mask) must have all its one bits to the right of its zero bits\n"); + next; + } + + my $start = hex($addr) & ~hex($mask) & 0xffffffff; + my $end = (hex($addr) | hex($mask)) & 0xffffffff; + + $start = sprintf("0x%08x", $start); + $end = sprintf("0x%08x", $end); + + push(@{$results}, [ $start, $end ]); + } +} + +# 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 exists $config{dccm}{dccm_enable}) { + $jh{dccm}{region} = $config{dccm}{dccm_region}; + $jh{dccm}{size} = 1024*decimal($config{dccm}{dccm_size}); # From 1k to bytes + $jh{dccm}{offset} = $config{dccm}{dccm_offset}; + + $jh{dccm}{size} = sprintf("0x%x", $jh{dccm}{size}); + } + + # Collect icccm configs. + if (exists $config{iccm} and exists $config{iccm}{iccm_enable}) { + $jh{iccm}{region} = $config{iccm}{iccm_region}; + $jh{iccm}{size} = 1024*decimal($config{iccm}{iccm_size}); # From 1k to bytes + $jh{iccm}{offset} = $config{iccm}{iccm_offset}; + + $jh{iccm}{size} = sprintf("0x%x", $jh{iccm}{size}); + } + + # Collect CSRs + + $jh{csr} = $config{csr} if exists $config{csr}; + + # Collect pic configs. + if (exists $config{pic}) { + my %mem_mapped; + collect_mem_mapped_regs($config{pic}, \%mem_mapped); + $jh{'memory_mapped_registers'} = \%mem_mapped; + + # This is now deprecated. To be removed soon. + while (my ($k, $v) = each %{$config{pic}}) { + next if $k eq 'pic_base_addr'; # derived from region and offset + if ($k eq 'pic_size') { + $v *= 1024; # from kbytes to bytes + $v = sprintf("0x%x", $v); + } + $k =~ s/^pic_//o; + $v += 0 if $v =~ /^\d+$/o; + $jh{pic}{$k} = $v; + } + } + + # Collect triggers. + $jh{triggers} = $config{triggers} if exists $config{triggers}; + + # Dump JSON config file. + my $json = JSON->new->allow_nonref; + my $text = $json->pretty->encode(\%jh); + print($fh $text); + + close $fh; +}#}}} + + +# Checker for iccm/dccm/pic sub-region address alignment. Address must be a multiple +# of size or next higher power of 2 if size is not a power of 2. +sub check_addr_align { + my ($section, $addr, $size) = @_; + + die("Invalid $section size: $size\n") if $size <= 0; + + my $log_size = log2($size); + my $p2 = 1 << $log_size; + $size = 2*$p2 if $size != $p2; + + if (($addr % $size) != 0) { + printf("Address of $section area(0x%x) is not a multiple of its size (0x%x)\n", + $addr, $size); + exit(1); + } +} + + +sub log2 { + my ($n) = @_; + return log($n)/log(2); +} + +sub gen_default_linker_script {#{{{ + + open (FILE, ">$linkerfile") || die "Cannot open $linkerfile for writing $!"; + 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}) { + 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 < 8'h5 && WriteData[7:0] < 8'h7f; + + parameter MAX_CYCLES = 10_000_000; + + integer fd, tp, el; + + always @(negedge core_clk) begin + cycleCnt <= cycleCnt+1; + // Test timeout monitor + if(cycleCnt == MAX_CYCLES) begin + $display ("Hit max cycle count (%0d) .. stopping",cycleCnt); + $finish; + end + // cansol Monitor + if( mailbox_data_val & mailbox_write) begin + $fwrite(fd,"%c", WriteData[7:0]); + $write("%c", WriteData[7:0]); + end + // End Of test monitor + if(mailbox_write && WriteData[7:0] == 8'hff) begin + $display("\nFinished : minstret = %0d, mcycle = %0d", `DEC.tlu.minstretl[31:0],`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[1:0] <= '{`DEC.dec_i1_wen_wb, `DEC.dec_i0_wen_wb}; + wb_dest[1:0] <= '{`DEC.dec_i1_waddr_wb, `DEC.dec_i0_waddr_wb}; + wb_data[1:0] <= '{`DEC.dec_i1_wdata_wb, `DEC.dec_i0_wdata_wb}; + if (trace_rv_i_valid_ip !== 0) begin + $fwrite(tp,"%b,%h,%h,%0h,%0h,3,%b,%h,%h,%b\n", trace_rv_i_valid_ip, trace_rv_i_address_ip[63:32], trace_rv_i_address_ip[31:0], + trace_rv_i_insn_ip[63:32], trace_rv_i_insn_ip[31:0],trace_rv_i_exception_ip,trace_rv_i_ecause_ip, + trace_rv_i_tval_ip,trace_rv_i_interrupt_ip); + // Basic trace - no exception register updates + // #1 0 ee000000 b0201073 c 0b02 00000000 + for (int i=0; i<2; i++) + if (trace_rv_i_valid_ip[i]==1) begin + commit_count++; + $fwrite (el, "%10d : %8s %0d %h %h%13s ; %s\n",cycleCnt, $sformatf("#%0d",commit_count), 0, + trace_rv_i_address_ip[31+i*32 -:32], trace_rv_i_insn_ip[31+i*32-:32], + (wb_dest[i] !=0 && wb_valid[i]) ? $sformatf("%s=%h", abi_reg[wb_dest[i]], wb_data[i]) : " ", + dasm(trace_rv_i_insn_ip[31+i*32 -:32], trace_rv_i_address_ip[31+i*32-:32], wb_dest[i] & {5{wb_valid[i]}}, wb_data[i]) + ); + end + end + if(`DEC.dec_nonblock_load_wen) begin + $fwrite (el, "%10d : %10d%22s=%h ; nbL\n", cycleCnt, 0, abi_reg[`DEC.dec_nonblock_load_waddr], `DEC.lsu_nonblock_load_data); + tb_top.gpr[0][`DEC.dec_nonblock_load_waddr] = `DEC.lsu_nonblock_load_data; + 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"; + // tie offs + jtag_id[31:28] = 4'b1; + jtag_id[27:12] = '0; + jtag_id[11:1] = 11'h45; + reset_vector = 32'h0; + nmi_vector = 32'hee000000; + nmi_int = 0; + + $readmemh("program.hex", lmem.mem); + $readmemh("program.hex", imem.mem); + tp = $fopen("trace_port.csv","w"); + el = $fopen("exec.log","w"); + $fwrite (el, "// Cycle : #inst hart pc opcode reg=value ; mnemonic\n"); + $fwrite (el, "//---------------------------------------------------------------\n"); + fd = $fopen("console.log","w"); + commit_count = 0; + preload_dccm(); + preload_iccm(); + +`ifndef VERILATOR + if($test$plusargs("dumpon")) $dumpvars; + forever core_clk = #5 ~core_clk; +`endif + end + + + assign rst_l = cycleCnt > 5; + assign porst_l = cycleCnt >2; + + //=========================================================================- + // RTL instance + //=========================================================================- +swerv_wrapper rvtop ( + .rst_l ( rst_l ), + .dbg_rst_l ( porst_l ), + .clk ( core_clk ), + .rst_vec ( reset_vector[31:1]), + .nmi_int ( nmi_int ), + .nmi_vec ( nmi_vector[31:1]), + .jtag_id ( jtag_id[31:1]), + +`ifdef RV_BUILD_AHB_LITE + .haddr ( ic_haddr ), + .hburst ( ic_hburst ), + .hmastlock ( ic_hmastlock ), + .hprot ( ic_hprot ), + .hsize ( ic_hsize ), + .htrans ( ic_htrans ), + .hwrite ( ic_hwrite ), + + .hrdata ( ic_hrdata[63:0]), + .hready ( ic_hready ), + .hresp ( ic_hresp ), + + //--------------------------------------------------------------- + // Debug AHB Master + //--------------------------------------------------------------- + .sb_haddr ( sb_haddr ), + .sb_hburst ( sb_hburst ), + .sb_hmastlock ( sb_hmastlock ), + .sb_hprot ( sb_hprot ), + .sb_hsize ( sb_hsize ), + .sb_htrans ( sb_htrans ), + .sb_hwrite ( sb_hwrite ), + .sb_hwdata ( sb_hwdata ), + + .sb_hrdata ( sb_hrdata ), + .sb_hready ( sb_hready ), + .sb_hresp ( sb_hresp ), + + //--------------------------------------------------------------- + // LSU AHB Master + //--------------------------------------------------------------- + .lsu_haddr ( lsu_haddr ), + .lsu_hburst ( lsu_hburst ), + .lsu_hmastlock ( lsu_hmastlock ), + .lsu_hprot ( lsu_hprot ), + .lsu_hsize ( lsu_hsize ), + .lsu_htrans ( lsu_htrans ), + .lsu_hwrite ( lsu_hwrite ), + .lsu_hwdata ( lsu_hwdata ), + + .lsu_hrdata ( lsu_hrdata[63:0]), + .lsu_hready ( lsu_hready ), + .lsu_hresp ( lsu_hresp ), + + //--------------------------------------------------------------- + // DMA Slave + //--------------------------------------------------------------- + .dma_haddr ( '0 ), + .dma_hburst ( '0 ), + .dma_hmastlock ( '0 ), + .dma_hprot ( '0 ), + .dma_hsize ( '0 ), + .dma_htrans ( '0 ), + .dma_hwrite ( '0 ), + .dma_hwdata ( '0 ), + + .dma_hrdata ( dma_hrdata ), + .dma_hresp ( dma_hresp ), + .dma_hsel ( 1'b1 ), + .dma_hreadyin ( dma_hready_out ), + .dma_hreadyout ( dma_hready_out ), +`endif +`ifdef RV_BUILD_AXI4 + //-------------------------- 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), +`endif + .timer_int ( 1'b0 ), + .extintsrc_req ( '0 ), + + .lsu_bus_clk_en ( 1'b1 ), + .ifu_bus_clk_en ( 1'b1 ), + .dbg_bus_clk_en ( 1'b1 ), + .dma_bus_clk_en ( 1'b1 ), + + .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 ( 1'b0 ), + .jtag_tms ( 1'b0 ), + .jtag_tdi ( 1'b0 ), + .jtag_trst_n ( 1'b0 ), + .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), + .debug_brkpt_status (debug_brkpt_status), + + .i_cpu_halt_req ( 1'b0 ), + .o_cpu_halt_ack ( o_cpu_halt_ack ), + .o_cpu_halt_status ( o_cpu_halt_status ), + .i_cpu_run_req ( 1'b0 ), + .o_debug_mode_status (o_debug_mode_status), + .o_cpu_run_ack ( o_cpu_run_ack ), + + .dec_tlu_perfcnt0 (dec_tlu_perfcnt0), + .dec_tlu_perfcnt1 (dec_tlu_perfcnt1), + .dec_tlu_perfcnt2 (dec_tlu_perfcnt2), + .dec_tlu_perfcnt3 (dec_tlu_perfcnt3), + + .scan_mode ( 1'b0 ), + .mbist_mode ( 1'b0 ) + +); + + + //=========================================================================- + // AHB I$ instance + //=========================================================================- +`ifdef RV_BUILD_AHB_LITE + +ahb_sif imem ( + // Inputs + .HWDATA(64'h0), + .HCLK(core_clk), + .HSEL(1'b1), + .HPROT(ic_hprot), + .HWRITE(ic_hwrite), + .HTRANS(ic_htrans), + .HSIZE(ic_hsize), + .HREADY(ic_hready), + .HRESETn(rst_l), + .HADDR(ic_haddr), + .HBURST(ic_hburst), + + // Outputs + .HREADYOUT(ic_hready), + .HRESP(ic_hresp), + .HRDATA(ic_hrdata[63:0]) +); + + +ahb_sif lmem ( + // Inputs + .HWDATA(lsu_hwdata), + .HCLK(core_clk), + .HSEL(1'b1), + .HPROT(lsu_hprot), + .HWRITE(lsu_hwrite), + .HTRANS(lsu_htrans), + .HSIZE(lsu_hsize), + .HREADY(lsu_hready), + .HRESETn(rst_l), + .HADDR(lsu_haddr), + .HBURST(lsu_hburst), + + // Outputs + .HREADYOUT(lsu_hready), + .HRESP(lsu_hresp), + .HRDATA(lsu_hrdata[63:0]) +); + +`endif +`ifdef RV_BUILD_AXI4 +axi_slv #(.TAGW(`RV_IFU_BUS_TAG)) imem( + .aclk(core_clk), + .rst_l(rst_l), + .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(core_clk), + .rst_l(rst_l), + .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(core_clk), + .reset_l(rst_l), + + .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) + +); + +`endif + +task preload_iccm; +bit[31:0] data; +bit[31:0] addr, eaddr, saddr; + +/* +addresses: + 0xfffffff0 - ICCM start address to load + 0xfffffff4 - ICCM end address to load +*/ + +addr = 'hffff_fff0; +saddr = {lmem.mem[addr+3],lmem.mem[addr+2],lmem.mem[addr+1],lmem.mem[addr]}; +if ( (saddr < `RV_ICCM_SADR) || (saddr > `RV_ICCM_EADR)) return; +`ifndef RV_ICCM_ENABLE + $display("********************************************************"); + $display("ICCM preload: there is no ICCM in SweRV, terminating !!!"); + $display("********************************************************"); + $finish; +`endif +addr += 4; +eaddr = {lmem.mem[addr+3],lmem.mem[addr+2],lmem.mem[addr+1],lmem.mem[addr]}; +$display("ICCM pre-load from %h to %h", saddr, eaddr); + +for(addr= saddr; addr <= eaddr; addr+=4) begin + data = {imem.mem[addr+3],imem.mem[addr+2],imem.mem[addr+1],imem.mem[addr]}; + slam_iccm_ram(addr, data == 0 ? 0 : {riscv_ecc32(data),data}); +end + +endtask + + +task preload_dccm; +bit[31:0] data; +bit[31:0] addr, saddr, eaddr; + +/* +addresses: + 0xffff_fff8 - DCCM start address to load + 0xffff_fffc - DCCM end address to load +*/ + +addr = 'hffff_fff8; +saddr = {lmem.mem[addr+3],lmem.mem[addr+2],lmem.mem[addr+1],lmem.mem[addr]}; +if (saddr < `RV_DCCM_SADR || saddr > `RV_DCCM_EADR) return; +`ifndef RV_DCCM_ENABLE + $display("********************************************************"); + $display("DCCM preload: there is no DCCM in SweRV, terminating !!!"); + $display("********************************************************"); + $finish; +`endif +addr += 4; +eaddr = {lmem.mem[addr+3],lmem.mem[addr+2],lmem.mem[addr+1],lmem.mem[addr]}; +$display("DCCM pre-load from %h to %h", saddr, eaddr); + +for(addr=saddr; addr <= eaddr; addr+=4) begin + data = {lmem.mem[addr+3],lmem.mem[addr+2],lmem.mem[addr+1],lmem.mem[addr]}; + slam_dccm_ram(addr, data == 0 ? 0 : {riscv_ecc32(data),data}); +end + +endtask + +`define DRAM(bank) \ + 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 + + +task slam_iccm_ram(input [31:0] addr, input[38:0] data); +int bank, indx; +`ifdef RV_ICCM_ENABLE +bank = get_iccm_bank(addr, indx); +case(bank) +0: `IRAM0(0)[indx] = data; +1: `IRAM1(0)[indx] = data; +2: `IRAM2(0)[indx] = data; +3: `IRAM3(0)[indx] = data; +`ifdef RV_ICCM_NUM_BANKS_8 +4: `IRAM0(1)[indx] = data; +5: `IRAM1(1)[indx] = data; +6: `IRAM2(1)[indx] = data; +7: `IRAM3(1)[indx] = data; +`endif +`ifdef RV_ICCM_NUM_BANKS_16 +8: `IRAM0(2)[indx] = data; +9: `IRAM1(2)[indx] = data; +10: `IRAM2(2)[indx] = data; +11: `IRAM3(2)[indx] = data; +12: `IRAM0(3)[indx] = data; +13: `IRAM1(3)[indx] = data; +14: `IRAM2(3)[indx] = data; +15: `IRAM3(3)[indx] = data; +`endif +endcase +`endif +endtask + +task slam_dccm_ram(input [31:0] addr, input[38:0] data); +int bank, indx; +`ifdef RV_DCCM_ENABLE +bank = get_dccm_bank(addr, indx); +case(bank) +0: `DRAM(0)[indx] = data; +1: `DRAM(1)[indx] = data; +`ifdef RV_DCCM_NUM_BANKS_4 +2: `DRAM(2)[indx] = data; +3: `DRAM(3)[indx] = data; +`endif +`ifdef RV_DCCM_NUM_BANKS_8 +2: `DRAM(2)[indx] = data; +3: `DRAM(3)[indx] = data; +4: `DRAM(4)[indx] = data; +5: `DRAM(5)[indx] = data; +6: `DRAM(6)[indx] = data; +7: `DRAM(7)[indx] = data; +`endif +endcase +`endif +endtask + +function[6:0] riscv_ecc32(input[31:0] data); +reg[6:0] synd; +synd[0] = ^(data & 32'h56aa_ad5b); +synd[1] = ^(data & 32'h9b33_366d); +synd[2] = ^(data & 32'he3c3_c78e); +synd[3] = ^(data & 32'h03fc_07f0); +synd[4] = ^(data & 32'h03ff_f800); +synd[5] = ^(data & 32'hfc00_0000); +synd[6] = ^{data, synd[5:0]}; +return synd; +endfunction + +function int get_dccm_bank(input int addr, output int bank_idx); +`ifdef RV_DCCM_NUM_BANKS_2 + bank_idx = int'(addr[`RV_DCCM_BITS-1:3]); + return int'( addr[2]); +`elsif RV_DCCM_NUM_BANKS_4 + bank_idx = int'(addr[`RV_DCCM_BITS-1:4]); + return int'(addr[3:2]); +`elsif RV_DCCM_NUM_BANKS_8 + bank_idx = int'(addr[`RV_DCCM_BITS-1:5]); + return int'( addr[4:2]); +`endif +endfunction + +function int get_iccm_bank(input int addr, output int bank_idx); +`ifdef RV_ICCM_NUM_BANKS_4 + bank_idx = int'(addr[`RV_ICCM_BITS-1:4]); + return int'( addr[3:2]); +`elsif RV_ICCM_NUM_BANKS_8 + bank_idx = int'(addr[`RV_ICCM_BITS-1:5]); + return int'(addr[4:2]); +`else + bank_idx = int'(addr[`RV_ICCM_BITS-1:6]); + return int'( addr[5:2]); +`endif +endfunction + +/* verilator lint_off WIDTH */ +/* verilator lint_off CASEINCOMPLETE */ +`include "dasm.svi" +/* verilator lint_on CASEINCOMPLETE */ +/* verilator lint_on WIDTH */ + + +endmodule +`ifdef RV_BUILD_AXI4 +`include "axi_lsu_dma_bridge.sv" +`endif diff --git a/test/helloworld/test_tb_top.cpp b/test/helloworld/test_tb_top.cpp new file mode 100644 index 0000000..899caf1 --- /dev/null +++ b/test/helloworld/test_tb_top.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 "Vtb_top.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); + + Vtb_top* tb = new Vtb_top; + + // init trace dump + VerilatedVcdC* tfp = NULL; + +#if VM_TRACE + Verilated::traceEverOn(true); + tfp = new VerilatedVcdC; + tb->trace (tfp, 24); + tfp->open ("sim.vcd"); +#endif + // Simulate + while(!Verilated::gotFinish()){ +#if VM_TRACE + tfp->dump (main_time); +#endif + main_time += 5; + tb->core_clk = !tb->core_clk; + tb->eval(); + } + +#if VM_TRACE + tfp->close(); +#endif + + std::cout << "\nVerilatorTB: End of sim" << std::endl; + exit(EXIT_SUCCESS); + +}