# SystemC - SystemC Perl Interface
# See copyright, etc in below POD section.
######################################################################

package SystemC::Netlist::Class;
use Class::Struct;
use Carp;

use SystemC::Netlist;
use SystemC::Netlist::Net;
use SystemC::Template;
use Verilog::Netlist::Subclass;
@ISA = qw(SystemC::Netlist::Class::Struct
	  Verilog::Netlist::Subclass);
$VERSION = '1.331';
use strict;

structs('new',
	'SystemC::Netlist::Class::Struct'
	=>[name     	=> '$', #'	# Name of the module
	   filename 	=> '$', #'	# Filename this came from
	   lineno	=> '$', #'	# Linenumber this came from
	   msb	 	=> '$', #'	# MSB bit #
	   lsb		=> '$', #'	# LSB bit #
	   stored_lsb	=> '$', #'	# Bit number of signal stored in bit 0  (generally lsb)
	   cast_type	=> '$', #'	# What to cast to for tracing
	   convert_type	=> '$', #'	# What to output if transforming sp_ui's
	   is_enum	=> '$', #'	# Maps to enum type
	   netlist	=> '$', #'	# Netlist is a member of
	   userdata	=> '%',		# User information
	   #
	   # For special procedures
	   _nets	=> '%',		# List of nets if this is tracable
	   ]);

######################################################################
# List of basic C++ types and their sizes

our %GenerateInfo
    = (bool=>		[ msb=>0,  lsb=>0, cast_type=>undef, ],
       sc_clock=>	[ msb=>0,  lsb=>0, cast_type=>'bool', ],
       int8_t=>		[ msb=>7,  lsb=>0, cast_type=>undef, ],
       int16_t=>	[ msb=>15, lsb=>0, cast_type=>undef, ],
       int32_t=>	[ msb=>31, lsb=>0, cast_type=>undef, ],
       int64_t=>	[ msb=>63, lsb=>0, cast_type=>undef, ],
#      int =>		[ msb=>31, lsb=>0, cast_type=>undef, ],
       uint8_t=>	[ msb=>7,  lsb=>0, cast_type=>undef, ],
       uint16_t=>	[ msb=>15, lsb=>0, cast_type=>undef, ],
       uint32_t=>	[ msb=>31, lsb=>0, cast_type=>undef, ],
       uint64_t=>	[ msb=>63, lsb=>0, cast_type=>undef, ],
#      uint =>		[ msb=>0,  lsb=>0, cast_type=>undef, ],
       nint8_t=> 	[ msb=>7,  lsb=>0, cast_type=>undef, ],
       nint16_t=>	[ msb=>15, lsb=>0, cast_type=>undef, ],
       nint32_t=>	[ msb=>31, lsb=>0, cast_type=>undef, ],
       nint64_t=>	[ msb=>63, lsb=>0, cast_type=>undef, ],
       );

######################################################################
######################################################################
#### Netlist construction

sub generate_class {
    my $netlist = shift;
    my $name = shift;
    # We didn't find a class already declared of the specified type.
    # See if it matches a C++ standard type, and if so, add it.
    if ($GenerateInfo{$name}) {
	return $netlist->new_class(name=>$name,
				   @{$GenerateInfo{$name}});
    }
    elsif ($name =~ /^sc_bv<(\d+)>$/) {
	return $netlist->new_class(name=>$name,
				   msb=>($1-1), lsb=>0, cast_type=>undef);
    }
    elsif ($name =~ /^sp_ui<(-?\d+),(-?\d+)>$/) {
	my $msb = $1;  my $lsb = $2;
	# sp_ui<10,1> means we store bits 10:0,
	# and trace 10:0 (as VCD format doesn't allow otherwise)
	my $stored_lsb = ($lsb<0 ? $lsb : 0);
	my $size = $msb-$stored_lsb+1;
	my $out = ((($size==1) && "bool")
		   || (($size<=32) && "uint32_t")
		   || (($size<=64) && "uint64_t")
		   || "sc_bv<".$size.">");
	return $netlist->new_class(name=>$name, convert_type=>$out,
				   msb=>$msb, lsb=>$lsb,
				   stored_lsb=>$stored_lsb,
				   cast_type=>undef);
    }
    elsif ($netlist->{_enum_classes}{$name}) {
	return $netlist->new_class(name=>$name, is_enum=>1,
				   msb=>31, lsb=>0, cast_type=>'uint32_t');
    }
    return undef;
}

######################################################################
######################################################################
#### Accessors

sub logger { return $_[0]->netlist->logger; }

sub sc_type { return $_[0]->convert_type || $_[0]->name; }

sub is_sc_bv {
    my $self = shift;
    return ($self->sc_type =~ /^sc_bv/);
}

######################################################################
######################################################################
#### Nets

# Constructors
sub new_net {
    my $self = shift;
    # @_ params
    # Create a new net under this module
    my $netref = new SystemC::Netlist::Net (direction=>'net', array=>'', @_, module=>$self, );
    $self->_nets ($netref->name(), $netref);
    return $netref;
}

######################################################################
#### Nets
# These are compatible with Module's methods so the reader doesn't need to know
# if it is adding to a module or a class

sub find_net {
    my $self = shift;
    my $search = shift;
    return $self->_nets->{$search};
}

sub _decl_order {}
sub _decl_max { return 1;}

sub nets {
    return (values %{$_[0]->_nets});
}
sub nets_sorted {
    return (sort {$a->name() cmp $b->name()} (values %{$_[0]->_nets}));
}

######################################################################
#### Linking

sub _link {
    my $self = shift;
    foreach my $netref ($self->nets) {
	$netref->_link();
    }
}

######################################################################
#### Debug

sub dump {
    my $self = shift;
    my $indent = shift||0;
    my $norecurse = shift;
    print " "x$indent,"Class:",$self->name(),"  File:",$self->filename(),"\n";
    if (!$norecurse) {
	foreach my $netref ($self->nets_sorted) {
	    $netref->dump($indent+2);
	}
    }
}

######################################################################
#### Package return
1;
__END__

=pod

=head1 NAME

SystemC::Netlist::Class - Class (type) information

=head1 DESCRIPTION

SystemC::Netlist::Class contains type information.  It is called from
SystemC::Netlist.

=head1 DISTRIBUTION

SystemPerl is part of the L<http://www.veripool.org/> free SystemC software
tool suite.  The latest version is available from CPAN and from
L<http://www.veripool.org/systemperl>.

Copyright 2001-2009 by Wilson Snyder.  This package is free software; you
can redistribute it and/or modify it under the terms of either the GNU
Lesser General Public License Version 3 or the Perl Artistic License
Version 2.0.

=head1 AUTHORS

Wilson Snyder <wsnyder@wsnyder.org>

=head1 SEE ALSO

L<SystemC::Netlist>

=cut
