verilog testbench - submodule array writing in a file - verilog

I need to write an array in a file in verilog test bench. the array is declared as below in the module stage1.v (hierarchy picture attached)
wire [WIDTH-1:0] s1_res1_arr[0:LENGTH-1];
it is filled with certain values.
in my testbench i am writing like this
write_file = $fopen("stage1.txt");
for ( i = 0 ; i <= 255 ; i = i+1 )
$fwrite(write_file,"%b \n",FFT_top/stage1/s1_res1_arr[i]);
modelsim is giving the following error
Failed to find 'FFT_top' in hierarchical name '/FFT_top'.
Failed to find 'stage1' in hierarchical name '/stage1'.
Failed to find 's1_res1_arr' in hierarchical name '/s1_res1_arr'.

Okay, I found it myself. It will be done as:
$fwrite(write_file1,"%b \n",uut.FFT_top.stage_1.s1_res1_arr[i]);

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.

Unexpected ";" , expecting ")" near class handle

So, I created my first system Verilog testbench by modifying the tutorial from https://verificationguide.com/systemverilog-examples/systemverilog-testbench-example-01/ ( In this tutorial a memory block is tested, I modified it for a simple AND gate).
There are seven files excluding the DUT file,
environment.sv
interface.sv
transactions.sv
generator.sv
testbench.sv ( topLevel testbench)
driver.sv
test.sv
I used Intel modelsim to compile these files.
While compiling, I got these errors in driver.sv and generator.sv
** Error: (vlog-13069) D:/Altera/Projects/AndGate/testbench/driver.sv(28): near ";": syntax error, unexpected ';', expecting '('.
** Error: (vlog-13069) D:/Altera/Projects/AndGate/testbench/generator.sv(4): near "trans": syntax error, unexpected IDENTIFIER, expecting ';' or ','.
Below are the corresponding files,
driver.sv
`define DRIV_IF mem_vif.DRIVER.driver_cb
class driver;
int num_trans;
virtual mem_intf mem_vif;
mailbox gen2driv;
function new(virtual mem_intf mem_vif, mailbox gen2driv);
this.mem_vif = mem_vif;
this.gen2driv = gen2driv;
endfunction
task reset();
wait(mem_vif.reset);
$display("--------- [DRIVER] Reset Started ---------");
`DRIV_IF.A <= 0;
`DRIV_IF.B <= 0;
`DRIV_IF.C <= 0;
wait(!mem_vif.reset);
$display("--------- [DRIVER] Reset Ended ---------");
endtask
task drive();
transaction trans;
gen2driv.get(trans);
$display("Num transactions : %0d", num_trans);
#(posedge mem_vif.DRIVER.clk);
`DRIV_IF.A <= trans.A;
`DRIV_IF.B <= trans.B;
trans.C = `DRIV_IF.C;
$display("\tA = %0h \tB = %0h \tC = %0h", trans.A, trans.B, `DRIV_IF.C);
num_trans++;
endtask
endclass
generator.sv
class generator;
var rand transaction trans;
mailbox gen2driv;
int repeat_count;
event ended;
function new(mailbox gen2driv, event ended);
this.gen2driv = gen2driv;
this.ended = ended;
endfunction
task main();
repeat(repeat_count) begin
trans = new();
if(!trans.randomize())$fatal("Random Generation failed");
gen2driv.put(trans);
end
-> ended;
endtask
endclass
Please, help me with this...
For future reference, it would really help to point to the line 28 and 4 in the respective files where the error is occurring as well as give the command line used to compile the code. But since I've seen this exact error before, I know it is because you put all of these files separately on your command line and not compiled together as a package.
Modelsim/Questa compiles every SystemVerilog file on the command line as a separate compilation unit. Identifiers declared in one compilation unit cannot be seen by other compilation units. When the generator and driver classes get compiled, it has no idea what transaction means and you get a syntax error. Modules and interfaces names exist in a separate namespace and the syntax where they are referenced allows them to used before their declarations have been compiled.
To remedy this, you could `include all you class files in testbench module, or the normal practice is putting them all in a package and importing the package. There is also a compilation mode where everything on the command line in one compilation unit, but that option is not scaleable as your designer get larger.
I also suggest reading these two posts I wrote:
https://blogs.sw.siemens.com/verificationhorizons/2010/07/13/package-import-versus-include/
https://blogs.sw.siemens.com/verificationhorizons/2009/05/07/programblocks/

design ROM to save filter coefficients in verilog

I want to store filter coefficients(fixed values) in ROM using verilog.Below is the code for ROM using case.
module rom_using_case (
address , // Address input
data , // Data output
read_en , // Read Enable
ce // Chip Enable
);
input [3:0] address;
output [7:0] data;
input read_en;
input ce;
reg [7:0] data ;
always # (ce or read_en or address)
begin
case (address)
0 : data = 10;
1 : data = 55;
2 : data = 244;
3 : data = 0;
4 : data = 1;
5 : data = 8'hff;
6 : data = 8'h11;
7 : data = 8'h1;
8 : data = 8'h10;
9 : data = 8'h0;
10 : data = 8'h10;
11 : data = 8'h15;
12 : data = 8'h60;
13 : data = 8'h90;
14 : data = 8'h70;
15 : data = 8'h90;
endcase
end
endmodule
what does the case block do in the above code?
can i store filter coefficients in data variable in the case block?
can i access those filter coefficients?
As you state the coefficients will be stored in a RAM LUT or in a ROM block.
The code is (somewhat) self-descriptive, the always is sensitive to the address then each time the address changes its value the stored value will be assigned to data, case is the selector for which location of the memory block will be assinged to data.
Your implementation is enough for small filters, but if you need a lot of coefficients it will get hard to maintain.
For this purpose you can use the $readmemh or $readmemb. Those are verilog intrisic tasks.
From: https://www.csee.umbc.edu/~tinoosh/cmpe415/slides/Rom-LUT-verilog.pdf
The $readmemh system task expects the content of the named file to be
a sequence of hexadecimal numbers, separated by spaces or line breaks.
Similarly, $readmemb expects the file to contain a sequence of binary.
Here is a snippet which shows how to use it:
reg [19:0] data_ROM [0:511];
...
initial $readmemh("rom.data", data_ROM);
always #(address)
if (ce & read_en)
d_out = data_ROM[address];
The "rom.data" contains the coefficients in text. For example, in your case:
8'hA
8'h37
8'hF4
8'h0
8'h1
8'hff
8'h11
8'h1
8'h10
8'h0
8'h10
8'h15
8'h60
8'h90
8'h70
8'h90

verilog generate loop assign to iterator width mismatch

I am using a generate loop to instantiate a paramaterizable number of modules, and I want to assign some of the inputs to the module based on the loop iteration. Unfortunately I'm running into issues with synthesis where design compiler says there's an error because the port width doesn't match. Here's what I'm trying to do:
genvar k;
generate
for(k = 0; k < `NUM/2; ++k) begin
cmp2 cmps(
.a (arr[k]),
.b (arr[k+1]),
.a_idx (k), //gives errors about port width mismatch
.b_idx (k+1), //but I can't get it to work any other way
.data_out(data[k]),
.idx_out (idx[k])
);
end
endgenerate
I've also tried using localparams in the loop and assigning a_idx and b_idx to the localparam but I still get the same error under synthesis.
I've tried something like .a_idx((k)[bit_width-1:0]), but that doesn't work either.
Any ideas?
k and k+1 are 32-bit wide, which causes the width mismatch.
Depending on what your synthesis tool supports, you might want to try the following:
Bit slicing:
.a_idx (k[0 +: bit_width])
Cast to bit_width-wide logic:
typedef logic[bit_width-1:0] logicN_t;
// .... //
.a_idx (logicN_t'(k)),
.b_idx (logicN_t'(k+1)),
// .... //

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

Resources