Introduction


index


Processes

     

2 Ports and Data Types

2.1 SystemC I/O Ports

Table 2.1 shows some basic SystemC I/O ports and their VHDL counter parts.

VHDL Port

SystemC Port

SystemC Notes

in

sc_in

 

out

sc_out

Behaves like a VHDL buffer port

inout

sc_inout

 

buffer

sc_inout

 

Table 2.1 SystemC I/O Ports types

The port's data type is passed on between the angle brackets (<>, templated class), for example:

VHDL

SystemC

port (clk    : in  std_logic;
      count  : inout std_logic_vector(7 downto 0);
      zero   : out std_logic);
sc_in<sc_logic >    clk;
sc_inout<sc_lv<8> > count;
sc_out<sc_logic >   zero;

Note the space between the last 2 closing angle brackets for the count declaration "> >". The >> without the space is a C++ stream operator. Although it might be clear from the context what is intended, some compilers can't handle it (gcc 3.4.4 complains, Visual C++ seems OK).

In VHDL you can specify a range for your vectors but you can't do this in SystemC! This can leads to translation difficulties between VHDL and SystemC since bit positions are no longer the same!

VHDL

SystemC

xyz1  : out std_logic_vector(7 downto 3);
xyz2  : out std_logic_vector(2 to 8);

sc_out<sc_lv<5> > xyz1;
sc_out<sc_lv<7> > xyz2;

2.1.1 Reading and writing from ports

Reading from and writing to an IO ports is straightforward. Unlike in VHDL you only have one assignment operator "=" for both signals and variables. It is therefore recommended to use the port methods when reading from (.read()) and writing to (.write()) a port. A method is a function call that can be overwritten if required (so called virtual member function). Example of some R/W operations:

VHDL

SystemC

SystemC Notes

count  <= X"55";

count=0x55;

Style not recommended

count  <= "0101XZ01";

count.write("0101XZ01");

 

zero <= '0';

zero.write('0');

 

zero <= '0';

zero.write(SC_LOGIC_0)

SC_LOGIC_0, SC_LOGIC_1, SC_LOGIC_X, SC_LOGIC_Z

clk='1'

clk=='1'

Style not recommended

if (clk='1') then

if (clk.read()==SC_LOGIC_1) {

 

Note the == operator in the last SystemC example. It is quite easy to make a mistake like:

int test;
if (test = 42) {   // Mistake, should have been test==42

which is perfectly legal C/C++/SystemC syntax since the return value of the assignment is true but probably not what the programmer intended.

There are cases where the use of '0'/'1'/'X' and 'Z' literals are ambiguous, if you get a compile error then try to use the SystemC std_logic constants SC_LOGIC_0/SC_LOGIC_1/SC_LOGIC_X and SC_LOGIC_Z respectively.

2.1.2 Initialising a ports

Initialising a port is not as simple as in VHDL.  As a VHDL programmer you might have thought of using something like this:

VHDL

SystemC

SystemC Notes

ENTITY (test) is

port (count : out std_logic_vector(7 downto 0):=X"AA";
      zero  : out std_logic:='1');
SC_MODULE(test) {

sc_inout
<sc_lv<8> > count=0xAA;
sc_out<sc_logic >   zero='1';


** error: ISO C++ forbids initialization of member .. **

As was mentioned in the beginning of the tutorial SC_MODULE can be considered as a combined Entity Architecture pair. Although the comparison is valid since both encapsulate ports, processes, functions etc, in reality SC_MODULE is a user defined C++ type (a class). If you then drawn the analogy with a VHDL type (albeit a very powerful one with additional processes, ports and functions) then you can understand that you cannot assign constant values to any of its data members as shown in the above code snippet. An SC_MODULE is created when it is instantiated and at that time the constructor (SC_CTOR) is automatically called. It is during this construction phase that ports, signals and variable are initialised.   To initialise a port you have to use the .initialize() method during construction as shown below.

VHDL

SystemC

ENTITY (test) is

port (count : out std_logic_vector(7 downto 0):=X"AA";
      zero  : out std_logic:='1');
SC_MODULE(test) {
   sc_inout
<sc_lv<8> > count;
   sc_out<sc_logic >   zero;

SC_CTOR(count) {
   count.initialize(0x55);
   zero.initialize('1');

2.2 SystemC Data Types

SystemC extends the C++ data types with some additional types useful for modeling hardware. Table 2.2 list a few of these data types and their equivalent VHDL ones.

VHDL Type

SystemC Type

SystemC Notes

bit

sc_bit

Use native C++ bool type instead

bit_vector

sc_bv

Faster in simulation than sc_lv

std_ulogic

sc_logic

Only support 4 types,  'X','Z','0' and '1'

std_ulogic_vector

sc_lv

Only support 4 types,  'X','Z','0' and '1'

std_logic

sc_logic_resolved

Resolution function for 'X','Z','0' and '1'

std_logic_vector

sc_signal_rv

Resolution function for 'X','Z','0' and '1'

boolean

bool

recommended instead of sc_bit

integer

int

int size is platform dependent, use sizeof(int)

integer

sc_int<N>/sc_uint<N>

N bits signed/unsigned integer vector (N <=64)

integer

sc_bigint<M>/sc_biguint<M>

arbitrary length signed/unsigned integer vector

Coming in VHDL2006

sc_fixed/sc_ufixed/sc_fix/sc_ufix

signed and unsigned fixed point number

float

float

Native C/C++ 32bits floating point number

Table 2.2 SystemC Data types

Note that the SystemC sc_logic and sc_lv are unresolved types and only support 4 signal types ('X','Z','0','1').

The general recommendation is to use the native C++ types as much as possible since they simulate faster than the SystemC types. If you don't need the 'X' and 'Z' values then use bool for std_logic and sc_int/sc_uint for std_logic_vector.

2.2.1 Data Types Operations

Table 2.2.1 shows some VHDL operations and their SystemC equivalent.

Operation

VHDL Example

SystemC Equivalent

Bit Select

count(3)

count[3]

Part Select

count(5 downto 2)

count(5,2)

Alt. Part Select

count(5 downto 2)

count.range(5,2)

Concatenate

count(1)&count(3 downto 2)

(count[1],count(3,2))

Alt. Concatenate

count(1)&count(3 downto 2)

.concat(count[1],count(3,2))

Attributes

count'LEFT

Not Supported, Note 1

Table 2.2.1 Data Type Operations

Note1: some attributes have equivalent methods, for example count'HIGH can be replaced with count.length().

The bit select operator is the overloaded angle brackets [n] operator. The part select (slice in VHDL) is the overloaded round bracket operator (n,n), you can also use the .range() method. Finally the concatenation operator is the overloaded comma (,) operator or you can use the .concat() method. Note, the term operator overloading refers to C++ capability to create new behaviour/functions for standard C++ operators like '+','-','=', '&' etc based on their arguments.

The above described bit/part select and concatenations seems straightforward, however, it is quite easy to make mistakes. The VHDL code fragment below shows a 1 bit ROtate Right register and one that swaps a nibble.

port (din   : in  std_logic_vector(7 downto 0);
      dout1 : out std_logic_vector(7 downto 0);
      dout2 : out std_logic_vector(7 downto 0));  

Architecture

     dout1 <= din(0) & din(7 downto 1);          -- ROR
     dout2 <= din(3 downto 0) & din(7 downto 4); -- Swap Nibble

To translate this to SystemC one might try the following bit of code:

sc_in<sc_uint<8> > din;
sc_out<sc_uint<8> > dout1;
sc_out<sc_uint<8> > dout2;

dout1.write( din[0] , din(7,1) );    //** Error **
dout2.write( din(3,0) , din(7,4) ); //** Error **

This code fragment has several errors, the first one is that you can not apply part select, bit select on a port or signal directly, you need to use the .read() method first. The reason will become clear later in the tutorial. The second problem is that the concatenation (overloaded comma) operator. If you familiar with say the C-language you might think that the following code fragment has 2 redundant brackets:

write((a,b));

And if this was a C function call you would be right, however, for SystemC the comma operator is of the form (,) and the surrounding brackets are part of the overloaded operator so they are required. The correct form of the VHDL code fragment is shown below:

dout1.write( ( din.read()[0] , din.read()(7,1)  ) );  // correct
dout2.write( ( din.read()(3,0) , din.read()(7,4) ) ) ;// correct

or using methods

dout1.write( concat(din.read()[0],  din.read().range(7,1)) ); // correct
dout2.write( concat(din.read()(3,0),din.read().range(7,4)) ); // correct

2.2.2 Logical/Assignment/Equality Operations

Table 2.2.2 list some VHDL operations and their SystemC counter part.

VHDL

SystemC

Notes

Bit wise AND OR XOR NOT

& | ^ ~

 

srl sll

>> <<

 

Signal assignment <=

=

 

Variable assignment :=

=

Note same operator as for signals

Equality = /=

== !=

Easy to make mistake and use one '='

Relational < <= > >=

< <= > >=

same

Table 2.2.2 Operations

2.2.3 Arithmetic Operations

The SystemC integer types (sc_int/sc_uint/sc_bigint/sc_biguint) can all be used with the normal integer operations such as  +,-,*,/ and %. The SystemC vector types (sc_bv/sc_lv) on the other hand do not support any type of arithmetic operations. Although in VHDL you can add to an std_logic_vector using the obsolete std_logic_unsigned package, the recommendation is to use the numeric_std package which means like SystemC you have to convert to unsigned first.

VHDL

SystemC

use ieee.std_logic_unsigned.all; -- Obsolete package
signal
counter : std_bit_vector(7 downto 0);
counter <= counter + '1';

use numeric_std.all; -- good
counter <= std_logic_vector(unsigned(counter) + 1);





sc_signal
<sc_bv<8> > counter;
counter.write(counter.read().to_uint() + 1);

Note SystemC also supports the C/C++ autoincrement ++ and autodecrement -- operators which adds 1 and subtracts 1 respectively.

2.2.4 Data Type Conversions

Conversion between different SystemC types is done using methods. Table 2.2.4 shows some simple examples:

VHDL

SystemC

use ieee.numeric_std.all;

port(dout : out std_logic_vector(3 downto 0));

signal cnt_i : integer range 0 to 15

-- Convert std_logic_vector to integer
cnt_i <= TO_INTEGER(unsigned(din));

-- Convert  integer to std_logic_vector
dout <= std_logic_vector(TO_UNSIGNED(cnt_i, dout'length));



sc_out<sc_lv<4> > dout;

sc_signal<sc_uint<4> > cnt_i;

// Convert sc_lv to sc_uint
cnt_i.write(din.read().to_uint());

// Convert sc_uint to sc_lv using a cast
dout.write(static_cast<sc_lv<4> >(cnt_i.read()));

if (std_logic='1') then boolean=TRUE; else boolean=FALSE;
if (boolean) then std_logic='1'; else std_logic='0';

sc_logic.to_bool();
if (bool) sc_logic='1'; else sc_logic='0';
 

Table 2.2.4 Example type conversion

Note the static_cast operation is not really necessary since there is an implicit conversion from sc_uint to sc_lv, however, this is good coding practise?

 

 


home

 


Introduction


index


Processes