When using `typedef`: Where to place array indication? [duplicate] - system-verilog

This question already has answers here:
packed vs unpacked vectors in system verilog
(7 answers)
Closed 5 years ago.
When using typedef to declare a userdefine type, then both these forms are accepted by ModelSim:
typedef logic logic_7_0_t [7:0];
typedef logic [7:0] logic_7_0_t;
However, if doing something similar based on real type, then 2nd format fails:
typedef real real_3_0_t [3:0];
typedef real [3:0] real_3_0_t; // Syntax error by ModelSim
Where to place the array indication, and why the difference between logic and real?

Based on the references to duplicate answers, my conclusion is that:
typedef logic logic_7_0_t [7:0]; // Unpacked array of logic, which is OK
typedef logic [7:0] logic_7_0_t; // Packed array of logic, which is OK
typedef real real_3_0_t [3:0]; // Unpacked array or real, which is OK
typedef real [3:0] real_3_0_t; // Would be packed array of real, which is not illegal

Related

Is a struct packed allowed to be used in ports?

Most of the tools I use allow it but one doesn't. I've read the specs, IEEE1800-2017 I couldn't find it.
module mymod (
input logic clk,
input logic reset,
input struct packed {
logic [1:0] var0;
logic [1:0] var1;
logic [8:0] var2;
} addr,
...
I saw some examples here and there, using even typedef structures in ports.
Is it allowed by the specs? Where?
Cf. 7.2 Structures and 7.2.1 Packed structures
A port can be any data type. (section 23.2.2) There are some restrictions on whether that datatype can be represented by a variable or net signal that interact with the port direction.
But I would strongly discourage the use of an anonymous type (struct in your example) and instead declare a user defined type with a typedef in a common package and use that typedef when declaring that port. That eliminates type compatibility issues when trying to connect unpacked struct and enums.

Is signed type valid for each element using typedef + packed array (v.s. multidimensional packed array)

I have a question about signed property with multiple packed dimensions which is defined in stages with typedef.
Basically,
logic signed [1:0][2:0] foo;
* foo[0] is not signed (signed is meaningless if you expect signed element) because all entire packed array is signed but each element is not signed.
But,
typedef logic signed [1:0] foo_t;
foo_t [2:0] foo;
* foo[0] is signed. What a strange..
Q1> What happens? Why is it signed??
Q2> Is it same declaration with
logic signed [1:0][2:0] foo; // ??
Q3> LRM says that [1:0] index varies most rapidly, which is not my expectation.
logic signed [2:0][1:0] foo; //??
This is an artifact of the allowed syntax(BNF). The signed keyword applies signedness to the identifier as a whole, not to the individual elements (logic) you are packing. There's no syntax that allowes you to control the signedness of each dimension except by the typedef stages you discovered.
When you create a multidimensional array in stages, each dimension you add varies less rapidly than the previous. So dimensionally, your typedef is equivalent to
logic signed [2:0][1:0] foo;
foo_t [2:0] foo; // the [2:0] gets added to the left of [1:0]
If use an unpacked array, we can also keep signed property for each element.
logic signed [1:0] foo [2:0];
But, it seems that array of typedef with unpacked array is not supported by systemverilog.
typedef logic signed data_t [3:0];
data_t [2:0] foo;
When I try this, compiler shows an error
“illegal element type for a vector (vector element type must be an integral type)”. - you may leave any comment for this.
Anyway, thanks for your answer.

Passing a struct as a parameter in System Verilog

The following code works fine under Modelsim when the unused localparam is removed. It produces the error below if it is left in. If it is possible to use a struct to pass parameters to a module, what am I doing wrong? Many thanks.
typedef bit [7:0] myarr[2];
typedef struct { int a; myarr bytes; } mystruct;
module printer #(mystruct ms)();
// works fine if this is removed
localparam myarr extracted = ms.bytes;
initial
$display("Got %d and %p", ms.a, ms.bytes);
endmodule
parameter mystruct ms = '{ a:123, bytes:'{5, 6}};
module top;
printer #(.ms(ms)) DUT ();
endmodule
Here is the error. Compilation using vlog -sv -sv12compat produces no errors or warnings.
$ vsim -c -do "run -all; quit" top
Model Technology ModelSim - Intel FPGA Edition vlog 10.5c Compiler 2017.01 Jan 23 2017
(.......)
# ** Error: (vsim-8348) An override for an untyped parameter ('#dummyparam#0') must be integral or real.
I think the problem here is that you are assigning a whole unpacked array in one statement, which is not allowed. Try changing the myarr typedef to a packed array instead.
My workaround was to use a packed array. I didn't need to pack the whole struct.
I would happily upvote/accept someone else's answer if one appears. In particular, it would be helpful to confirm whether this is really a bug in Modelsim, or just an instance of a correct compilation error that could be made more helpful by including the location and parameter name.

How do I sign extend in SystemVerilog?

Below is the code I have for my module:
module sext(input in[3:0], output out[7:0]);
always_comb
begin
if(in[3]==1'b0)
assign out = {4'b0000,in};
else
assign out = {4'b1111,in};
end
endmodule
For some reason this is not working. Instead of sign extending it is zero extending. Any ideas to why this might be the case?
I'm going to assume you meant (input [3:0] in, output [7:0] out). If that is true, then all you needed to write is
module sext(input signed [3:0] in, output signed [7:0] out);
assign out = in;
endmodule
You could also write
module sext(input [3:0] in, output [7:0] out);
assign out = 8'(signed'(in));
endmodule
And perhaps you don't even need to write this as a separate module.
Few things you need to take care is,
you haven't declared a data type for in and out, so by default they are wire and wire can't be used at LHS inside procedural block. Refer Section 6.5 Nets and variables (SV LRM 1800-2012). So either use a continuous assignment or declare it as a variable (i.e. reg/logic etc.).
The assignment of unpacked array is illegal in your example, so either use packed array or follow the instructions given in Section 10.10 Unpacked array concatenation (SV LRM 1800-2012)
It is not illegal syntax but assign used inside an always block probably does not do what you think it does. Use assign for wires and do not use it inside initial or always.
You have defined your port ranges after the name, this results in 4 and 8 1-bit arrays rather than a 4 and 8 bit value.
You have used {} for concatination, but they can also be used for replication ie {4{1'b1}}.
module sext(
input [3:0] in,
output reg [7:0] out ); //ranged defined before name
//No assign in always
//concatenation with replication
always_comb begin
out = { {4{in[3]}}, in};
end
endmodule
Or :
module sext(
input [3:0] in,
output [7:0] out ); //out left as wire
assign out = { {4{in[3]}}, in};
endmodule
I have seen your code.
There are some mistake in your code that you have to take care whiling writing the code.
You have use unpacked array so your targeted elements and actual elements are not match.
ERROR : Number of elements in target expression does not match the number of
elements in source expression.
This error can solve by using packed array.So, your targeted elements and actual elements are matched.
Here is link from where you will get better understanding regarding packed and unpacked array.
LINK : [http://www.testbench.in/SV_09_ARRAYS.html][1]
2.Another thing that you have to take care is you are storing some value in out signal(variable) like assign out = {4'b0000,in};
So you have to use reg data type to sore the value.
ERROR : Non reg type is not valid on the left hand side of this assignment
When you use reg data type then you can store value in out data type.
So, your problem is solved.
Here I also provide code which will run fine.
module sext(input [3:0]in, output reg [7:0]out);
always_comb
begin
if(in[3]==1'b0)
assign out = {4'b0000,in};
else
assign out = {4'b1111,in};
end
endmodule

Problems with using delphi dta types with a C DLL

I am trying to use a .dll which has been written in C (although it wraps around a matlab .ddl)
The function I am trying to use is defined in C as:
__declspec(dllexport) int ss_scaling_subtraction(double* time, double** signals, double* amplitudes, int nSamples, int nChannels, double* intensities);
The .dll requires, amongst others, a 2 dimensional array - When I tried to use:
Array of array of double
In the declaration, the compiler gave an error so I defined my own data type:
T2DArray = Array of array of double;
I initialise the .dll function in a unit like so:
function ss_scaling_subtraction(const time: array of double; const signals: T2DArray; const amplituides : array of double; const nSamples: integer;const nChannels: integer; var intensities: array of double) : integer ; cdecl; external 'StirScanDLL.dll';
However, when called this function, I get an access violation from the .dll
Creating a new data type
T1DArray = array of double
and changing
Array of double
To
T1DArray
In the declaration seems to make things run but the result is still not correct.
I have read on here that it can be dangerous to pass delphi data types to .dll's coded in a different language so I thought this might be causing the issue.
But how do I NOT use a delphi data type when I HAVE to use it to properly declare the function in the first place?!
Extra Info, I have already opened the matlab runtime complier lib's and opened the entry point to the StirScanDLL.dll
The basic problem here is one of binary interop mismatch. Simply put, a pointer to an array is not the same thing at a binary level as a Delphi open array parameter. Whilst they both semantically represent an array, the binary representation differs.
The C function is declared as follows:
__declspec(dllexport) int ss_scaling_subtraction(
double* time,
double** signals,
double* amplitudes,
int nSamples,
int nChannels,
double* intensities
);
Declare your function like so in Delphi:
function ss_scaling_subtraction(
time: PDouble;
signals: PPDouble;
amplitudes: PDouble;
nSamples: Integer;
nChannels: Integer;
intensities: PDouble
): Integer; cdecl; external 'StirScanDLL.dll';
If you find that PPDouble is not declared, define it thus:
type
PPDouble = ^PDouble;
That is, pointer to pointer to double.
Now what remains is to call the functions. Declare your arrays in Delphi as dynamic arrays. Like this:
var
time, amplitudes, intensities: TArray<Double>;
signals: TArray<TArray<Double>>;
If you have an older pre-generics Delphi then declare some types:
type
TDoubleArray = array of Double;
T2DDoubleArray = array of TDoubleArray;
Then declare the variables with the appropriate types.
Next you need to allocate the arrays, and populate any that have data passing from caller to callee.
SetLength(time, nSamples); // I'm guessing here as to the length
SetLength(signals, nSamples, nChannels); // again, guessing
Finally it is time to call the function. Now it turns out that the good designers of Delphi arranged for dynamic arrays to be stored as pointers to the first element. That means that they are a simple cast away from being used as parameters.
retval := ss_scaling_subtraction(
PDouble(time),
PPDouble(signals),
PDouble(amplitudes),
nSamples,
nChannels,
PDouble(intensities)
);
Note that the casting of the dynamic arrays seen here does rely on an implementation detail. So, some people might argue that it would be better to use, for instance #time[0] and so on for the one dimensional arrays. And to create an array of PDouble for the amplitudes and copy over the addresses of the first elements of the inner arrays. Personally I am comfortable with relying on this implementation detail. It certainly makes the coding a lot simpler.
One final piece of advice. Interop can be tricky. It's easy to get wrong. When you get it wrong, the code compiles, but then dies horribly at runtime. With cryptic error messages. Leading to much head scratching.
So, start with the simplest possible interface. A function that receives scalar parameters. Say, receives an integer, and returns an integer. Prove that you can do that. Then move on to floating point scalars. Then one dimensional arrays. Finally two dimensional arrays. Each step along the way, build up the complexity. When you hit a problem you'll know that it is down to the most recently added parameter.
You've not taken that approach. You've gone straight for the kill and implemented everything in your first attempt. And when it fails, you've no idea where to look. Break a problem into small pieces, and build the more complex problem out of those smaller pieces.