use Storable qw( dclone );
use vars qw( $opt_n $opt_S $opt_I $opt_h $opt_d $opt_v $opt_r $opt_o $opt_t
use vars qw( @ORIG_ARGS );
getopts('n:S:I:hdvropt');
# n - Additional namepaces separated by commas
# S - source file destination path
# I - include file destination path
# d - dump internal representation, then quit
# v - validate register, then quit
# p - include pretty print routines, e.g. toString()
# t - not to make the register a BL_ThinFieldObj-derived class
####################################################################
####################################################################
####################################################################
####################################################################
####################################################################
####################################################################
print "usage: $0 [-h|d|v] [-I include path] [-S source path] [-n csv namespace list] <xml file names>\n";
for my $xml_file ( @ARGV ){
####################################################################
####################################################################
####################################################################
my ( $xml_file, $leaf ) = @_;
my $xs = XML::Simple->new();
my $xml_hash = $xs->XMLin( $xml_file );
# If the register has only one entry, fix it up.
# This is a consequence of using the XML::Simple library.
if( defined $xml_hash->{register}->{field}->{name} ){
# copy the single field to the single field's name. Then remove
# all of the other key's using fix_hash.
$xml_hash->{register}->{field}->{$xml_hash->{register}->{field}->{name}} = dclone( $xml_hash->{register}->{field} );
fix_hash( $xml_hash->{register} );
if ( defined $xml_hash->{register}->{inherits} ){
my $parent_file = $xml_hash->{register}->{inherits};
#$parent_file = $opt_S . "/" . $parent_file if defined $opt_S;
$parent_xml_hash = get_xml_hash( $parent_file, 0 );
$xml_hash = merge_parent_child( $parent_xml_hash, $xml_hash, $leaf );
$xml_hash->{register}->{inheritance_info}->{other_ancestor} = 1;
$xml_hash->{register}->{inheritance_info}->{ancestor_xml} = $parent_file;
for my $field_name ( keys (%{$xml_hash->{register}->{field}}) ){
$xml_hash->{register}->{field}->{$field_name}->{generate_data} = 1;
if( $leaf && defined $xml_hash->{register}->{inheritance_info}->{other_ancestor} ){
my $inh_xml_file = $xml_hash->{register}->{inheritance_info}->{ancestor_xml};
my $inh_include_file = $inh_xml_file;
#$inh_include_file =~ s/\.xml$/.h/;
if( $inh_xml_file =~ m#\b(\w[\w\d]*)\.xml$# ){
$inh_include_file = $1.".h";
die "$0: couldn't extract class name from \"$inh_xml_file\"\n";
$xml_hash->{register}->{inheritance_info}->{include_file} = $inh_include_file;
$xml_hash->{register}->{inheritance_info}->{ancestor_class} = $inh_class_name;
####################################################################
####################################################################
####################################################################
my ( $p, $start_o, $end_o ) = @_;
for my $field ( keys (%{$p->{field}}) ){
return $field if ( $p->{field}->{$field}->{start_offset} == $start_o &&
$p->{field}->{$field}->{end_offset} == $end_o );
####################################################################
####################################################################
####################################################################
my ( $parent_h, $child_h, $leaf ) = @_;
my ( $p, $c ) = ( $parent_h->{register}, $child_h->{register} );
print_debug "Merging $p->{class_name} into $c->{class_name}\n";
my $old_class_name = $p->{class_name};
my $new_class_name = $c->{class_name};
# top-level informational tags
$p->{class_name} = $c->{class_name};
$p->{name} = $c->{name} if defined $c->{name};
$p->{submodule} = $c->{submodule} if defined $c->{submodule};
$p->{priv} = $c->{priv} if defined $c->{priv};
$p->{comment} .= $c->{comment} if defined $c->{comment};
$p->{base_address} .= $c->{base_address} if defined $c->{base_address};
$p->{count} .= $c->{count} if defined $c->{count};
$p->{stride} .= $c->{stride} if defined $c->{stride};
$p->{public} .= $c->{public} if defined $c->{public};
$p->{protected} .= $c->{protected} if defined $c->{protected};
$p->{private} .= $c->{private} if defined $c->{private};
# copy any new aggregations that are in the child
if( defined $c->{aggregate} ){
for my $agg ( keys (%{$c->{aggregate}}) ){
$p->{aggregate}->{$agg} = dclone( $c->{aggregate}->{$agg} );
# don't generate any fields by default.
for my $field ( keys (%{$p->{field}}) ){
$p->{field}->{$field}->{generate_data} = 0;
for my $field ( keys (%{$c->{field}}) ){
my $field_name = location_match(
$c->{field}->{$field}->{start_offset},
$c->{field}->{$field}->{end_offset} );
# there's a field in the parent that matches the child's location
print_debug "Merging field '$field_name'\n";
if( defined $c->{field}->{$field}->{comment} ){
print_debug " Merged comment from $old_class_name.$field_name to $new_class_name.$field\n";
$p->{field}->{$field_name}->{comment} = $c->{field}->{$field}->{comment};
if( defined $c->{field}->{$field}->{base_address} ){
print_debug " Merged base_address from $old_class_name.$field_name to $new_class_name.$field\n";
$p->{field}->{$field_name}->{base_address} = $c->{field}->{$field}->{base_address};
if( defined $c->{field}->{$field}->{count} ){
print_debug " Merged count from $old_class_name.$field_name to $new_class_name.$field\n";
$p->{field}->{$field_name}->{count} = $c->{field}->{$field}->{count};
if( defined $c->{field}->{$field}->{stride} ){
print_debug " Merged stride from $old_class_name.$field_name to $new_class_name.$field\n";
$p->{field}->{$field_name}->{stride} = $c->{field}->{$field}->{stride};
if( defined $c->{field}->{$field}->{protection} ){
print_debug " Merged protection from $old_class_name.$field_name to $new_class_name.$field ";
print_debug "(old = $p->{field}->{$field_name}->{protection}, new = $c->{field}->{$field}->{protection})\n";
$p->{field}->{$field_name}->{protection} = $c->{field}->{$field}->{protection};
if( defined $c->{field}->{$field}->{field_type} ){
print_debug " Merged field_type from $old_class_name.$field_name to $new_class_name.$field ";
print_debug "(old=$p->{field}->{$field_name}->{field_type} new=$c->{field}->{$field}->{field_type})\n";
$p->{field}->{$field_name}->{field_type} = $c->{field}->{$field}->{field_type} ;
if( defined $c->{field}->{$field}->{initial_value} ){
print_debug " Merged intial_value from $old_class_name.$field_name to $new_class_name.$field ";
print_debug "(old=$p->{field}->{$field_name}->{initial_value} new=$c->{field}->{$field}->{initial_value})\n";
$p->{field}->{$field_name}->{initial_value} = $c->{field}->{$field}->{initial_value} ;
if( defined $c->{field}->{$field}->{format} ){
print_debug "Merged format from $old_class_name.$field_name to $new_class_name.$field\n";
$p->{field}->{$field_name}->{format} = dclone( $c->{field}->{$field}->{format} );
# If this statement is true, then the field has been renamed in the child
# Since we've merged everything into the parent, then we'll need clone the
# parent's field (containing the merged data) and assign it to the new name.
# Then we can remove copy under the old field name
if( $field ne $field_name ){
$p->{field}->{$field} = dclone( $p->{field}->{$field_name} );
delete( $p->{field}->{$field_name} );
$p->{field}->{$field}->{generate_data} = $leaf;
print_debug "Adding new field '$field' from child\n";
# no field matches child's location, so we add it.
$p->{field}->{$field} = dclone( $c->{field}->{$field} );
$p->{field}->{$field}->{generate_data} = $leaf;
####################################################################
####################################################################
####################################################################
my $xml_hash = get_xml_hash( $xml_file, 1 );
print Dumper( $xml_hash );
my $register_ref = $xml_hash->{register};
print Dumper( $register_ref );
my $register_ref = $xml_hash->{register};
if( defined $register_ref->{name} ){
gen_cpp( $xml_file, $register_ref->{name}, $register_ref );
foreach my $reg_name ( keys (%{$register_ref}) ){
$register_ref->{$reg_name}->{name} = $reg_name;
gen_cpp( $xml_file, $reg_name, $register_ref->{$reg_name} );
####################################################################
####################################################################
####################################################################
my ( $xml_file, $name, $register_ref ) = @_;
my( $h_file_name, $cc_file_name );
calculate_sizes( $register_ref );
if( !validate( $register_ref ) ){
return if defined $opt_v;
$include_path = $opt_I if defined $opt_I;
$source_path = $opt_S if defined $opt_S;
if( ! -d $include_path ){
system( "mkdir -p $include_path" );
system( "mkdir -p $source_path" );
$h_file_name = xlate_path( $register_ref->{class_name}, $include_path, "h" );
$cc_file_name = xlate_path( $register_ref->{class_name}, $source_path, "cc" );
open DOT_H_FILE, ">$h_file_name" or die "couldn't create $h_file_name";
open DOT_CC_FILE, ">$cc_file_name" or die "couldn't create $cc_file_name"
print "$xml_file -> $h_file_name\n";
write_include_file( *DOT_H_FILE, $xml_file, $register_ref, $register_ref->{name} );
print "$xml_file -> $cc_file_name\n";
write_impl_file ( *DOT_CC_FILE, $xml_file, $register_ref, $register_ref->{name} );
####################################################################
####################################################################
####################################################################
for my $field_name ( keys (%{$reg_ref->{field}} ) ){
$reg_ref->{field}->{$field_name}->{size} = $reg_ref->{field}->{$field_name}->{end_offset} -
$reg_ref->{field}->{$field_name}->{start_offset} + 1;
####################################################################
####################################################################
####################################################################
my ( $file, $path, $suffix ) = @_;
$new_file = $path . "/" . $new_file;
return $new_file . "." . $suffix;
####################################################################
####################################################################
####################################################################
for my $field_name ( keys (%{$reg_hash->{field}} ) ){
$bits += $reg_hash->{field}->{$field_name}->{size};
####################################################################
####################################################################
####################################################################
my %sz_hash = ( 8 => "uint8_t",
for my $k ( sort { $a <=> $b } keys %sz_hash ){
return ( $sz_hash{$k}, $k ) if $nr_bits <= $k;
print "ERROR: size $nr_bits cannot be represented in an integral type\n";
return ("ERROR", "ERROR");
####################################################################
####################################################################
####################################################################
sub build_aggregate_include_string
my $agg_ref = $reg_ref->{aggregate};
my $field_ref = $reg_ref->{field};
for my $agg ( keys (%{$agg_ref} ) ){
for my $field ( keys (%{$agg_ref->{$agg}->{field}}) ){
$size += $field_ref->{$field}->{end_offset} - $field_ref->{$field}->{start_offset} + 1;
my ( $native_type, $bits ) = get_native_type( $size );
$native_type get${agg}();
void set${agg}( $native_type );
####################################################################
####################################################################
####################################################################
sub build_aggregate_impl_string
my ( $reg_ref, $class_name ) = @_;
my $agg_ref = $reg_ref->{aggregate};
my $field_ref = $reg_ref->{field};
for my $agg ( keys (%{$agg_ref} ) ){
for my $field ( keys (%{$agg_ref->{$agg}->{field}}) ){
my $sz = $field_ref->{$field}->{end_offset} - $field_ref->{$field}->{start_offset} + 1;
$field_data{$agg_ref->{$agg}->{field}->{$field}->{'pos'}}->{name} = $field;
$field_data{$agg_ref->{$agg}->{field}->{$field}->{'pos'}}->{size} = $sz;
my ( $native_type, $bits ) = get_native_type( $size );
my ( $get_str, $set_str ) = ( "", "" );
for my $pos ( sort { $a <=> $b } keys %field_data ){
my $var_name = uc $field_data{$pos}->{name};
my $mask = (2 ** $field_data{$pos}->{size}) - 1;
$mask = sprintf "0x0%lx", $mask;
$get_str .= "(get$var_name() << $offset) |\n ";
$set_str .= " set$var_name((____d >> $offset) & $mask);\n";
$offset += $field_data{$pos}->{size};
$native_type ${class_name}::get${agg}()
void ${class_name}::set${agg}( $native_type ____d )
####################################################################
####################################################################
####################################################################
my ( $constructor_mask, $constructor_init, $constructor_bits,
$constructor_rw1c ) = ( "0\n", "0\n", "0\n", "0\n" );
for my $field_name ( keys (%{$reg_ref->{field}} ) ){
$register_size += $reg_ref->{field}->{$field_name}->{size};
if( $reg_ref->{field}->{$field_name}->{field_type} eq "NORMAL" ){
push @tmpList, $field_name;
$fields{ $reg_ref->{field}->{$field_name}->{start_offset}} =
while( ($fn = pop @tmpList) ){
my $ha_field_mask = "(~uint64_t(0) >> (64 - $reg_ref->{field}->{$fn}->{size}))";
my $ha_field_shft = "$reg_ref->{field}->{$fn}->{start_offset}";
if( defined $reg_ref->{field}->{$fn}->{initial_value} ){
$constructor_init .= " | (($reg_ref->{field}->{$fn}->{initial_value} & $ha_field_mask) << $ha_field_shft)\n";
if( $reg_ref->{field}->{$fn}->{field_type} eq "NORMAL" ){
if( $reg_ref->{field}->{$fn}->{protection} eq "RW" ){
$constructor_mask .= " | ($ha_field_mask << $ha_field_shft)\n";
if( $reg_ref->{field}->{$fn}->{protection} eq "RW1C" ){
$constructor_rw1c .= " | ($ha_field_mask << $ha_field_shft)\n";
$constructor_bits .= " | ($ha_field_mask << $ha_field_shft)\n";
return ( $constructor_mask, $constructor_init, $constructor_bits,
####################################################################
####################################################################
####################################################################
my( $file_handle, $xml_file, $reg_ref, $reg_name ) = @_;
my $reg_name_uc = uc $reg_name;
my $class_name = $reg_ref->{class_name};
my $class_name_ref = "${class_name}&";
my $class_name_const_ref = "const ${class_name}&";
my ( $get_string, $set_string );
my ( $extra_namespace_header, $extra_namespace_footer );
my $field_type_enum = "enum { ";
my $field_string_array = "static const FieldObject::FieldInfo fieldData[] = {";
my $pretty_print_includes;
my ( $constructor_mask, $constructor_init, $constructor_bits,
$constructor_rw1c ) = &calc_constructors($reg_ref);
"$constructor_mask, $constructor_init, $constructor_bits, $constructor_rw1c";
if (defined $reg_ref->{base_address}) {
$base_address = "static const uint64_t BaseAddress = $reg_ref->{base_address};";
if (defined $reg_ref->{count}) {
$count = "static const uint64_t Count = $reg_ref->{count};";
if (defined $reg_ref->{stride}) {
$stride = "static const uint64_t Stride = $reg_ref->{stride};";
if (defined $reg_ref->{public}) {
$public = "$reg_ref->{public}";
if (defined $reg_ref->{protected}) {
$protected = "$reg_ref->{protected}";
if (defined $reg_ref->{private}) {
$private = "$reg_ref->{private}";
$agg_string = build_aggregate_include_string( $reg_ref ) if defined $reg_ref->{aggregate};
# Get count of total register size and field count
for my $field_name ( keys (%{$reg_ref->{field}} ) ){
# maps field start_offset to field name
$fields{$reg_ref->{field}->{$field_name}->{start_offset}} = $field_name;
$sz += $reg_ref->{field}->{$field_name}->{size};
my $field_count = $nr_fields;
for my $o ( reverse sort { $a <=> $b } keys %fields ){
my $field_name = $fields{$o};
$field_type_enum .= uc $field_name;
if($reg_ref->{field}->{$field_name}->{field_type} eq "NORMAL" ){
my ($data_type, $foo) = get_native_type( $reg_ref->{field}->{$field_name}->{size} );
# $field_type_struct .= " $data_type ". lc $field_name . ";\n" if $reg_ref->{field}->{$field_name}->{generate_data};
$get_string .= create_get_fn_decl( $reg_name, $field_name, $reg_ref->{field}->{$field_name}->{size}, $reg_ref->{field}->{$field_name}->{start_offset} );
$set_string .= create_set_fn_decl( $reg_name, $field_name, $reg_ref->{field}->{$field_name}->{size}, $reg_ref->{field}->{$field_name}->{start_offset}, $reg_ref->{field}->{$field_name}->{protection});
$set_string .= create_bitsize_decl( $reg_name, $field_name, $reg_ref->{field}->{$field_name}->{size}, $reg_ref->{field}->{$field_name}->{start_offset}, $reg_ref->{field}->{$field_name}->{protection}); }
$field_type_enum =~ s/,\s*$//; # chop off the comma from the last entry
$field_type_enum .= " }";
my $include_guard = "RIESLING_" . uc $class_name . "_H";
my $comment_str = get_comment_string( $0, $xml_file );
foreach my $ns ( split /,/, $opt_n ){
$extra_namespace_header .= "namespace $ns {\n";
$extra_namespace_footer .= "} /* namespace $ns */\n";
## Frontend registration handling
my $to_string_fn = "std::string toString() const;";
my $set_native_fn = "void setNative( uint64_t value ) { FieldObject::setNative(value); }";
$set_native_fn = "void setNative( uint64_t value ) { BL_ThinFieldObj<$constructor_list>::setNative(value); }" if $opt_t;
my $set_nativeHW_fn = "void setNativeHW( uint64_t value ) { FieldObject::setNativeHW(value); }";
$set_nativeHW_fn = "void setNativeHW( uint64_t value ) { BL_ThinFieldObj<$constructor_list>::setNativeHW(value); }" if $opt_t;
my $get_native_fn = "uint64_t getNative() const { return FieldObject::getNative(); }";
$get_native_fn = "uint64_t getNative() const { return BL_ThinFieldObj<$constructor_list>::getNative(); }" if $opt_t;
my $default_ctor = "$class_name();";
my $ancestor_include = $opt_t ? '#include "BL_ThinFieldObj.h"' :
'#include "FieldObject.h"';
my $ancestor_class = "FieldObject";
$ancestor_class = "BL_ThinFieldObj<$constructor_list>" if $opt_t;
if( defined $reg_ref->{inheritance_info}->{other_ancestor} ){
$ancestor_include = '#include "' . $reg_ref->{inheritance_info}->{include_file} . '"';
$ancestor_class = $reg_ref->{inheritance_info}->{ancestor_class};
# TODO This should really find out of RegisteredObject was already inherited by its # ancestor
# base class aready has these so no need to duplicate/confuse people
$pretty_print_includes = "#include <iostream>\n#include <string>\n" if $ opt_p;
print $file_handle <<EOHFILE0
#include "BL_ThinFieldObj.h"
print $file_handle <<EOHFILE1
#include "Interface/RegisteredObject.h"
#################################
## Produce html for doxygen
#################################
print $file_handle "/**\n<pre>\n";
print_field_table_doc( $file_handle, $reg_name_uc, \%fields, $reg_ref );
print $file_handle "\n</pre>\n*/\n";
print $file_handle <<EOHFILE1
class $class_name : public $ancestor_class $extra_ancestors {
print $file_handle <<EOHFILE4
print $file_handle <<EOHFILE5
* An enumeration that represent each accessable field. Use these types
* as inputs for accessors and mutators for fields.
typedef $field_type_enum FieldT;
print $file_handle <<EOHFILE6
$class_name( $class_name_const_ref obj );
print $file_handle <<EOHFILE60
$class_name_const_ref operator=( $class_name_const_ref obj ) { return ($class_name_const_ref)$ancestor_class ::operator=(obj); }
bool operator==( $class_name_const_ref obj ) const { return $ancestor_class ::operator==(obj); }
* Get a copy of the register's native representation
* \@param data A pointer to a chunk of memory large enough
* to hold the register's native representaion
print $file_handle <<EOHFILE7
* Return the register's size in bits
* \@return The register size in bits
* \@see ${class_name}::FieldT
uint32_t getSize() const;
* Return the field's size in bits
* \@param field The number of this field
* \@return The field's size in bits
* \@see ${class_name}::FieldT
virtual uint32_t getSize( uint_t field ) const;
* Return the field's offset in the register
* \@param field The number of this field
* \@return The field's offset
* \@see ${class_name}::FieldT
virtual uint32_t getOffset( uint_t field ) const;
* Return the field's protection. That is, can the field be
* read, written, or both.
* \@param field The number of this field
* \@return The field's protection
* \@see FieldObject::ProtectionT
* \@see ${class_name}::FieldT
FieldObject::Protection getProtection( uint_t field ) const;
* Return a string representation of the field name
* \@param field The number of this field
* \@return The name of the field
* \@see ${class_name}::FieldT
virtual const char* getName() const;
* Return a string representation of the field name
* \@param field The number of this field
* \@return The name of the field
* \@see ${class_name}::FieldT
virtual const char* getName( uint_t field ) const;
print $file_handle <<EOHFILE80
my( $file_handle, $xml_file, $reg_ref, $reg_name ) = @save_args;
write_impl_file( $file_handle, $xml_file, $reg_ref, $reg_name );
print $file_handle <<EOHFILE8
* Return the string representaton of this register.
* Print this Register to an output stream
* \@param os The output stream to which the register should be
* printed. Omitting this parameter will print the std::cout
virtual void print( std::ostream& os = std::cout ) const;
print $file_handle <<EOHFILE85
print $file_handle <<EOHFILE9
//! How many fields the register has.
static const int NR_FIELDS = $nr_fields;
static const FieldObject::FieldInfo fieldData[];
print $file_handle <<EOHFILE10
#endif /* $include_guard */
####################################################################
####################################################################
####################################################################
my( $file_handle, $xml_file, $reg_ref, $reg_name ) = @_;
my $ifile_name = $reg_ref->{class_name} . ".h";
if( defined $reg_ref->{submodule} ){
$ifile_name = $reg_ref->{submodule} . "/" . $ifile_name;
my $class_name = $reg_ref->{class_name};
my $class_name_ref = "${class_name}&";
my $class_name_const_ref = "const ${class_name}&";
my $class_scope = $class_name . '::';
my ( $get_string, $set_string );
my ( $copy_constructor_string, $constructor_string );
my ( $constructor_mask, $constructor_init, $constructor_bits,
$constructor_rw1c ) = &calc_constructors($reg_ref);
my ( $get_native_string, $set_native_string, $set_nativeHW_string );
$agg_string = build_aggregate_impl_string( $reg_ref, $class_name ) if defined $reg_ref->{aggregate};
my $field_string_array = "const FieldObject::FieldInfo ${class_scope}fieldData[] = {";
for my $field_name ( keys (%{$reg_ref->{field}} ) ){
$register_size += $reg_ref->{field}->{$field_name}->{size};
if( $reg_ref->{field}->{$field_name}->{field_type} eq "NORMAL" ){
push @tmpList, $field_name;
$fields{ $reg_ref->{field}->{$field_name}->{start_offset}} = $field_name;
for my $o ( reverse sort { $a <=> $b } keys %fields ){
my $field_name = $fields{$o};
if ( $reg_ref->{field}->{$field_name}->{protection} eq "RWH") {
$field_string_array .= "\n { FieldObject::RO, ";
$field_string_array .= "\n { FieldObject::$reg_ref->{field}->{$field_name}->{protection}, ";
$field_string_array .= " $reg_ref->{field}->{$field_name}->{start_offset},";
$field_string_array .= " $reg_ref->{field}->{$field_name}->{size},";
$field_string_array .= " FieldObject::$reg_ref->{field}->{$field_name}->{field_type},";
$field_string_array .= " \"$field_name\" }";
$field_string_array .= ",";
if( $reg_ref->{field}->{$field_name}->{field_type} eq "NORMAL" ){
# build impl for getNative method
$get_native_string .= " |\n" if $get_native_string ne "";
$get_native_string .= " ( (0ULL |" . lc $field_name . ") << " .
$reg_ref->{field}->{$field_name}->{start_offset} . ")";
# build impl for setNative method
if( $reg_ref->{field}->{$field_name}->{protection} eq "RW" ){
my $mask = "(~0ULL >> (64 - $reg_ref->{field}->{$field_name}->{size}))";
$set_native_string .= " " . lc $field_name .
" = (____d >> $reg_ref->{field}->{$field_name}->{start_offset}) & $mask;\n";
elsif($reg_ref->{field}->{$field_name}->{protection} eq "RW1C"){
my $mask = "(~0ULL >> (64 - $reg_ref->{field}->{$field_name}->{size}))";
$set_native_string .= " " . lc $field_name .
" &= ~((____d >> $reg_ref->{field}->{$field_name}->{start_offset}) & $mask);\n";
# build impl for setNativeHW method
if( $reg_ref->{field}->{$field_name}->{protection} ne "RO" ){
my $mask = "(~0ULL >> (64 - $reg_ref->{field}->{$field_name}->{size}))";
$set_nativeHW_string .= " " . lc $field_name .
" = (____d >> $reg_ref->{field}->{$field_name}->{start_offset}) & $mask;\n";
$field_string_array =~ s/,\s*$//; # chop off the comma from the last entry
$field_string_array .= " }";
my ( $get_case_body, $set_case_body );
while( ($fn = pop @tmpList) ){
$equal_string .= " $lc_fn == rhs.$lc_fn";
$equal_string .= " &&\n" if @tmpList;
$printing_string .= " \"" . uc( $fn ) . "=\" << get$uc_fn() << \" \"";
$printing_string .= " <<\n" if @tmpList;
my $comment_str = get_comment_string( $0, $xml_file );
# construct using declarations for each additional namespace
my $extra_ns_accum = "Riesling";
foreach my $ns ( split /,/, $opt_n ){
$extra_ns_accum .= "::$ns";
$using_ns .= "using namespace $extra_ns_accum;\n";
print $file_handle <<EO_CCFILE
using namespace Riesling;
print $file_handle <<EO_CCFILE1
const int ${class_scope}NR_FIELDS;
print $file_handle <<EO_CCFILE6
$class_name( const $class_name& obj )
print $file_handle <<EO_CCFILE6
${class_scope}$class_name()
mask = $constructor_mask ;
init = $constructor_init ;
bits = $constructor_bits ;
rw1c = $constructor_rw1c ;
${class_scope}~$class_name()
${class_scope}$class_name( const $class_name& obj )
print $file_handle <<EO_CCFILE7
uint32_t ${class_scope}getSize() const
uint32_t ${class_scope}getSize( uint_t field ) const
if( field >= NR_FIELDS ){
RIESLING_THROW_INVALID_ARGUMENT( "Invalid field specifier." );
return ${class_scope}fieldData[ field ].size;
uint32_t ${class_scope}getOffset( uint_t field ) const
if( field >= NR_FIELDS ){
RIESLING_THROW_INVALID_ARGUMENT( "Invalid field specifier." );
return ${class_scope}fieldData[ field ].offset;
FieldObject::Protection ${class_scope}getProtection( uint_t field ) const
if( field >= NR_FIELDS ){
RIESLING_THROW_INVALID_ARGUMENT( "Invalid field specifier." );
return ${class_scope}fieldData[ field ].prot;
const char* ${class_scope}getName() const
return "$reg_ref->{name}";
const char* ${class_scope}getName( uint_t field ) const
if( field >= NR_FIELDS ){
RIESLING_THROW_INVALID_ARGUMENT( "Invalid field specifier." );
return ${class_scope}fieldData[ field ].name;
print $file_handle <<EO_CCFILE8
std::string ${class_scope}toString() const
os << std::hex << $printing_string;
void ${class_scope}print( std::ostream& os ) const
print $file_handle "$agg_string\n;";
####################################################################
####################################################################
####################################################################
my ( $class_name, $field_name, $field_size, $field_start, $prot) = @_;
my ( $sz_type, $sz ) = get_native_type( $field_size );
my $field_name_uc = uc $field_name;
my $field_name_lc = lc $field_name;
my $rvalue = "(value << $field_start)";
my $mask = "uint64_t field_mask = (~uint64_t(0) >> (64 - $field_size)) << $field_start;";
$rvalue = "(data & ~field_mask) | ((value << $field_start) & field_mask)";
## This is a little painful. Long time ago Riesling decided to make itself public, very public
## and that means that all registers are visible and accessable, including the set field methods.
## This is a grieving mistake. It should have been hidden, awell, now we have a problem ...
## If someone sets a field of a register and internally there is some side effect associated with that
## then we need to call a function or method that handles the side effect ... thank god for pointers
## to functions or methods ha style. All because the rshell allows for statements like
## $hpstate.HPRIV=1 ... and that needs a call ... and I don't know what the jshell does.
my $decl_string = "void set$field_name_uc( uint64_t value ) { $mask data=$rvalue; }\n";
$decl_string .= "void set${field_name_uc}_Notify( uint64_t value ) { $mask call->call(this,$rvalue); }" if ! $opt_t;
$decl_string = "virtual $decl_string";
//! set the value of $class_name.$field_name_uc
####################################################################
####################################################################
####################################################################
my ( $class_name, $field_name, $field_size, $field_start ) = @_;
my ( $sz_type, $sz ) = get_native_type( $field_size );
my $field_name_uc = uc $field_name;
my $field_name_lc = lc $field_name;
my $decl_string = "uint64_t get$field_name_uc( ) const { return (data >> $field_start) & (~uint64_t(0) >> (64 - $field_size));}";
$decl_string = "virtual $decl_string";
//! return the value of $class_name.$field_name_uc
####################################################################
####################################################################
####################################################################
my ( $class_name, $field_name, $field_size, $field_start ) = @_;
my ( $sz_type, $sz ) = get_native_type( $field_size );
my $field_name_uc = uc $field_name;
my $field_name_lc = lc $field_name;
my $decl_string = "static const bitSize$field_name_uc = $field_size;";
//! return the value of $class_name.$field_name_uc
####################################################################
####################################################################
####################################################################
my ( $generator, $source_file ) = @_;
my( $user_login_name,$passwd,$uid,$gid,$quota,$comment,$user_full_name, @foo ) = getpwuid( $1 );
my $short_gen = $generator;
$source_file = resolve_path( $pwd, $source_file );
/************************************************************************
** ****** MACHINE-GENERATED FILE ******
** ****** DO NOT EDIT BY HAND ******
** Generated from $source_file
** File created on $today by $user_full_name ($user_login_name)
** Command Line Used to Generate File:
** Copyright (C) 2002, Sun Microsystems, Inc.
** Sun considers its source code as an unpublished, proprietary
** trade secret and it is available only under strict license provisions.
** This copyright notice is placed here only to protect Sun in the event
** the source is deemed a published work. Disassembly, decompilation,
** or other means of reducing the object code to human readable form
** is prohibited by the license agreement under which this code is
** provided to the user or company in possession of this copy.
*************************************************************************/
####################################################################
####################################################################
####################################################################
while( $path =~ s#\.\./## ){
if( $path !~ m#^/# && $pwd !~ m#/$# ){
####################################################################
####################################################################
####################################################################
sub get_register_documentation_string
####################################################################
####################################################################
####################################################################
sub print_field_table_doc
my ( $file_handle, $reg_name, $field_ref, $reg_ref ) = @_;
#################################
## Produce the table of register fields.
#################################
print $file_handle <<EOHEAD
$reg_name Field Specification
Offset Size Name Description
------------------------------------------------------------------------------------------------
for my $o ( sort { $a <=> $b } keys %{$field_ref} ){
my ($FMT_offset,$FMT_size,$FMT_name, $FMT_description);
my $field_name = $field_ref->{$o};
@>> @>> @<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
$FMT_offset,$FMT_size,$FMT_name, $FMT_description
^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<~~
( $FMT_description, @comments ) = split /\\n/, $reg_ref->{field}->{$field_name}->{comment};
$FMT_offset = $reg_ref->{field}->{$field_name}->{start_offset};
$FMT_size = $reg_ref->{field}->{$field_name}->{size};
$file_handle->format_name( "COMMENT_INIT" );
my $FMT_cont = shift @comments;
^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<~~
$file_handle->format_name( "COMMENT_CONT" );
####################################################################
####################################################################
####################################################################
delete( $reg_ref->{field}->{field_type});
delete( $reg_ref->{field}->{name} );
delete( $reg_ref->{field}->{format} );
delete( $reg_ref->{field}->{comment} );
delete( $reg_ref->{field}->{start_offset} );
delete( $reg_ref->{field}->{end_offset} );
delete( $reg_ref->{field}->{protection} );
delete( $reg_ref->{field}->{size} );
delete( $reg_ref->{field}->{initial_value} );
####################################################################
####################################################################
####################################################################
for my $field_name ( keys (%{$reg_ref->{field}} ) ){
$size += $reg_ref->{field}->{$field_name}->{size};
$max_offset = $reg_ref->{field}->{$field_name}->{end_offset}
if $max_offset < $reg_ref->{field}->{$field_name}->{end_offset};
if( $size != $max_offset + 1 ){
print STDERR "VALIDATION ERROR: Max end_offset is $max_offset but is size is $size\n.";
for( my $i = 0; $i < $size; $i++ ){
for my $field_name ( keys (%{$reg_ref->{field}} ) ){
if( defined $names{ $field_name } ){
print STDERR "VALIDATION ERROR: duplicate field: $field_name\n";
if( $field_name =~ /^\W/ ){
print STDERR "VALIDATION ERROR: $field_name must start with a letter or and underscore.\n";
if( $field_name =~ /([^\w\d])/ ){
print STDERR "VALIDATION ERROR: $field_name cannot contain the character $1.\n";
# Check for offsets that are negative or too large.
my $offset = $reg_ref->{field}->{$field_name}->{start_offset};
print STDERR "VALIDATION ERROR: $field_name.offset is negative\n";
print STDERR "VALIDATION ERROR: $field_name.offset = $offset is greater than size = $size\n";
my $field_size = $reg_ref->{field}->{$field_name}->{size};
print STDERR "VALIDATION ERROR: $field_name.size is less than one.\n";
if( $offset + $field_size - 1 >= $size ){
print STDERR "VALIDATION ERROR: $field_name.offset ($offset) + $field_name.size ($field_size) is \
greater than size ($size)\n";
# Check for overlapping bits
for( my $i = $offset; $i < ($offset + $field_size); $i++ ){
print STDERR "VALIDATION ERROR: $field_name overlaps with $bits[$i] at bit $i\n";
my $initial_value = $reg_ref->{field}->{$field_name}->{initial_value};
my $max_size = ( 2 ** $size ) - 1;
if( $initial_value > $max_size ){
print STDERR "WARNING: $field_name.intial_value is greater than maximum representable value for\n";
print STDERR " $field_name. This value will be truncated.\n";
$reg_ref->{field}->{$field_name}->{initial_value} &= $max_size;
my $prot = $reg_ref->{field}->{$field_name}->{protection};
if( $prot ne "RO" && $prot ne "RW" && $prot ne "WO" && $prot ne "RWH" && $prot ne "RW1C"){
# RWH is used to indicate a field that is read-only by software,
# but is writable by hardware, we need this to create setNativeHW,
# to be used by (N2) testbench to force a value into an otherwise
print STDERR "VALIDATION ERROR: $field_name.protection is not RO, RW, or WO [$prot]\n";
print STDERR "IMPLEMENTATION CHANGE: RWH behaviour is available through setNativeHW which treats RO fields as RW\n";
my $type = $reg_ref->{field}->{$field_name}->{field_type};
if( $type ne "NORMAL" && $type ne "DONT_CARE" && $type ne "ZERO" ){
print STDERR "VALIDATION ERROR: $field_name.field_type is not NORMAL, DONT_CARE, or ZERO.\n";
my $comment = $reg_ref->{field}->{$field_name}->{comment};
if( $type ne "NORMAL" && $comment != /\w/ ){
print STDERR "VALIDATION WARNING: $field_name.comment appears to be blank\n";
for( my $i = 0; $i < $size; $i++ ){
push @uncounted_bits, $i;
if( @uncounted_bits > 0 ){
print STDERR "VALIDATION ERROR: Bits @uncounted_bits are not part of any field.\n";
####################################################################
####################################################################
####################################################################
xml2reg - Build a C++ implementation of a register from an XML specification.
xml2reg [-hdrv] [ -n namespaces] [ -I path] [ -S path ] xml file ...
xml2reg takes an XML file containing a specification for a register as input and generates the
corresponding C++ implemenation of that specification. All xml2reg-generated registers
implement the FieldObject interface. xml2reg documents the C++ files with appropriate
doxygen-compatible comments.
Dump out the internal represenation (parse tree) of the XML file. This option is useful
for developers who wish to modify xml2reg.
Validate the XML file and then exit without generating any C++ output. This option is used
to ensure the correctness of the your XML register file specification. xml2reg performs a
number of sanity checks on your XML file. When an error in your XML file is discovered,
xml2reg will report the error to stderr an then exit with a nonzero status. Some problems with your
XML will generate warnings. A warning will be reported to stderr, but will not cause xml2reg to
exit. xml2reg will exit with zero status if your file has no errors but does generate warnings.
=item B<-n> I<namespace list>
Enclose the C++ implemenation in additional namespaces. By default, the C++ code generated by
xml2reg is placed in the Riesling namespace. This option is used to specify additional enclosing
namespaces. The namespaces are specified as a comma-separated list of namespaces with no intervening
whitespace. The the namespaces should be specified from in outermost to innermost order.
Generate code to make this register accessble from the object registry. Classes generated with this
can be instantiated and their instances manipulated Riesling's frontend.
Specify the directory to which the generated header file (.h file) should be written.
Specify the directory to which the generated implemenation file (.cc file) should be written.
Generate C++ code for a single xml file. The resulting C++ files will be names myreg.h and myreg.cc.
The files will be written to the current working directory.
Process all the XML files in the current directory. A .h and .cc file will be generated for each
xml2reg -n Mmu -I /src/Riesling/include/mmu -S /src/Riesling/src/mmu MmuConfigReg.xml
Generates C++ code for the XML file MmuConfigReg.xml. The the class is enclosed in the Mmu namespace.
The .h file is written to /src/Riesling/include/mmu/MmuConfigReg.h. The .cc file is written to
/src/Riesling/include/mmu/MmuConfigReg.cc.
XML::Simple, FileHandle, process_xml(1)
Errors parsing the XML file will be reported by XML::Simple, and these errors can be cryptic.
See the document I<Riesling Register Specification> for a complete discussion
of the XML specification.