Access internal regs without declaring them as input/outputs - verilog

How do I access internal regs/signals without declaring them as input/output.
e.g., consider the following block, A & B are placed in TOP block and I need to access int_A from withing block B without declaring it as output in A and input in B.

You can do that by hierarchical reference.
However as far as I know you can only use that in test-benches.(I have never even dared to use that in RTL).
// Top level test-bench
wire int_A;
assign int_A = dut_0.int_A;
dut dut_0 ( // instance of dut
....
);
If inside the dut you have another instance use the same method:
module dut (
);
core core0 (
);
endmodule // dut
A signal inside the core can now be referenced from the top level as:
assign int_A = dut_0.core_0.int_A;

Related

Multi-dimensional array concatenation on module port

I'm trying concatenation of several packed arrays to unpacked array
module temp (
output logic [64-1:0] top_fab_diu_tmu_time_o_0,
output logic [64-1:0] top_fab_diu_tmu_time_o_1,
output logic [64-1:0] top_fab_diu_tmu_time_o_2,
);
temp_v1 u_temp_v1 (
. top_fab_diu_tmu_time ({top_fab_diu_tmu_time_o_0,top_fab_diu_tmu_time_o_1,top_fab_diu_tmu_time_o_2})
);
where module temp_v1 port is defined as unpacked array:
module temp_v1 (
output logic [63:0] top_fab_diu_tmu_time [3],
);
when i run ace compilation (vcs) it failed and generate this error message:
Unpacked array concatenation to output port will be treated as
assignment ;; pattern. Prefix with tick (') to convert to assignment
pattern.
However DC next (Design compiler) PASS
when i change the port assignment on module temp to (add '):
.top_fab_diu_tmu_time('{top_fab_diu_tmu_time_o_0,top_fab_diu_tmu_time_o_1,top_fab_diu_tmu_time_o_2})
VCS compilation- PASS
DC nxt - FAILED with this message:
The construct 'assignment pattern in port connection' is not supported
Since your tools are struggling with this syntax, you can declare another signal to connect directly to the instance port, then assign each 64-bit output separately:
module temp (
output logic [64-1:0] top_fab_diu_tmu_time_o_0,
output logic [64-1:0] top_fab_diu_tmu_time_o_1,
output logic [64-1:0] top_fab_diu_tmu_time_o_2
);
logic [63:0] top_fab_diu_tmu_time [3];
temp_v1 u_temp_v1 (.top_fab_diu_tmu_time (top_fab_diu_tmu_time));
assign top_fab_diu_tmu_time_o_0 = top_fab_diu_tmu_time[0];
assign top_fab_diu_tmu_time_o_1 = top_fab_diu_tmu_time[1];
assign top_fab_diu_tmu_time_o_2 = top_fab_diu_tmu_time[2];
endmodule
This compiles for me on VCS without errors or warnings.

How to connect interface array port to a concatenation of individual interfaces?

I have a module that has, as one of its ports, an unpacked array of an interface. I am trying to connect it to a few different singular interfaces using an assignment pattern, as I would for a simple port.
Doing so results in an error in QuestaSim:
"Expected an interface instance as an actual for 'intf_out'."
What syntactic sugar do I need get this working?
I wrote a small example that shows the issue.
interface example_interface #(
parameter SIZE = 4
);
logic [SIZE-1:0] example_signal;
endinterface
module example_module (
example_interface intf_in,
example_interface intf_out [0:2]
);
assign intf_out[0].example_signal = intf_in.example_signal;
assign intf_out[1].example_signal = intf_in.example_signal;
assign intf_out[2].example_signal = intf_in.example_signal;
endmodule
module example_port_connection ();
example_interface #(.SIZE(3)) a ();
example_interface #(.SIZE(4)) b ();
example_interface #(.SIZE(5)) c ();
example_interface #(.SIZE(6)) d ();
example_module uut (
.intf_in(a),
.intf_out('{b,c,d}) //error here
);
endmodule
This can't be done in SystemVerilog using interfaces. Besides not having any syntax for a concatenation of interfaces, you no longer have an array when each element is a different type.

Using an array of parameters to generate modules

I have a module which stores a bitmap of different characters, that I am planning on using to display text on a matrix. Currently, the bitmap is populated with a memory initialization file, and this file is passed in as a parameter (I have confirmed this working in Quartus and ModelSim).
In order to actually have a lookup table for all the characters, I wanted to make a separate module which has instantiations of the all bitmaps, and selects the correct one based on a character code. These bitmap instantiations are created in a generate block, and they take the correct filename from an array. However, ModelSim doesn't like this. My code is as follows:
module mem_char_disp_lib(
output logic pixel,
input logic [4:0] x,
input logic [5:0] y,
input logic [6:0] code,
input logic clk
);
localparam CHAR_NUM = 26;
logic [CHAR_NUM-1:0] alphabet;
const var [CHAR_NUM-1:0] BITMAPS = {
"/mem/char/A.hex",
"/mem/char/B.hex",
"/mem/char/C.hex",
// ... a lot more declarations here...
"/mem/char/X.hex",
"/mem/char/Y.hex",
"/mem/char/Z.hex"
};
genvar i;
generate
for (i=0; i<CHAR_NUM; i=i+1) begin : mem_char_disp_blocks
mem_char_disp #(.BITMAP(BITMAPS[i])) block (
.pixel(alphabet[i]),
.x, .y, .clk,
.code(i),
.data(1'b0),
.write_en(1'b0)
);
end
endgenerate
always_comb
pixel = alphabet[code];
endmodule
The error ModelSim is giving me is:
The expression for a parameter actual associated with the parameter name ('BITMAP') for the module instance ('block') must be constant.
(referring to the line inside the for loop)
I am not sure why this doesn't work. On a hardware level, it seems like I'm just making a lot of copies of a module, and slightly tweaking each one with a constant parameter known at compile-time. Is there some basic syntax that I'm missing?
Edit: I have also tried the following code, which seems to give a runtime error:
for (i=0; i<CHAR_NUM; i=i+1) begin : mem_char_disp_blocks
parameter [CHAR_NUM-1:0] BITMAPS = {
"/mem/char/A.hex",
// more elements...
"/mem/char/Z.hex"
};
mem_char_disp #(.BITMAP(BITMAPS[i])) block (
.pixel(alphabet[i]),
.x, .y, .clk,
.code(i),
.data(1'b0),
.write_en(1'b0) );
end
The error is Module parameter 'BITMAP' not found for override. (One of these errors for each of the generated modules; CHAR_NUM total.) This doesn't make sense to me, since instantiating a single one directly works just fine (e.g. mem_char_disp #(.BITMAP("/mem/char/A.hex") block /* ... */).
A const variable is not a constant - it is a write-once variable that gets initialized at runtime when the variable gets allocated. You need to us a parameter or localparam to assign to another parameter as you discovered in your update. You also need to fix the dimensions of the array
parameter bit [1:15*8] BITMAPS[26] = {
"/mem/char/A.hex", // 15 8-bit chars
// more elements...
"/mem/char/Z.hex" // 26 elements
};
Can't help you with your last error without seeing the declaration of the module mem_char_disp

verilog set bus equal to array of struct bits

I'm trying to set a bus equal to a bit of a struct, for an array of structs (s.t. the array size == bus size). My struct looks like
typedef struct {
//other stuff
logic valid;
} BFRAME_OUTPUT;
And I've declared the array of structs and bus like
BFRAME_OUTPUT bframe_outs[`BSTACK_SIZE-1:0];
logic [`BSTACK_SIZE-1:0] valid;
I want to do something like either of these to simply make the valid bus equal to the valid bits for the array of structs.
assign valid[`BSTACK_SIZE-1:0] = bframe_outs[`BSTACK_SIZE-1:0].valid;
//
// or
//
for(int i = 0; i < `BSTACK_SIZE; ++i) begin
assign[i] = bframe_outs[i].valid;
end
However I get errors when trying to simulate with vcs:
Error-[XMRE] Cross-module reference resolution error
/modules/branch_stack.sv, 87
Error found while trying to resolve cross-module reference.
token 'bframe_outs'. Originating module 'branch_stack'.
Source info: assign valid[(16 - 1):0] = bframe_outs[(16 - 1):0].valid;
More importantly, there is another error which you have not shown:
Error-[PSNA] Part Select Not Allowed testbench.sv, 14 Part selects
are not allowed on arrays of classes. Source info: assign valid[(5 -
1):0] = bframe_outs[(5 - 1):0].valid; Convert the part select to
refer to each element individually.
As the error points out, you need to convert the assignment to part selection. Here, you can use one of the two ways. Either use logic as reg and use it in always block, or use logic as wire and do some other stuff.
While using it as reg, you need to extract the value in some procedural block. So, just remove the assign statement and use alway_comb. Since you have used logic here, no need to change its datatype.
always_comb
begin
for(int i = 0; i < `BSTACK_SIZE; ++i)
valid[i] = bframe_outs[i].valid;
end
Alternatively, there is a generate block to perform certain things multiple times. Note that by using generate block, you are providing continuous assignments and using logic as wire. Here, you need to provide each bit signal to the wire individually. Here, use generate as follows:
genvar i;
generate
for(i = 0; i < `BSTACK_SIZE; ++i) begin
assign valid[i] = bframe_outs[i].valid;
end
endgenerate
Refer to SystemVerilog IEEE 1800-2012 section 7.2 for structures and this link for generate blocks. I have created a working example at EDAPlayground link.

Assigning an ID number or code to Verilog module

I have designed a module (A) in Verilog and I need to instantiate it four times in a top module. The two modules communicate with each other and some other modules. 'A' sends out some signals which the other instantiation of 'A' should accept. The signals are sent through an interface or a bus. I do not want to complicate the design by incorporating any standard bus protocols. I have created an inout port to avoid having the same type of ports for input as well as output.
Is there any way to assign an id or a code to every instantiation, so that every instantiation checks for that id and accepts the signals coming from a different ID than itself. Right now without the id or a standard bus protocol, the modules are accepting their own signals too which is not supposed to happen.
Here ways you can do this:
Add an ID input port When this port is tided to a constant, at power-up the device can detect its ID. Technically you could do dynamic ID with this, but usually you just connect the port to a constant value. This is the most flexible option, especially if you want your end product to be used as a configurable component.module A ( /* your_ports */, input [1:0] ID );
/* ... code ... */
endmodule
module top;
A inst0 ( .ID(2'd0), .* );
A inst1 ( .ID(2'd1), .* );
A inst2 ( .ID(2'd2), .* );
A inst3 ( .ID(2'd3), .* );
endmodule
Create an ID parameter Simulate to the ID input port except that the value is hard coded and the instance knows the ID value at compile time, before simulation or device power-up. Unique parameter values generate unique modules. If the ID is 0, it will be physically different than an ID with 1. module A #(parameter ID) ( /* your_ports */ );
/* ... code ... */
endmodule
module top;
A #( .ID(0) ) inst0 ( .* );
A #( .ID(1) ) inst1 ( .* );
A #( .ID(2) ) inst2 ( .* );
A #( .ID(3) ) inst3 ( .* );
endmodule
Why don't you set a parameter for each module and use it as an ID? Then set the parameter uniquely for each instance:
module A;
parameter ID = 0; //default value
case (ID)
0: //specific code for ID0
1: //specific code for ID1
2: //specific code for ID2
3: //specific code for ID3
endcase
endmodule
And your top module:
module top;
A #(.ID(0)) inst_0 (...);
A #(.ID(1)) inst_1 (...);
A #(.ID(2)) inst_2 (...);
A #(.ID(3)) inst_3 (...);
endmodule
A couple of other useful points:
You may want to check generate block or vectorized/array module instantiation, which allow you instantiate an array of modules.
Also, notice that in general, each module can see the entire hierarchy. Inside each module, you can access signals using a hierarchical expression:
module A;
reg s;
....
initial $display("The initial value of signal s in instance A_2 is:", top.inst_2.s);
endmodule
Beware though this is not recommended since your module description would be specific to your hierarchy.

Resources