I am looking for the best way to mask a field inside a packed struct.
Imagine you have:
typedef struct packed {
logic [5:0] add;
logic [3:0] data;
logic [1:0] control;
} mytype;
I want to assign to a new signal a signal with the data masked to zero. In my case, the struct has many fields so I prefer not to assign them one by one if possible, like this:
my_type new_signal;
assign new_signal.add = old_signal.add;
assign new_signal.data = '0;
assign new_signal.control = old_signal.control;
I need it to compare the old signal against a different signal, except for 3 fields.
You can do this in procedural code by assigning the whole signal first, then assigning the individual fields you want to mask out.
always_comb begin
new_signal = old_signal;
new_signal.data = '0;
end
Another way is to use 'packed' vector for the struct. If you know your offsets in the struct you can build a mask. In your case the following will work:
new_signal = old_signal & 12'b111111_0000_11;
------------------------------^^^^^^_----_^^
add....data.control
Related
My struct contains parameters that vary per module. I'd like to use this struct to pass input/outputs to these modules. I'm using this for design so it has to be synthesizable and my toolchain doesn't support Interfaces unfortunately.
For example:
`ifdef MY_STRUCTS
`define MY_STRUCTS
typedef struct packed {
logic [PARAMETER_VAL-1:0] field1;
logic [PARAMETER1_VAL-1:0] field2;
} myStruct_t;
`endif
module top #(
parameter PARAMETER_VAL = 8;
parameter PARAMETER1_VAL = 16;
) (
input myStruct_t in_packet,
output myStruct_t out_packet,
);
Unfortunately, this seems to be a chicken-or-egg problem. The struct definition can't be compiled because it relies on the module parameters to define it. However, the input/output declarations can't be declared because it relies on the struct to know what to declare.
Does anyone have a solution to this? Would definitely appreciate suggestions.
Potentially you can also use a parameterized interface.
Disclaimer: the following code works with synopsys but fails with cadence in eda playground. I think that Cadence is in violation of the standard here (They might have fixed it in the latest version).
Anyway, here is the example
interface top_if #(int PARAMETER_VAL = 8, PARAMETER1_VAL = 16) ();
typedef struct packed {
logic [PARAMETER_VAL-1:0] field1;
logic [PARAMETER1_VAL-1:0] field2;
} myStruct_t;
myStruct_t in_packet, out_packet;
modport in (input in_packet);
modport out (output out_packet);
endinterface
module caller();
top_if #(8,16) top_if();
always_comb top_if.in_packet = '{11, 22};
top top(top_if.in, top_if.out);
logic [top_if.PARAMETER1_VAL-1:0] field2;
always_comb field2 = top_if.out_packet.field2;
always #* begin
$display("out.field2=%0d", field2);
end
endmodule
module top(
top_if in,
top_if out
);
logic [in.PARAMETER_VAL-1:0] field1;
always_comb field1 = in.in_packet.field1;
always_comb out.out_packet = '{field1, field1+55};
always #* begin
$display("input.field1=%d", field1);
end
endmodule
Two options:
Instead of passing a list of parameter values, pass a single struct typedef with the field widths you need. You would likely want to use the struct in the upper level anyway.
module upper;
typedef struct packed {
logic [7:0] field1;
logic [16:0] field2;
} myStruct_t;
my_Struct in, out;
lower #(.T(my_Struct_t) ins1 (in, out);
...
endmodule
module lower #(type T) (
input T in_packet,
output T out_packet,
);
...
endmodule
Create the struct type inside the lower level module, but keep the ports as packed arrays. This works because the struct is packed as well.
module top #(
parameter PARAMETER_VAL = 8;
parameter PARAMETER1_VAL = 16;
) (
input logic [PARAMETER_VAL+PARAMETER_VAL1-1:0] in,
output logic [PARAMETER_VAL+PARAMETER_VAL1-1:0] out,
);
typedef struct packed {
logic [PARAMETER_VAL-1:0] field1;
logic [PARAMETER1_VAL-1:0] field2;
} myStruct_t;
myStruct_t in_packet, out_packet;
assign in_packet = in;
assign out = out_packet;
I have the following structs:
typedef struct packed {
type1_t info1;
type2_t info2;
} module_info_registers_t;
typedef struct packed {
logic [0:0] data1;
logic [2:0] data2;
logic [11:0] data3;
logic [15:0] data4;
} info1;
typedef struct packed {
logic [1:0] data1;
logic [3:0] data2;
logic [10:0] data3;
logic [14:0] data4;
} info2;
As you can see, type1_t and type2_t are defined as 32-bit data structures.
I want to instantiate the following:
module_info_registers_t myregs;
and I want to access the registers based on index (rather than having to type myreqs.info2.data4):
myregs[1].data4
This is because the definition of module_info_registers_t will change from time to time and is autogenerated, so I don't want to hardcode 'info2' in my RTL
However, I am getting an error saying that I can't have a slice on a scalar object.
I understand that for some reason I can't access the data in the way I want to. Is there another way I can do what I am trying to achieve?
There is no way in verilog to do what you want. You might get around using macros, or bit-level access to the struct fields.
Macros can be done like this:
`define ACCESS_REG(R, NUM) R.info``NUM
module_info_registers_t regs;
`ACCESS_REG(regs, 1).data1 = 0;
The above will work, assuming certain naming conventions applied to the fields.
with bit-level access you need to be able to calculate offset and width of every struct member, making declaration and usage more complicated. Here is a very simplified System Verilog example for clarity:
typedef struct packed {
logic [1:0] f1;
logic [2:0] f2;
logic [3:0] f3;
} sp_t;
sp_t sp;
sp[$bits(sp.f3) + $bits(sp.f2) +: $bits(sp.f3)] = 2'b10;
The above example will set 'sp.f1'.
So, in your case you can create arrays of parameters describing offset and widths of the corresponding fields and use them for indexing. So, something like that might work in your case:
parameter int info[2] = {0, 32};
parameter int data1Offset[2] = {31, 30};
parameter int data1Width[2] = {1, 2};
module_info_registers_t regs;
regs[info[1] + data1Offset[1] +: data1Width[1]] = 0;
I am trying to change a c++ code into verilog HDL.
I want to write a module that changes one of its inputs. (some how like call by reference in c++)
as I know there is no way to write a call by reference module in verilog (I can't use systemverilog)
Here is a code that I wrote and it works. are there any better ways to do this?!
my problme is that the register I want to be call by reference is a big array. this way duplicates the registers and has a lot of cost.
module testbench();
reg a;
wire b;
reg clk;
initial begin
a = 0;
clk = 0;
#10
clk = 1;
end
test test_instance(
.a(a),
.clk(clk),
.aOut(b)
);
always#(*)begin
a = b;
end
endmodule
module test(
input a,
input clk,
output reg aOut
);
always #(posedge clk) begin
if (a == 0)begin
a = 1;
aOut = a;
end
end
endmodule
Verilog is not a software programming language; it is a hardware description language. The inputs to a module are pieces of metal (wires, tracks, pins); the outputs from a module are pieces of metal. If you want a port that is both an input and an output you can use an inout. However, inout ports are best avoided; it is usually much better to use separate inputs and outputs.
A Verilog module is not a software function. Nothing is copied to the inputs; nothing is copied from the outputs. A Verilog module is a lump of hardware: it has inputs (pieces of metal carrying information in) and outputs (pieces of metal carrying information out).
Your are right to say that you can use either pass-by-copy or pass-by-reference in SystemVerilog. If you wish to pass a large data structure into a function or into/out of a task, then passing by reference may save simulation time.
By reference means by address, so to translate this to hdl directly you would either need to provide a way for the module to get on that bus and perform transactions based on that address.
Or better, if you need this as an input take each of the items in the struct and make individual inputs from them. If it is pass by reference because it is an output or is also an output, then you create individual outputs for each of the items in the struct. The module then distinguishes between the input version of that sub item and output version of that sub item.
my.thing.x = my.thing.x + 1;
becomes something like
my_thing_x_output = my_thing_x_input + 1;
I would like to write a module with a variable number of inputs, i.e. depending on some parameter, the result would be:
module my_module #(LENGTH)(
input clk,
input rst_n,
input [LENGTH-1:0] data_1
);
//...
endmodule
or
module my_module #(LENGTH)(
input clk,
input rst_n,
input [LENGTH-1:0] data_1,
input [LENGTH-1:0] data_2,
input [LENGTH-1:0] data_3
);
//...
endmodule
Would it be possible to do this in Verilog or Systemverilog or would I have to write a script, let's say in Python, in order to generate the code for a specific module with fixed number of inputs? (it might be more than 1000 inputs)
There are no variable number of ports in SystemVerilog, but you could use a port that is a parameterized array.
module my_module #(int LENGTH, DEPTH)(
input clk,
input rst_n,
input [LENGTH-1:0] data[DEPTH]
);
//...
endmodule
Otherwise, you would need to use a script to generate the code.
Use a two dimensional input with a parameterized size. Added a generate for loop that can be used to set signals individually. Although many operations can be done with smart array operations.
module my_module #(SIZE, LENGTH)(
input clk,
input rst_n,
input [SIZE-1:0][LENGTH-1:0] data_in_array,
output [SIZE-1:0][LENGTH-1:0] data_out_array
);
genvar N;
generate for (N=0; N<SIZE; N++) begin :la_coolOps
//Do cool operations here. For example instantiate a module for every data_in
end
//...
endmodule
Edit:
As Mehran Torki points out: The syntax above will work for SystemVerilog only. Verilog does not allow for multiple packed arrays. Use input [LENGTH*SIZE-1:0] data_in_array.
I would add to these other answers that ports are just groupings of wires. While having 3, 1-bit wires named a, b, and c might be easier to read and understand, there is no physical/logical difference between a single, 3-bit wire abc, where abc[0] corresponds to a, abc[1] corresponds to b, and abc[2] corresponds to c.
So, you can always just expand or shrink a single (or multiple) signal(s) to get however many bits you need. It may not be as neat, but it will work. In the receiving module, you can then part-select the bus in whatever manner you like. So, you could have one really long wire the shrinks or expands (wire [(SOME_PARAM*8)-1:0] my_input_wire), or with SystemVerilog an array (wire [7:0] my_input_wire[0:SOME_PARAM-1])
If this is just testbench/verification code, the other thing you could do in SystemVerilog is use a dynamic array
As others said, there is no direct way to do this, but another workaround is to use SystemVerilog interfaces, where you define all the inputs that you want in the interface definition and inside the module only use the ones that correspond to the parameter. Below is a sample:
module my_module #(LENGTH)(
input clk;
input rst_n;
output o;
interface i_data;
);
logic outValue;
generate
case (LENGTH) //Based on the value of LENGTH, use corresponding data
1: outValue = i_data.data_1;
2: outValue = i_data.data_1 + i_data.data_2;
3: outValue = i_data.data_1 + i_data.data_2 + i_data.data_3;
endcase
endgenerate
always #(posedge clk) begin
if (~rst_n)
o <= '0;
else
begin
o <= outValue;
end
endmodule
You can still use a parameterized array for data and a for-generate loop if your outputs are similar.
With System verilog we can import a package instead of having parameterization and define types in the package to be used in the portlist.
module mymodule
import mymodule_pkg::*;
(
input portlist_t portlist
);
endmodule
And define multiple copies of the package with different variants of the port list and compile whichever version is required. eg
package mymodule_pkg;
localparam LENGTH=5;
typedef struct packed {
logic [LENGTH-1:0] data_1,
logic [LENGTH-1:0] data_2,
logic [LENGTH-1:0] data_3
} portlist_t;
endpackage
As with the interface solution there will be situations where you run into issues, like having different iterations of the module instantiated together.
From testbench, I have to corrupt a bus in design.
I am using a random variable to select a bit location (bit_sel)
bit_sel = $urandom_range(0,MAX_LENGTH-1);
Bus is somewhere deep inside the RTL with a width of MAXLENGTH.
wire [MAX_LENGTH-1:0] BUS_TO_BE_FORCED;
In TB, I am using following line to corrupt the bus:
force TOP.DUT.....BUS_TO_BE_FORCED[bit_sel] = ~TOP.DUT.....BUS_TO_BE_FORCED[bit_sel];
But, I am getting compilation error. What is the best way to do this? I want to flip only one bit.
You could instead flip the bits using a XOR mask:
wire [MAX_LENGTH-1:0] corrupt_bits = 1 << $urandom_range(0,MAX_LENGTH-1);
force BUS_TO_BE_FORCED = corrupt_bits ^ BUS_TO_BE_FORCED;
The LHS must be a constant bit-select of a vector net (among other things). So,
force TOP.DUT.....BUS_TO_BE_FORCED[0]
is Ok, but
force TOP.DUT.....BUS_TO_BE_FORCED[bit_sel]
isn't. You could try a big case statement, because the selectors don't have to be constant:
case(bit_sel)
0: force TOP.DUT.....BUS_TO_BE_FORCED[0] = ...
...etc
EDIT: the initial answer contained my guesses, along with completely wrong information. I should not have answered this question in the first place, therefore I had to write test-benches and confirm the following statements to compensate for the mess.
1) Bit select must be a constant (at compile time). Even the following code (perfectly reasonable in my opinion) won't pass elaboration:
integer bit_sel;
initial begin
bit_sel = 0;
force BUS_TO_BE_FORCED[bit_sel] = 1'b1;
end
2) If used inside "initial" block, the following statement is fine:
force BUS_TO_BE_FORCED[SOME_PARAM] = ~BUS_TO_BE_FORCED[some_index];
SOME_PARAM is a parameter
some_index may be a variable or a net
SOME_PARAM = some_index
However, the same statement inside "always" block causes the simulation to hang. This issue may be resolved by adding delay:
#1 force BUS_TO_BE_FORCED[SOME_PARAM] = ~BUS_TO_BE_FORCED[some_index];
3) The answer by Eric is a very elegant way around language's limitations, but it is also subject to limitations described in section 2 above - you'll have to add delay if you want to use it in "always" block.
I had a similar problem and resorted to using another vector of equal width to the signal to be corrupted. I also encapsulated this in an interface so that I could bind it to any part of the DUT as necessary. Refer to the code below:
import uvm_pkg::*;
`include "uvm_macros.svh"
interface sync_signal_fault_injector #(
parameter int SIGNAL_WIDTH = 1
) (
input clk,
input reset,
input [SIGNAL_WIDTH-1:0] signals
);
bit [SIGNAL_WIDTH-1:0] toggle_bits = '0;
class sync_signal_fault_injector_c extends uvm_object implements fivip_pkg::Injectable;
function new(string name="fault_injector");
super.new(name);
endfunction
virtual function int unsigned get_size();
return SIGNAL_WIDTH;
endfunction
virtual task inject(ref int unsigned indices[], input int unsigned delay);
repeat (delay) #(posedge clk);
foreach (indices[id]) begin
int unsigned bit_index = indices[id];
if (bit_index >= get_size()) begin
`uvm_fatal("BOUNDS",
$sformatf("Tried to access bit %0d but signal bus is only of size %0d", id, get_size())
)
end
// Prepare toggle bits
toggle_bits[bit_index] = 1;
end
force signals = signals ^ toggle_bits;
#(posedge clk);
release signals;
// Reset toggle bits
toggle_bits = '0;
endtask
endclass
sync_signal_fault_injector_c fault_injector = new;
endinterface