I have an array that I want to load up from a binary file:
parameter c_ROWS = 8;
parameter c_COLS = 16;
reg [15:0] r_Image_Raw[0:c_ROWS-1][0:c_COLS-1];
My input file is binary data, 256 bytes long (same total space as r_Image_Raw). I tried using $fread to accomplish this, but it only works through the 4th column of the last row:
n_File_ID = $fopen(s_File_Name, "r");
n_Temp = $fread(r_Image_Raw, n_File_ID);
I also tried using $fscanf for this, but I get an error about packed types when opening the synthesis tool:
while (!$feof(n_File_ID))
n_Temp = $fscanf(n_File_ID, "%h", r_Image_Raw);
I feel like this should be easy to do. Do I have create a 2D for loop and loop through the r_Image_Raw variable, reading in 16 bits at a time? I feel like it should not be that complicated.
I realized my mistake. It should be:
n_File_ID = $fopen(s_File_Name, "rb");
n_Temp = $fread(r_Image_Raw, n_File_ID);
I was using "r" and not "rb" to specify that it was a binary file. Interestingly enough, "r" does work for the majority of the data, but it is unable read in the last ~13 locations from the file.
Try this.
f_bin = $fopen(s_File_Name,"rb");
for (r = 0; r < c_ROWS; r = r+1) begin
for (c = 0; c < c_COLS; c = c+1) begin
f = $fread(r16,f_bin);
r_Image_Raw[r][c] = r16;
end
end
See that $fread(r16,f_bin) first param is reg, second - file!
Below an example for reading from a binary file with systemverilog.
As shown in IEEE SV Standard documentation, the "nchar_code" will return the number of bytes/chars read. In case EOF have been already reached on last read this number will be zero.
Please, notice that "nchar_code" can be zero but EOF has not been reached, this happens if you have spaces or returns at the end of the data file.
You can control the number of bytes to be read with the $fread function. This is done with the type definition of the "data_write_temp" or "mem" of the below examples. If the "data_write_temp" variable is 16bits long then it will read 16bits each time the $fread is called. Besides, $fread will return "nchar_code=2" because 16bits are 2bytes. In case, "data_write_temp" is 32bits as in the example, the $fread will read nchar_code=4bytes(32bits). You can also define an array and the $fread function will try to fill that array.
Lets define a multidimensional array mem.
logic [31:0] mem [0:2][0:4][5:8];
In the example word contents, wzyx,
-w shows the start of the word
-z corresponds to words of the [0:2] dimension (3 blocks).
-y corresponds to words of the [0:4] dimension (5 rows).
-x corresponds to words of the [5:8] dimension (4 columns).
The file will be structure as below (notice #z shows the z dimension blocks):
#0 w005 w006 w007 w008
w015 w016 w017 w018
w025 w026 w027 w028
w035 w036 w037 w038
w045 w046 w047 w048
#1 w105 w106 w107 w108
w115 w116 w117 w118
w125 w126 w127 w128
w135 w136 w137 w138
w145 w146 w147 w148
#2 w205 w206 w207 w208
w215 w216 w217 w218
w225 w226 w227 w228
w235 w236 w237 w238
w245 w246 w247 w248
In the previous structure, the numbers shows the index of each dimension.
e.g. w048 means, the word w (32bits) value on index z =0, index y= 4 and index x= 8.
Now, you have many ways to read this.
You can read all in a single shot using the type "mem" declared above, or you can do a while loop until EOF reading pieces of 32bits using a "data_write_temp" variable of 32bits. The loop is interesting if you want to do something some checks for every word piece and you are not interested having a memory value.
In case multidimensional array / single shot read is chosen, then you can either use $fread or use an specific function $readmemh defined in SV standard.
$readmemh("mem.data", mem, 1, (3*5*4));
is equivalent to
$readmemh("mem.data", mem);
The $readmemh spare you the need to open/close the file.
If you use $fread for one shot read
logic [31:0] mem [0:2][0:4][5:8];
register_init_id = $fopen("mem.data","rb");
nchar_code = $fread(mem, register_init_id);
if (nchar_code!=(3*5*4)*4)) begin
`uvm_error("do_read_file", $sformatf("Was not possible to read the whole expected bytes"));
end
$fclose(register_init_id);
In case you wanted to do a loop using 32b word read. Then see the following example.
The example uses the data which is read from the file to write to AHB Bus using an AHB Verification Component.
logic [31:0] data_write_temp;
...
//DO REGISTER FILE
register_init_id = $fopen("../../software/binary.bin","rb");
if (register_init_id==0) begin `uvm_error("do_read_file", $sformatf("Was not possible to open the register_init_id file")); end
count_32b_words=0;
while(!$feof(register_init_id)) begin
nchar_code = $fread(data_write_temp, register_init_id);
if ((nchar_code!=4)||(nchar_code==0)) begin
if (nchar_code!=0) begin
`uvm_error("do_read_file", $sformatf("Was not possible to read from file a whole 4bytes word:%0d",nchar_code));
end
end else begin
tmp_ahb_address = (pnio_pkg::conf_ahb_register_init_file_part1 + 4*count_32b_words);
data_write_temp = (data_write_temp << 8*( (tmp_ahb_address)%(DATAWIDTH/(8))));//bit shift if necessary not aligned to 4 bytes
`uvm_create_on(m_ahb_xfer,p_sequencer.ahb0_seqr);
assert(m_ahb_xfer.randomize(* solvefaildebug *) with {
write == 1;//perform a write
HADDR == tmp_ahb_address;
HSIZE == SIZE_32_BIT;
HBURST == HBURST_SINGLE;
HXDATA.size() == 1; //only one data for single bust
HXDATA[0] == data_write_temp;
}) else $fatal (0, "Randomization failed"); //end assert
`uvm_send(m_ahb_xfer);
count_32b_words++;
end //end if there is a word read
end //end while
$fclose(register_init_id);
Related
With some simulators(for ex. VCS) the following code is passing and with some of them it brings to compilation error( for ex. Xcelium):
For example:
`define MAX_SIZE 8;
Who knows what is the reason that some simulators passing with ";" symbol at the end?
Best Regards,
The reason has to do with whether to tool is interpreting the code as Verilog or SystemVerilog. Verilog does not have the concept of a null statement, while SystemVerilog does:
module top;
;
endmodule
When you put a ; at the end of a macro and put one at the end of the statement that uses the macro, you wind up with a null statement.
`defne MAX_SIZE 8;
A = `MAX_SIZE;
This gets intrpreted as
A = 8; ;
So it depends on whether that null statement makes sense in the context where it appears.
begin
; // allowed here
case (expr)
1: A = 8;
2: A = 16; ; // null statement not allowed here
endcase
B = 8; ; // allowed here
end
Verilog text macros are used for text substitutions. In your case ; is a part of the macro definition. It will be placed in the text as is, for example:
`define MAX_SIZE 8;
...
assign abc = `MAX_SIZE
The last statement does not contain explicit semicolon. It is supplied by the macro when its text gets substituted there and will look like assign abc = 8;
answering the comment
It is not a good practice to use the ; in macro definition. Verilog is very strict about semicolons ad there are other issues as well. For example, if one puts a semicolon after a such macro, as in the comment, compilation will fail because of the double ;;
`assign abc = `MAX_SIZE;
The other example of failing compilation is declaration:
reg[`MAX_SIZE-1:0] ctrl;
Now, the semicolon from the MAX_SIZE would stay in the way.
The best way to avoid issues in verilog with macros: do not use semicolon in macro definition, in particular when you define constants:
`define MAX_SIZE 8
However, even a better way to define constants is to use parameters. parameter MAX_SIZE = 8;
The JPEG standard defines the DECODE procedure like below. I'm confused about a few parts.
CODE > MAXCODE(I), if this is true then it enters in a loop and apply left shift (<<) to code. AFAIK, if we apply left shift on non-zero number, the number will be larger then previous. In this figure it applies SLL (shift left logical operation), would't CODE always be greater than MAXCODE?
Probably I coundn't read the figure correctly
What does + NEXTBIT mean? For instance if CODE bits are 10101 and NEXTBIT is 00000001 then will result be 101011 (like string appending), am I right?
Does HUFFVAL list is same as defined in DHT marker (Vi,j values). Do I need to build extra lookup table or something? Because it seems the procedure used that list directly
Thanks for clarifications
EDIT:
My DECODE code (C):
uint8_t
jpg_decode(ImScan * __restrict scan,
ImHuffTbl * __restrict huff) {
int32_t i, j, code;
i = 1;
code = jpg_nextbit(scan);
/* TODO: infinite loop ? */
while (code > huff->maxcode[i]) {
i++;
code = (code << 1) | jpg_nextbit(scan);
}
j = huff->valptr[i];
j = code + huff->delta[i]; /* delta = j - mincode[i] */
return huff->huffval[j];
}
It's not MAXCODE, it's MAXCODE(I), which is a different value each time I is incremented.
+NEXTBIT means literally adding the next bit from the input, which is a 0 or a 1. (NEXTBIT is not 00000001. It is only one bit.)
Once you've found the length of the current code, you get the Vi,j indexing into HUFFVAL decoding table.
I am trying to verify the RISC-V DUT with 32bit integer set instruction which is available at https://github.com/ucb-bar/vscale
they have their inputs stored in memory as a hex file # vscale/src/test/inputs/ ( from the above link).
I would like to verify my set of instructions for which i need them to be in the hex format .
For example my set of instructions are ( just mentioning briefly)
ADD
SW
LW
SUB
I would like to convert these set of instructions in hex format so that I can verify its functionality. Could anyone help me out on how to go about .... would be really helpful.
vscale/src/test/inputs have several hex inputs with similar format: 32 hex chars per line (16 bytes, 4 of 4-byte words) and 8192 lines. For example:
https://github.com/ucb-bar/vscale/blob/master/src/test/inputs/rv32ui-p-add.hex
000000000000000000010101464c457f
00000034000001000000000100f30002
00280001002000340001000000000d04
00000000000000000000000100020005
00000005000007500000075000000000
...
Such files are loaded by testbench module in verilog with $readmemh function: https://github.com/ucb-bar/vscale/blob/master/src/test/verilog/vscale_hex_tb.v
module vscale_hex_tb();
localparam hexfile_words = 8192;
...
initial begin
$value$plusargs("max-cycles=%d", max_cycles);
$value$plusargs("loadmem=%s", loadmem);
$value$plusargs("vpdfile=%s", vpdfile);
if (loadmem) begin
$readmemh(loadmem, hexfile);
for (i = 0; i < hexfile_words; i = i + 1) begin
for (j = 0; j < 4; j = j + 1) begin
DUT.hasti_mem.mem[4*i+j] = hexfile[i][32*j+:32];
end
end
end
$vcdplusfile(vpdfile);
$vcdpluson();
// $vcdplusmemon();
#100 reset = 0;
end // initial begin
The $readmemh is documented in http://verilog.renerta.com/mobile/source/vrg00016.htm http://fullchipdesign.com/readmemh.htm
.. $readmemh reads hexadecimal data. Data has to exist in a text file. White space is allowed to improve readability, as well as comments in both single line and block. The numbers have to be stored as ... hexadecimal values. The basic form of a memory file contains numbers separated by new line characters that will be loaded into the memory.
The test inputs are used to initialize embedded memory DUT.hasti_mem.mem.
To work with such files you should know the memory map used in this testbench. Some parts of the memory may be not the instructions, but data and some initialization vectors. If you want to disassemble some of files, convert hex into binary (there are parsers for perl or you can write converter in other language or use verilog's $writememb to convert). Then add header of any binary format supported by your riscv disassembler, like elf for riscv objdump, or no any header for radare2 (https://github.com/radare/radare2) with riscv support.
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
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.