How To generate hex files in RISC V? - riscv

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.

Related

Converting Char "1" to hex "4'h0001"

I am trying to convert a string to the same value in hex. Eg
If string="abc123" it's hex value should also be 24'habc123.
The length of string is 64 and so I convert each char to hex,I'll get 64*4=256 bits of hex value
eg if text_o_cplus.getc(i)=a i.e 97,I should assign it a hex value a i'e 4'ha;
But I am not getting proper way to do that. That's what I tried
int j=255;
for(int i=text_o_cplus.len();i>0;i--)
begin
while(j>=0)
begin
case(text_o_cplus.getc(i))
48: begin
rev_result[j]=4'b0000;
j=j-4;
break;
end
and so on.
rev_result is defined as
bit [64][4] rev_result;
I tried to define it as
bit [255:0] rev_result
also but it didn't work.
Can someone please suggest how can I achieve it?
Use the built-in function:
bit [255:0] rev_result = text_o_cplus.atohex();

VHDL - String indexing - RAM usage and total logic elements increase by over 100% each

I'm hoping someone with more VHDL experience can enlighten me! To summarise, I have an LCD entity and a Main entity which instantiates it. The LCD takes an 84-character wide string ("msg"), which seems to cause me huge problems as soon as I index it using a variable or signal. I have no idea what the reason for this is, however, since the string is displaying HEX values, and each clock cycle, I read a 16-bit value... I need to update 4 characters of the string for each nybble of this 16-bit value. This doesn't need to be done in a single clock cycle, since a new value is read after a large number of cycles... however, experimenting with incrementing a "t" variable, and only changing string values one "t" at a time makes no difference for whatever reason.
The error is: "Error (170048): Selected device has 26 RAM location(s) of type M4K" However, the current design needs more than 26 to successfully fit
Here is the compilation report with the problem:
Flow Status Flow Failed - Tue Aug 08 18:49:21 2017
Quartus II 64-Bit Version 13.0.1 Build 232 06/12/2013 SP 1 SJ Web Edition
Revision Name Revision1
Top-level Entity Name Main
Family Cyclone II
Device EP2C5T144C6
Timing Models Final
Total logic elements 6,626 / 4,608 ( 144 % )
Total combinational functions 6,190 / 4,608 ( 134 % )
Dedicated logic registers 1,632 / 4,608 ( 35 % )
Total registers 1632
Total pins 50 / 89 ( 56 % )
Total virtual pins 0
Total memory bits 124,032 / 119,808 ( 104 % )
Embedded Multiplier 9-bit elements 0 / 26 ( 0 % )
Total PLLs 1 / 2 ( 50 % )
The RAM summary table contains 57 rows, of "LCD:display|altsyncram:Mux####_rtl_0|altsyncram_####:auto_generated|ALTSYNCRAM"
Here is the LCD entity:
entity LCD is
generic(
delay_time : integer := 50000;
half_period : integer := 7
);
port(
clk : in std_logic;
SCE : out std_logic := '1';
DC : out std_logic := '1';
RES : out std_logic := '0';
SCLK : out std_logic := '1';
SDIN : out std_logic := '0';
op : in std_logic_vector(2 downto 0);
msg : in string(1 to 84);
jx : in integer range 0 to 255 := 0;
jy : in integer range 0 to 255 := 0;
cx : in integer range 0 to 255 := 0;
cy : in integer range 0 to 255 := 0
);
end entity;
The following code is what causes the problem, where a, b, c and d are variables which are incremented by 4 after each read:
msg(a) <= getHex(data(3 downto 0));
msg(b) <= getHex(data(7 downto 4));
msg(c) <= getHex(data(11 downto 8));
msg(d) <= getHex(data(15 downto 12));
Removing some of these lines causes the memory and logic element usages to both drop, but they still seem absurdly high, and I don't understand the cause.
Replacing a, b, c and d with integers, like 1, 2, 3 and 4 causes the problem to go away completely, with the logic elements at 22%, and RAM usage at 0%!
If anybody has any ideas at all, I'd be very grateful! I will post the full code below in case anybody needs it... but be warned, it's a bit messy, and I feel like the problem could be simple. Many thanks in advance!
Main.vhd
LCD.vhd
There are a few issues here.
The first is that HDL synthesis tools do an awful lot of optimization. What this basically means is if you don't properly connect up input and output parts to/from something it is likely (but not certain) to get eliminated by the optimizer.
The second is you have to be very careful with loops and functions. Basically loops will be unrolled and functions will be inlined, so a small ammount of code can generate an awful lot of logic.
The third is that under some cicumstances arrays will be translated to memory elements.
As pointed out in a comment this loop is the root cause of the large ammounts of memory usage.
for j in 0 to 83 loop
for i in 0 to 5 loop
pixels((j*6) + i) <= getByte(msg(j+1), i);
end loop;
end loop;
This has the potential to use a hell of a lot of memory resources. Each call to "getByte" requires a read port on (parts of) "ram" but blockrams only have two read ports. So "ram" gets duplicated to satisfy the need for more read ports. The inner loop is reading different parts of the same location so basically each iteration of the outer loop needs an independent read port on the ram. So that is about 40 copies of the ram. Reading the cyclone 2 datasheet each copy will require 2 m4k blocks
So why doesn't this happen when you use numbers instead of the variables a,b,c and d?
If the compiler can figure out something is a constant it can compute it at compile time. This would limit the number of calls to "pixels" that have to actually be translated to memory blocks rather that just having their result hardcoded. Still i'm surprised it's dropping to zero.
I notice your code doesn't actually have any inputs other than the clock and a "rx" input that doesn't actually seem to be being used for anything, so it is quite possible that the synthesizer may be figuring out a hell of a lot of stuff at build time. Often eliminating one bit of code can allow another bit to be eliminated until you have nothing left.

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.

Read binary file data in Verilog into 2D Array

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);

Generate instance with different string parameters in verilog

When I was config pll_reconfig module in Quartus II, the generate for statement in design have to specify different string parameter (filenames) to different instances.
I have tried these code:
genvar i;
generate
for (i=0; i<2; i=i+1) begin:u
rom #($sformatf("mif%d.mif",i)) U(
//signals connected.
);
end
endgenerate
It is said that the code is not synthesizable.
How can I specify variable string parameter in generate for block?
I had a similar problem but on a system that did not support $sformatf. My solution is a little dirty but may help others:
genvar i;
generate
for (i=0; i<10; i=i+1)
begin
mymodule #(.NAME("NAME0" + i) instance(.RESET(mreset) ... );
end
endgenerate
This works, I believe, by treating the string "NAME0" as a number (a 40-bit number). By adding i, you just increase the value by i and the result is the last ASCII char changes. Luckily '0' + i gives you '1', '2', '3' etc
The obvious flaw is this only works for 0-9, however there is a simple extension using divide and modulo arithmatic:
mymodule #(.NAME("NAME00" + (256 * (i / 10)) + (i % 10) ) ) ...
As a side note, I ran into issues using string concatenation {"NAME", i} because Verilog was treating i as 32-bit value so the string ends up as:
NAME 1
due to the extra 'unwanted' 24 bits which equate to 3 null characters

Resources