In this post I will talk about the data types part of the SystemC library.
Here is a list of content if you want to jump to a particular subject:
1. Fixed-precision integer types
1.1 sc_int
1.2 sc_uint
1.3 sc_bigint and sc_biguint
2. Logic and arbitrary width vector types
2.1 sc_logic
2.2 sc_lv<W>
3. Fixed-Point Types
3.1 Fixed-Point Parameters
3.1.1. World length (WL) and Integer Word Length (IWL)
3.1.2. Quantization Mode (QUAT)
3.1.2.1. Quantization for Signed Fixed-Point Numbers
3.1.2.2. Quantization for Unsigned Fixed-Point Numbers
3.1.3. Overflow Mode (OVFW) and Number of Saturation Bits (NBITS)
3.1.3.1. Overflow for Signed Fixed-Point Numbers
3.1.3.2. Overflow for Unsigned Fixed-Point Numbers
3.2 Fixed-Point Classes
1. Fixed-precision integer types
In hardware world it is mandatory to use a precise number of bits when representing a number. This is because the HDL code will be synthesized to a physical implementation in silicon where every register bit takes up area and this costs money.
For example, one might declare in Verilog a 10 bit counter like this:
1 | reg[9:0] counter |
In the software world there is no requirement for such a fine granularity. In the best case we have usually a 8 bit granularity when it comes to data types widths in bits. For example some of the basic data types that we have natively in C language are:
- char– width: >= 8
- int– width: >= 16
- long– width: >= 32
- etc
SystemC comes with a solution for this problem with four parameterized classes.
Signed | Unsigned | |
LENGTH ≤ 64 | sc_int<LENGTH> | sc_uint<LENGTH> |
LENGTH > 64 | sc_bigint<LENGTH> | sc_biguint<LENGTH> |
Let’s see some usage examples.
1.1. sc_int
First, we can take a look at an example for sc_int class:
1 2 3 4 5 6 7 8 9 | //we can initialize the variable by direct assignment sc_int<3> my_a = -1; //we can initialize the variable via its constructor sc_int<4> my_b(2); sc_int<4> result = my_a + my_b; cout << "sc_int: " << my_a << " + " << my_b << " = " << result << endl; |
We can use different styles for initializing our variables. For the code above we will get the following output:
1 | sc_int: -1 + 2 = 1 |
1.2. sc_uint
In the example for sc_uint class we can easily see the overflow effect as we do not have enough bits in the result to store the correct result of the operation:
1 2 3 4 5 6 7 | sc_uint<3> my_a = 3; sc_uint<4> my_b(15); //there is an overflow here as we do not have enough bits to store the correct result sc_uint<4> result = my_a + my_b; cout << "sc_uint: " << my_a << " + " << my_b << " = " << result << endl; |
The output:
1 | sc_uint: 3 + 15 = 2 |
1.3. sc_bigint and sc_biguint
Of course, the other two classes, sc_bigint and sc_biguint are used in exactly the same manner. You can even combine them:
1 2 3 4 5 6 7 8 | sc_biguint<128> my_a = 11; sc_bigint<128> my_b = 3; sc_bigint<128> result = my_a / my_b; //even if the result is 3.666 we are dealing with integers //so the result is truncated down to the closest integer value cout << "sc_biguint & sc_bigint: " << my_a << " / " << my_b << " = " << result << endl; |
As in all integer operations, the result is rounded down to the closest integer:
1 | sc_biguint & sc_bigint: 11 / 3 = 3 |
You can find all these examples on EDA Playground.
Choosing between native C++ types and these SystemC types must be done with care as SystemC types comes with a slower simulation comparing to native C++ types. Here are some guidelines for you to follow when deciding what types to use:
- use these SystemC types if in the end you will use synthesis on your SystemC code
- use these SystemC types to have the overflow effect out of the box
- use the proper SystemC class based on length and signed/unsigned as in the table from the beginning of this chapter
2. Logic and arbitrary width vector types
In a HDL like Verilog or VHDL, despite the fact that they are used for describing digital logic, a modeled bit of information can have more than just two values: ‘0’ or ‘1’. Most commonly you will see that, for example in Verilog, a register might also take some other values like:
- High Impedance – to model a physical wire left unconnected. This is represented as value ‘z’
- Unknown – to model a physical wire which which has an unknown value due to several reasons – one reason being that is can have two driving sources, or that the wire was never assigned. This is represented as value ‘x’
Such multi-value logic is modeled in SystemC by two classes:
- sc_logic – for modeling one bit of information with its four states: ‘0’, ‘1’, ‘x’ and ‘z’
- sc_lv<W> – a parameterized class to model a logic vector
For modeling a purely boolean representation of a bit (two values) there are other two classes:
- sc_bit (deprecated) – for modeling one bit of information with its two states: ‘0’ and ‘1’
- sc_bv
– a parameterized class to model a bit vector
Let’s see some usage examples of these classes.
2.1. sc_logic
There are a lot of ways to initialize a sc_logic class:
- using predefined constants: SC_LOGIC_0, SC_LOGIC_1, SC_LOGIC_X, SC_LOGIC_Z
- using boolean values: true, false
- using special characters: ‘0’, ‘1’, ‘X’ or ‘Z’
- using sc_logic_value_t type: Log_0, Log_1, Log_X or Log_Z
Here is an example that you can also try it for yourself on EDA Playground:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | //one can use the values of constants SC_LOGIC_0, SC_LOGIC_1, SC_LOGIC_X, SC_LOGIC_Z sc_logic val_0 = SC_LOGIC_0; //once can use the boolean values 'true' or 'false' to initialize a sc_logic class sc_logic val_1(true); //one can use the values of the type sc_logic_value_t: Log_0, Log_1, Log_X or Log_Z sc_logic val_x(Log_X); //one can use even the characters '0', '1', 'X' or 'Z' sc_logic val_z('Z'); sc_logic result_a = val_0 & val_1; sc_logic result_b = val_0 | val_1; sc_logic result_c = val_x ^ val_z; cout << val_0 << " & " << val_1 << " = " << result_a << endl; cout << val_0 << " | " << val_1 << " = " << result_b << endl; cout << val_x << " ^ " << val_z << " = " << result_c << endl; |
The output is:
1 2 3 | 0 & 1 = 0 0 | 1 = 1 X ^ Z = X |
There are many operators overloaded for this class so you should be able to cover all your scenarios.
I extracted from the LRM some truth tables for most common operations:
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
2.2. sc_lv<W>
sc_lv<W> is a template class representing a finite logic vector – lv in the name of the class stands for “logic vector”. This class inherits from sc_lv_base so you might want to take a look at this one also to see what API is available for you.
Let’s see some examples on how to use this class:
1 2 3 4 5 6 7 8 9 | sc_lv<4> a_vector = "1101"; sc_lv<4> b_vector(0b1110); //normal bitwise operations can be performed in logic vectors sc_lv<4> c_vector = a_vector & b_vector; cout << "a_vector: " << a_vector << endl; cout << "b_vector: " << b_vector << endl; cout << "c_vector: " << c_vector << endl; |
sc_lv<W> comes with lots of constructors so you can initialize it in the most intuitive way for you.
SystemC developers took fool advantage of the operator overload so normal bitwise operations can be performed on the logic vectors.
Here is the output of the example from above:
1 2 3 | a_vector: 1101 b_vector: 1110 c_vector: 1100 |
You can run the example for yourself on EDA Playground.
One other interesting aspect to mention here is that the base class, sc_lv_base, has a lot of useful functions. Here is an example with most of the available functions:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | sc_lv<4> a_vector = "1101"; cout << "a_vector: " << a_vector << endl; //Bitwise rotations cout << "a_vector.lrotate(1): " << a_vector.lrotate(1) << endl; cout << "a_vector.rrotate(1): " << a_vector.rrotate(1) << endl; //Bitwise reverse cout << "a_vector.reverse(): " << a_vector.reverse() << endl; //Bit selection cout << "a_vector[3]: " << a_vector[3] << endl; //Part selection cout << "a_vector(3,1): " << a_vector(3,1) << endl; cout << "a_vector.range(3,1): " << a_vector.range(3,1) << endl; //Reduce functions //<OPERATION>_reduce() – where <OPERATION> can be: and, nand, or, nor, xor, xnor cout << "a_vector.and_reduce(): " << a_vector.and_reduce() << endl; |
And the output:
1 2 3 4 5 6 7 8 | a_vector: 1101 a_vector.lrotate(1): 1011 a_vector.rrotate(1): 1101 a_vector.reverse(): 1011 a_vector[3]: 1 a_vector(3,1): 101 a_vector.range(3,1): 101 a_vector.and_reduce(): 0 |
You can run the example for yourself on EDA Playground.
3. Fixed-Point Types
Before you continue reading you must make sure you know how fixed-point numbers are represented in binary.
You can take a look at this short YouTube video explaining all you need to know about fixed-point number representation in binary.
IMPORTANT:
In order to have access to fixed point data type classes you must define SC_INCLUDE_FX before you include systemc.h file.
This can be achieved from command line by adding this argument to the compiler: -DSC_INCLUDE_FX
3.1 Fixed-Point Parameters
The SystemC classes used to model the fixed point types have five parameters:
- Word Length (WL)
- Integer Word Length (IWL)
- Quantization Mode (QUAT)
- Overflow Mode (OVFW)
- Number of Saturation Bits (NBITS)
In the next sections of this chapter I will try to explain how these parameters are used.
3.1.1. Word Length (WL) and Integer Word Length (IWL)
World Length represents how many bits are used to represent the entire number – must be positive.
Integer Word Length represents how many bits, out of Word Length, are used to represent the integer part – it can have any integer value.
There are three scenarios for a fixed point representation based on the relationship between WL and IWL:
Scenario #1: 0 <= IWL <= WL
This is the easiest scenario to understand. A representation of a number where WL is 5 and IWL is 3 is this:
i | i | i | f | f |
i = integer bit, f = fractional bit |
Let’s try to understand the range.
If we have to represent an unsigned number the lowest number, represented in binary, is 000.00 and in decimal is 0.
The biggest number, represented in binary, is 111.11 and in decimal is 7.75
If we have to represent a signed number, two’s complement representation is used, so the lowest number in binary is 100.00 and in decimal is -4.
The biggest number, represented in binary, is 011.11 and in decimal is 3.75
Scenario #2: WL < IWL
In this scenario we have more bits to represent the integer part than there are to represent the entire number. Strange right?
In the actual representation the remaining bits (IWL – WL) are all zero.
A representation of a number where WL is 5 and IWL is 7 is this:
i | i | i | i | i | 0 | 0 |
i = integer bit |
Let’s try to understand the range.
If we have to represent an unsigned number the lowest number, represented in binary, is 0000000 and in decimal is 0.
The biggest number, represented in binary, is 1111100 and in decimal is 124
If we have to represent a signed number, two’s complement representation is used, so the lowest number in binary is 1000000 and in decimal is -64.
The biggest number, represented in binary, is 0111100 and in decimal is 60
Scenario #3: IWL < 0 < WL
This is the hardest scenario to understand.
In this scenario we have a negative number of bits to represent the integer part. These bits will actually be a copy of the sign bit, for signed representations and zero for unsigned representations.
A representation of a signed number where WL is 5 and IWL is -2 is this:
s | s | f | f | f | f | f |
s = sign bit, f = fractional bit |
A representation of an unsigned number where WL is 5 and IWL is -2 is this:
0 | 0 | f | f | f | f | f |
f = fractional bit |
Let’s try to understand the range.
If we have to represent an signed number, two’s complement representation is used, so the lowest number, represented in binary, is .1110000 and in decimal is -0.125
The biggest number, represented in binary, is .0001111 and in decimal is 0.1171875
If we have to represent a unsigned number the lowest number in binary is .0000000 and in decimal is 0.
The biggest number, represented in binary, is .0011111 and in decimal is 0.2421875
3.1.2. Quantization Mode (QUAT)
Quantization Mode represents the way to handle the case when the precision of an assigned value exceeds the precision of a fixed-point variable.
For example, let’s say that we have a fixed point number with WL = 4 and IWL = 2 and it is equal to 0.75 (decimal) and in binary 0011.
If we want to assign it to a fixed point number with WL = 3 and IWL = 2, quantization mode dictates how the rounding shall be performed.
1 2 3 4 5 6 | //this number has two fractional bits sc_fixed<4,2> a = 0.75; //this number has only one fractional bit //quantization algorithm dictates what value b variable will have sc_fixed<3, 2> b = a; |
The quantization modes available in SystemC in the enum sc_q_mode and the possible values are listed in the table below.
Quantization mode | Name |
Rounding to plus infinity | SC_RND |
Rounding to zero | SC_RND_ZERO |
Rounding to minus infinity | SC_RND_MIN_INF |
Rounding to infinity | SC_RND_INF |
Convergent rounding | SC_RND_CONV |
Truncation | SC_TRN |
Truncation to zero | SC_TRN_ZERO |
Quantization modes |
3.1.2.1. Quantization for Signed Fixed-Point Numbers
Each of the quantization modes available in sc_q_mode has a mathematical formula which is applied in order to do the quantization.
In order to understand those mathematical formulas you need to understand some terminology involved.
Higher precision number | x | x | x | x | x | x | x | x |
Lower precision number | x | x | x | x | x | |||
Flags | sR | R | R | R | lR | mR | D | D |
Flags at bit level applied for quantization algorithms |
The flags in the table above have the following meaning:
- x – a binary digit (0 or 1)
- sR – a sign bit
- R – the remaining bits
- lR – the least significant remaining bit
- mR – the most significant deleted bit
- D – the deleted bits
In the mathematical formulas of the quantization algorithms it is used a symbol r – which is the logical OR between all the bits with flag D.
The table below list all the available quantization modes and how is computed the value to be added to the lower precision numer.
Quantization mode | Expression to be added | Details |
SC_RND | mD | Add the most significant deleted bit to the remaining bits. |
SC_RND_ZERO | mD & (sR | r) | If the most significant deleted bit is 1, and either the sign bit or at least one other deleted bit is 1, add 1 to the remaining bits. |
SC_RND_MIN_INF | mD & r | If the most significant deleted bit is 1 and at least one other deleted bit is 1, add 1 to the remaining bits. |
SC_RND_INF | mD & (! sR | r) | If the most significant deleted bit is 1, and either the inverted value of the sign bit or at least one other deleted bit is 1, add 1 to the remaining bits. |
SC_RND_CONV | mD & (lR | r) | If the most significant deleted bit is 1, and either the least significant of the remaining bits or at least one other deleted bit is 1, add 1 to the remaining bits. |
SC_TRN | 0 | Copy the remaining bits. |
SC_TRN_ZERO | sR & (mD | r) | If the sign bit is 1, and either the most significant deleted bit or at least one other deleted bit is 1, add 1 to the remaining bits. |
Quantization handling for signed fixed-point numbers |
Let’s see some examples for some of the quantization modes.
Rounding to plus infinity (SC_RND)
For this algorithm, the value to be added to the lower precision number is mD – most significant deleted bit.
1 2 3 4 5 6 7 8 9 | //this number has 5 fractional bits sc_fixed<8,3> a = -2.3125; cout << " a in dec: " << a << ", a in bin: "<< a.to_bin() << endl; //this number has 2 fractional bits sc_fixed<5,3, SC_RND> b_sc_rnd = a; cout << "SC_RND - b in dec: " << b_sc_rnd << ", b in bin: "<< b_sc_rnd.to_bin() << endl; |
In this case mD is a[2] = 1 – bit index 2 counting from right to left.
So, b_sc_rnd before adding the value of the quantization algorithm is 0b101.10
Once we add quantization mode value we have b_sc_rnd = 0b101.11
1 2 | a in dec: -2.3125, a in bin: 0b101.10110 SC_RND - b in dec: -2.25, b in bin: 0b101.11 |
You can run the full example on EDA Playground.
Truncation (SC_TRN)
For this algorithm, the value to be added to the lower precision number is 0 so things are much simpler – this is the default quantization mode.
1 2 3 4 5 6 7 8 9 | //this number has 5 fractional bits sc_fixed<8,3> a = -2.3125; cout << " a in dec: " << a << ", a in bin: "<< a.to_bin() << endl; //this number has 2 fractional bits sc_fixed<5,3, SC_TRN> b_sc_rnd = a; cout << "SC_RND - b in dec: " << b_sc_rnd << ", b in bin: "<< b_sc_rnd.to_bin() << endl; |
And the output is:
1 2 | a in dec: -2.3125, a in bin: 0b101.10110 SC_TRN - b in dec: -2.5, b in bin: 0b101.10 |
You can run the full example on EDA Playground.
3.1.2.1. Quantization for Unsigned Fixed-Point Numbers
For unsigned numbers the flags are quite similar with the signed numbers with the only difference that sR no longer exists.
Higher precision number | x | x | x | x | x | x | x | x |
Lower precision number | x | x | x | x | x | |||
Flags | R | R | R | R | lR | mR | D | D |
Flags at bit level applied for quantization algorithms |
The table below list all the available quantization modes and how is computed the value to be added to the lower precision numer.
Quantization mode | Expression to be added | Details |
SC_RND | mD | Add the most significant deleted bit to the left bits. |
SC_RND_ZERO | 0 | Copy the remaining bits. |
SC_RND_MIN_INF | 0 | Copy the remaining bits. |
SC_RND_INF | mD | Add the most significant deleted bit to the left bits. |
SC_RND_CONV | mD & (lR | r) | If the most significant deleted bit is 1, and either the least significant of the remaining bits or at least one other deleted bit is 1, add 1 to the remaining bits. |
SC_TRN | 0 | Copy the remaining bits. |
SC_TRN_ZERO | 0 | Copy the remaining bits. |
Quantization handling for unsigned fixed-point numbers |
3.1.3. Overflow Mode (OVFW) and Number of Saturation Bits (NBITS)
Overflow Mode represents the way to handle the case when the magnitude of an assigned value exceeds the magnitude of a fixed-point variable.
For example, let’s say that we have a fixed point number with WL = 4 and IWL = 3 and it is equal to 5.5 (decimal) and in binary 0b1011.
If we want to assign it to a fixed point number with WL = 3 and IWL = 2 (maximum integer value is only 3), overflow mode dictates how the assignment shall be performed.
1 2 3 4 5 6 | //this number has three integer bits sc_fixed<4,3> a = 5.5; //this number has two integer bits //overflow algorithm dictates what value b variable will have sc_fixed<3, 2> b = a; |
The overflow modes available in SystemC in the enum sc_o_mode and the possible values are listed in the table below.
Overflow Mode | Name |
Saturation | SC_SAT |
Rounding to zero | SC_SAT_ZERO |
Symmetrical saturation | SC_SAT_SYM |
Wrap-around | SC_WRAP |
Sign magnitude wrap-around | SC_WRAP_SM |
Overflow modes |
3.1.2.1. Overflow for Signed Fixed-Point Numbers
Each of the overflow modes available in sc_o_mode has a mathematical formula which is applied in order to do the overflow.
In order to understand those mathematical formulas you need to understand some terminology involved.
Higher precision number | x | x | x | x | x | x | x | x | x | x |
Lower precision number | x | x | x | x | x | x | ||||
Flags | sD | D | D | lD | sR | R(N) | R(lN) | R | R | lR |
Flags at bit level applied for overflow algorithms |
The flags in the table above have the following meaning:
- x – a binary digit (0 or 1)
- sD – a sign bit before overflow handling
- D – deleted bits
- lD – the least significant deleted bit
- sR – the bit on the MSB position of the result number. For the SC_WRAP_SM, 0 and SC_WRAP_SM, 1 modes, a distinction is made between the original value (sRo) and the new value (sRn) of this bit
- N – the saturated bits. Their number is equal to the n_bits argument minus 1
- lN – the least significant saturated bit
- R – the remaining bits
- lR – the least significant remaining bit
The table below list all the available overflow modes and how the result is computed.
Overflow mode | sR | N, lN | R, lR | Details |
SC_SAT | sD | !sD | The result number gets the sign bit of the original number. The remaining bits shall get the inverse value of the sign bit. | |
SC_SAT_ZERO | 0 | 0 | All bits shall be set to zero. | |
SC_SAT_SYM | sD | !sD | The result number shall get the sign bit of the original number. The remaining bits shall get the inverse value of the sign bit, except the least significant remaining bit, which shall be set to one. | |
SC_WRAP, n_bits = 0 | sR | x | All bits except for the deleted bits shall be copied to the result. | |
SC_WRAP, n_bits = 1 | sD | x | The result number shall get the sign bit of the original number. The remaining bits shall be copied from the original number. | |
SC_WRAP, n_bits > 1 | sD | !sD | x | The result number shall get the sign bit of the original number. The saturated bits shall get the inverse value of the sign bit of the original number. The remaining bits shall be copied from the original number. |
SC_WRAP_SM, n_bits = 0 | lD | x ^ sRo ^ sRn | The sign bit of the result number shall get the value of the least significant deleted bit. The remaining bits shall be XOR-ed with the original and the new value of the sign bit of the result. | |
SC_WRAP_SM, n_bits = 1 | sD | x ^ sRo ^ sRn | The result number shall get the sign bit of the original number. The remaining bits shall be XOR-ed with the original and the new value of the sign bit of the result. | |
SC_WRAP_SM, n_bits > 1 | sD | !sD | x ^ lNo ^ !sD | The result number shall get the sign bit of the original number. The saturated bits shall get the inverse value of the sign bit of the original number. The remaining bits shall be XOR-ed with the original value of the least significant saturated bit and the inverse value of the original sign bit. |
Overflow handling for signed fixed-point numbers | ||||
Let’s see an example.
Saturation (SC_SAT)
1 2 3 4 5 6 7 8 9 | //this number has 4 integer bits sc_fixed<6,4> a = -7; cout << " a in dec: " << a << ", a in bin: "<< a.to_bin() << endl; //this number has 2 integer bits sc_fixed<4,2, SC_RND, SC_SAT> b_sc_sat = a; cout << "SC_SAT - b in dec: " << b_sc_sat << ", b in bin: "<< b_sc_sat.to_bin() << endl; |
In this case sR = sD so it is a[5] = 1.
R = !sD so it is 0.
1 2 | a in dec: -7, a in bin: 0b1001.00 SC_SAT - b in dec: -2, b in bin: 0b10.00 |
You can run the full example on EDA Playground.
3.1.2.2. Overflow for Unsigned Fixed-Point Numbers
For unsigned numbers the flags are quite similar with the signed numbers with the only difference that sD, sR and lR no longer exists
Higher precision number | x | x | x | x | x | x | x | x | x | x |
Lower precision number | x | x | x | x | x | x | ||||
Flags | D | D | D | lD | R(N) | R | R | R | R | R |
Flags at bit level applied for overflow algorithms |
The table below list all the available overflow modes and how the result is computed.
Overflow mode | N | R | Details |
SC_SAT | 1 (overflow) 0 (underflow) | The remaining bits shall be set to 1 (overflow) or 0 (underflow). | |
SC_SAT_ZERO | 0 | The remaining bits shall be set to 0. | |
SC_SAT_SYM | 1 (overflow) 0 (underflow) | The remaining bits shall be set to 1 (overflow) or 0 (underflow). | |
SC_WRAP, n_bits = 0 | x | All bits except for the deleted bits shall be copied to the result number. | |
SC_WRAP, n_bits > 0 | 1 | x | The saturated bits of the result number shall be set to 1. The remaining bits shall be copied to the result. |
SC_WRAP_SM | Not defined for unsigned numbers. | ||
Overflow handling for unsigned fixed-point numbers | |||
3.2 Fixed-Point Classes
Now that we have a clear understanding on how these fixed-point numbers are represented we can take a look at the classes used for modeling fixed-point numbers:
Let’s look over the differences between these classes.
The ones with “fast” are called limited-precision fixed-point types. They are faster than the other ones due to the fact that internal implementation takes use of the double primitive. These types can not be bigger than 53 bits.
The ones with “u” are unsigned.
The ones with “fixed” (past tense) are template classes and you can set all the parameters via variable declaration.
The other ones, with “fix” are regular C++ classes for which you can set the parameters via their constructors or via parameters context.
Let’s see an example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | //first argument is WL and second argument is IWL sc_fixed<5,3> a_fixed = 1.75; cout << "a_fixed: " << a_fixed << endl; //for "fix" class you can specify via its constructor WL and IWL sc_fix a_fix(5, 3); a_fix = 1.75; cout << "a_fix: " << a_fix << endl; //however for "fix" classes the parameters can be set via a context sc_fxtype_params params(5,4); sc_fxtype_context context(params); //because we do not specify in b_fix constructor anything //the parameters are taken from the latest created context sc_fix b_fix; b_fix = 1.75; //b_fix is 1.5 because we configured the context with WL = 5 and IWL = 4 //leaving only one bit for fractional value cout << "b_fix: " << b_fix << endl; //even if we set the context earlier we can use the constructor to //hard code the arguments sc_fix c_fix(5,3); c_fix = 1.75; cout << "c_fix: " << c_fix << endl; |
This produce the following output:
1 2 3 4 | a_fixed: 1.75 a_fix: 1.75 b_fix: 1.5 c_fix: 1.75 |
Pay attention to the comments in the example as I tried to explain there how WL and IWL are attributed to each variable.
You can run the example on your own on EDAPlayground.
Next Lesson: Learning SystemC: #002 Module – sc_module
Previous Lesson: Learning SystemC: #000 Learning Materials and Initial Setup
reversed description for signed and unsigned fixed point representation for scenario 3. Also wrong sign for scenario 3: IWL< 0 < WL
You are right. thank you for the feedback! I did the changes in the article.
Under Section 3.1.2.1. Quantization for Signed Fixed-Point Numbers, I think you meant mD and not mR.