An Introduction to Basic SystemC Data Types

By John
March 10, 2022

In this post we take a look at the some of the basic data types which are included in the SystemC library. This includes a discussion of the sc_logic and sc_lv data types.

In the next post in this series, we look at the numeric data types that are included in the SystemC library.

SystemC is actually a set of classes and libraries which are built on top of the C++ programming language. We can download and install these libraries for free from the accellera website.

As a result of this, the basic syntax of the SystemC language is taken directly from C++.

However, in these tutorials we will only look at the SystemC extensions which we can use in FPGA design and verification.

Therefore, if you are not already familiar with the C++ language then it is a good idea to take a beginners C++ course before reading through these tutorials.

Simple Binary Types

When we are designing an FPGA, almost all of our signals fundamentally consist of one or more logical bits. We use the different data types in SystemC to tell our tools how these bits should be interpreted.

For example, when we declare an integer type variable in SystemC then we are actually declaring a 32 bit two's complement number.

The simplest types of data we can use in SystemC consists of a number of logical bits which are interpreted as binary words. We typically use one of the two data types for this purpose in SystemC.

Let's take a closer look at both of these data types.

sc_logic Type

The sc_logic type is the most basic of all of the SystemC data types. We use this type to model a single binary value within our FPGA. 

The code snippet below shows the syntax we use to declare an sc_logic data type in SystemC.

sc_logic <signal_name>;

We use the <name> field in the above construct to give a name to our variable.

When we design digital circuits in SystemC, we often use the C++ bool type to model single binary values.

However, we can also have cases where we need to model values other than 0b or 1b in SystemC. We could have a case where we need to drive the pin of an FPGA high impedance, for example.

The sc_logic type makes it possible to for us to model these different states in our design.

In addition to this, it also models conditions where the logic value is unknown or non-deterministic. This typically occurs due to errors in our design such as attempting to drive a signal from 2 different sources.

The table below shows the full list of values that the sc_logic type can have.

ValueDescription
XUnknown value as it's impossible to determine the value.
0Logic level 0
1Logic level 1
'Z'High impedance

We typically use SystemC constants to assign values to the sc_logic data type. These constants are SC_LOGIC_0 (for 0b), SC_LOGIC_1 (for 1b), SC_LOGIC_Z (high impedance) and SC_LOGIC_X (unknown value).

However, we can also directly assign the sc_logic type to '0', '1', 'z' or 'x'.

The code snippet below show how we assign values to a signal or port which uses the sc_logic type in SystemC. We can also simulate this example on EDA playground.

// Assigning a signal to 1
sc_logic sc_example1 = SC_LOGIC_1;
sc_example1 = '1';

// Assigning a signal to 0
sc_logic sc_example0 = SC_LOGIC_0;
sc_example0 = '0';

// Assigning a signal to high impedance
sc_logic sc_examplez = SC_LOGIC_Z;
sc_examplez = 'z';

// Assigning a signal to an unknown state
sc_logic sc_examplex = SC_LOGIC_X;
sc_examplex = 'x';

sc_lv Type

When we design digital circuits, we often use data buses which consist of multiple bits. We can't model these signals with the sc_logic data type as it consists of only 1 bit.

Therefore, we need to use a different data type to model data buses in our designs. In SystemC, we use the sc_lv data type for this purpose.

The sc_lv data type consists of a number of bits which are each modeled in a similar way to the sc_logic data type.

In order to allow for different size buses to be declared, the sc_lv data type is implemented as a generic C++ classes in SystemC. This means that we have to provide a parameter which defines how many bits are in the signal.

The code snippet below shows the general syntax we use to declare a sc_lv data type in SystemC.

sc_lv<<bits>> <name>;

In the above construct we use the <bits> to declare the number of bits in our signal.

We use the <name> field in the above construct to give a name to our signal.

When we assign data to the sc_lv data type we use quotation marks (") to enclose the binary data.

The code snippet below shows the general syntax we use to assign data to a sc_lv type variable.

// Declare a four bit vector
sc_lv<4> example_vector;

// Assign the value of 1010b (0xA)
example_vector = "1010";

Bit Slicing

We can also access single bits or data slices when we are working with sc_lv data types in SystemC.

In order to access a single bit in our sc_lv data we simply specify the bit which we want to access inside of square brackets. The code snippet below shows the general syntax we use to do this.

<variable_name>[<bit_number>] = <data>;

In this construct, we use the <bit_number> field to select the relevant bit in our variable.

When we want to access a slice of data in an sc_lv data type, we simply specify the range of the bits which we are selecting.

However, we do this inside of parentheses rather than square brackets when we want to take a slice of data.

The code snippet below shows the general syntax for this.

<variable_name>(<first_bit>, <last_bit>) = <data>;

In this construct, we use the <first_bit> field to indicate the starting point of our data slice. We use the <last_bit> field to indicate the last bit to include in our data slice.

The code snippet below shows how we can access single bits and slices of our data when using the sc_lv data type. We can also simulate this example on EDA playground.

// Declare a 4 bit sc_lv data type
sc_lv<4> example_lv = "1010";

// Set bit 0 to 1b
xample_lv[0] = "1";

// Set bits 3 to 1 to 010b
example_lv(3,1) = "010";

sc_lv Methods

The sc_lv data type comes with a number of in built methods which we can use in our SystemC code.

We can use these methods to efficiently perform a number of functions, such as bit shifts or reduction operations.

The table below summarizes the most commonly used sc_lv methods which are available to us.

MethodFunction
lrotate(N)Shift the data left by N bits. The dropped bit is appended to the end of the the variable.
rrotate(N)Shift the data right by N bits. The dropped bit is appended to the beginning of the variable.
reverse()Reverse the order of the bits.
range(START, END)Select a slice of the data from the variable (same as bit slicing)
and_reduce()Reduce the vector to a single bit by performing a logical and of all bits.
or_reduce()Reduce the vector to a single bit by performing a logical or of all bits.
xor_reduce()Reduce the vector to a single bit by performing a logical exclusive or of all bits.

The code snippet below shows an example of how each of these methods is used in practise. This example can also be simulated on EDA playground.

// Declare an sc_lv type
sc_lv<4> example = "0110";
  
// Examples of the sc_lv methods
cout << "lrotate(1) = " << example.lrotate(1) << endl;
cout << "rrotate(2) = " << example.rrotate(2) << endl;
cout << "reverse() = " << example.reverse() << endl;
cout << "range(2,0) = " << example.range(2,0) << endl; 
cout << "and_reduce() = " << example.and_reduce() << endl;
cout << "or_reduce() = " << example.or_reduce() << endl;
cout << "xor_reduce() = " << example.xor_reduce() << endl;

Running this example on EDA playground results in the output below.

lrotate(1) = 1100
rrotate(2) = 0011
reverse() = 1100
range(2,0) = 100
and_reduce() = 0
or_reduce() = 1
xor_reduce() = 0

Exercises

What is the most important difference between the sc_logic type and the bool type?

We can model high impedance and unknown states using the sc_logic type.

Write some code which declares an sc_logic type and assigns it to high impedance.

// Using the SystemC constants
sc_logic example = SC_LOGIC_Z;

// Directly assigning values
sc_logic example = 'z';

Write the code which declares an 8 bit sc_lv data type and assign it the value of 0xFF.

sc_lv<8> example = "11111111";

Which sc_lv method would we use to perform a shift right operation?

We would use the rrotate method to perform a right shift operation.

Enjoyed this post? Why not share it with others.
© 2024 FPGA Tutorial