Is it possible to see if vivado inferred blockram? - vivado

I have a following piece of code:
module cw305_reg_aes #(
parameter pADDR_WIDTH = 21,
parameter pBYTECNT_SIZE = 14,
parameter pPK_WIDTH = 800 // 800 * 8
)(
input wire usb_clk,
input wire crypto_clk,
input wire [pADDR_WIDTH-pBYTECNT_SIZE-1:0] reg_address,
input wire [pBYTECNT_SIZE-1:0] reg_bytecnt,
output reg [7:0] read_data,
input wire [7:0] write_data,
input wire reg_read,
input wire reg_write,
output wire [7:0] reg_pk
);
reg [7:0] reg_read_data;
reg [7:0] reg_crypt_public_key [pPK_WIDTH-1:0];
(* ASYNC_REG = "TRUE" *) reg [7:0] reg_crypt_public_key_crypt [pPK_WIDTH-1:0];
always #(posedge crypto_clk) begin
for (i=0; i<pPK_WIDTH;i=i+1) begin
reg_crypt_public_key_crypt[i] <= reg_crypt_public_key[i];
end
end
assign reg_pk = reg_crypt_public_key_crypt[0]
always #(*) begin
if (reg_read) begin
case (reg_address)
`REG_CRYPT_PUBLIC_KEY: reg_read_data = reg_crypt_public_key[reg_bytecnt];
default: reg_read_data = 0;
endcase
end
else
reg_read_data = 0;
end
always #(posedge usb_clk) begin
if (reg_write) begin
case (reg_address)
`REG_CRYPT_PUBLIC_KEY: reg_crypt_public_key[reg_bytecnt] <= write_data;
endcase
end
end
How can I see if Vivado 2021.1 inferred block ram instead of distributed ram for the reg_crypt_public_key array?

Block rams are reported in the synthesis log. If BRAMs are inferred there will be a section detailing what parts of the HDL produced which BRAMs of how many ports, width, etc
It reads like the log mentioned on the forums here: https://support.xilinx.com/s/article/61027?language=en_US
With header like
|Module Name ------ | RTL Object | PORT A (depth X width) | W | R | PORT B (depth X width) | W | R | OUT_REG | RAMB18 | RAMB36 | Hierarchical Name
Additionally opening the final utilization report will show a hierarchical break down of where in the design is using BRAMs vs LUTs as memory (distributed).
Finally see the synthesis guide for how to intentionally infer BRAM per the manufacturers recommended code guidelines. p. 111 https://www.xilinx.com/content/dam/xilinx/support/documents/sw_manuals/xilinx2021_2/ug901-vivado-synthesis.pdf

Another way:
Open the post route design or dcp file in the Vivado GUI.
Locate the netlist window and surf the hierarchical path to expected BRAM path.
Right click 'schematic' on the design element in the netlist window.
The schematic viewer opens showing: inferred BRAM, distributed RAM or registers.
Here is a little example showing a register connected to a BRAM:
This is a general way you can explore what the tools have done with the RTL code.

Related

Quartus does not allow using a Generate block in Verilog

Pretty simple problem. Given the following code:
module main(
output reg [1:0][DATA_WIDTH-1:0] dOut,
input wire [1:0][DATA_WIDTH-1:0] dIn,
input wire [1:0][ADDR_WIDTH-1:0] addr,
input wire [1:0] wren,
input wire clk
);
parameter DATA_WIDTH = 16;
parameter ADDR_WIDTH = 6;
reg [DATA_WIDTH-1:0] ram [2**ADDR_WIDTH-1:0];
generate
genvar k;
for(k=0; k<2; k=k+1) begin: m
always #(posedge clk) begin
if(wren[k])
ram[addr[k]] <= dIn[k];
dOut[k] <= ram[addr[k]];
end
end
endgenerate
endmodule
quarus 13.0sp1 gives this error (and its 20 other ill-begotten fraternally equivalent siblings):
Error (10028): Can't resolve multiple constant drivers for net "ram[63][14]" at main.v(42)
But if I manually un-roll the generate loop:
module main(
output reg [1:0][DATA_WIDTH-1:0] dOut,
input wire [1:0][DATA_WIDTH-1:0] dIn,
input wire [1:0][ADDR_WIDTH-1:0] addr,
input wire [1:0] wren,
input wire clk
);
parameter DATA_WIDTH = 16;
parameter ADDR_WIDTH = 6;
reg [DATA_WIDTH-1:0] ram [2**ADDR_WIDTH-1:0];
always #(posedge clk) begin
if(wren[0])
ram[addr[0]] <= dIn[0];
dOut[0] <= ram[addr[0]];
end
always #(posedge clk) begin
if(wren[1])
ram[addr[1]] <= dIn[1];
dOut[1] <= ram[addr[1]];
end
endmodule
It all becomes okay with the analysis & synthesis step.
What's the cure to get the generate loop running?
I think the correct way is in the lines of what it's explained in this question: Using a generate with for loop in verilog
Which would be transferred to your code as this:
module main(
output reg [1:0][DATA_WIDTH-1:0] dOut,
input wire [1:0][DATA_WIDTH-1:0] dIn,
input wire [1:0][ADDR_WIDTH-1:0] addr,
input wire [1:0] wren,
input wire clk
);
parameter DATA_WIDTH = 16;
parameter ADDR_WIDTH = 6;
reg [DATA_WIDTH-1:0] ram [2**ADDR_WIDTH-1:0];
integer k;
always #(posedge clk) begin
for(k=0; k<2; k=k+1) begin:
if(wren[k])
ram[addr[k]] <= dIn[k];
dOut[k] <= ram[addr[k]];
end
end
endmodule
Keeping all accesses to your dual port RAM in one always block is convenient so the synthesizer can safely detect that you are efefctively using a dual port RAM at register ram.
Both the generate loop and unrolled versions should not have passed synthesis. In both cases the same address in ram can be assigned by both always blocks. Worse, if both bits of wren are high with both addresses being the same and data being different, then the result is indeterminable. The Verilog LRM states last assignment on a register wins and always blocks with the same trigger could be evaluated in any order.
Synthesis requires assignments to registers to be deterministic. Two (or more) always blocks having write access to the same bit is illegal because nondeterministic. If the unrolled is synthesizing correctly, then that means there are constants on wren and addr outside of the shown module that make it logically impossible for write conflict; for some reason the generate loop version is not getting the same optimization. Example of constraints that would allow optimization to prevent multi-always block write access:
One wren is hard coded to 0. Therefore only one block has exclusive access
Address have non overlapping sets of possible values. Ex addr[0] can only be even while addr[1] can only be odd, or addr[0] < 2**(ADDR_WIDTH/2) and addr[1] >= 2**(ADDR_WIDTH/2).
Synthesis is okay with dOut being assigned by two always blocks because each block has exclusive write access to its target bits (non overlapping sets of possible address values).
The single always block in mcleod_ideafix answer is the preferred solution. If both bits of wren are high with both addresses being the same, then wren[1] will always win. If wren[0] should have priority, then make the for-loop a count down.

Modelsim - Object not logged & no signal data while simulating verilog clock divider code

What I'm trying to do: I wish to count numbers from 0 to hexadecimal F and display these on my FPGA board at different frequencies - my board's clock (CLOCK_50) is at 50 MHz and I wish to alter the frequency/speed of the counting based on two input switches on my board (SW[1:0]).
Verilog Code for top-module & clock divider module:
//top level module
module rate_divider (input CLOCK_50, input [1:0] SW, input [1:0] KEY,output [6:0] HEX0);
//Declare parameters that define the # of clock cycles needed to generate an enable pulse
according to the desired frequency.
parameter FREQ_5MHz = 4'd9; //To divide to 5 MHz we need (10-1) cycles,
//since the pulse needs to start at the 9th cycle.
parameter FULL50_MHz = (4'd1); //The CLOCK_50's Frequency.
//Select the desired parameter based on the input switches
reg [3:0] cycles_countdown;
wire enable_display_count;
wire [3:0] selected_freq;
always #(*)
case (SW)
2'b00: cycles_countdown = FULL50_MHz;
2'b01: cycles_countdown = FREQ_5MHz;
default : cycles_countdown = FULL50_MHz;
endcase
assign selected_freq = cycles_countdown;
//wire that is the output of the display_counter and input to the 7 segment
wire [3:0] hex_value;
// instantiate my other modules
clock_divider_enable freq_divider (.d(selected_freq), .clk(CLOCK_50), .reset(KEY[0]),
.enable(enable_display_count));
display_counter count_hex (.enable(enable_display_count), .clk(CLOCK_50), .hex_out(hex_value), .reset(KEY[1]));
hex_decoder HX0 (.hex_digit(hex_value), .segments(HEX0[6:0]));
endmodule
//the clock_divider sub-circuit.
module clock_divider_enable (input [3:0] d, input clk, reset,
output enable);
reg [3:0] q;
always #(posedge clk)
begin
if (!reset || !q)
q <= d;
else
q <= q - 4'd1;
end
assign enable = (q == 4'h0) ? 1'b1 : 1'b0;
endmodule
ModelSim Code:
vlib work
vlog rate_divider.v
vsim rate_divider
log {/*}
add wave {/*}
#initial reset - using KEY[1:0]. Note: active low synchronous reset.
force {CLOCK_50} 1
force {KEY[0]} 0
force {KEY[1]} 0
run 10ns
#choose 5 MHz as the desired frequency - turn SW[0] high.
force {CLOCK_50} 0 0ns, 1 {10ns} -r 20ns
force {KEY[0]} 1
force {KEY[1]} 1
force {SW[0]} 1
force {SW[1]} 0
run 600ns
Problems I am facing:
Here's the thing - when I don't use the always block to select a parameter, and pass a desired parameter to the wire selected_freq, my simulation works fine - I can see the expected enable pulse.
HOWEVER, if I use the always block, the reg cycles_countdown does get the correct value assigned, BUT for some reason the enable signal is just a red line. When I select my clock_divider_enable module and add it's 'q' signal onto my waveform, it is red too and shows no data, and the object q is "not logged". As such, I'm unable to debug and figure out what exactly the problem with my code is.
It'd be great if someone could help with how to fix the simulation issue rather than just point out the issue with my Verilog code since I want to learn how to use ModelSim efficiently so that in the future debugging will be easier for me.
Equipment Used:
FPGA: Altera De-1-SoC, Cyclone V chip
CAD/Simulation Tools: Altera Quartus II Lite 17.0 + ModelSim Starter Edition
SW wasn't given an initial value, therefore it is high-Z (X if connected to a reg).
I'm guessing when you used the parameter approach you were parameterizing cycles_countdown. Some simulators do not trigger #* at time-0. So if there isn't a change on the senctivity list, then the block may not execute; leaving cycles_countdown as its initial value (4'hX).
Instead of driving your test with TCL commands, you can use create a testbench in with verilog. This testbench should only be used in simulation, not synthesis.
module rate_devider_tb;
reg CLOCK_50;
reg [1:0] SW;
reg [1:0] KEY;
wire [6:0] HEX0;
rate_divider dut( .CLOCK_50(CLOCK_50), .SW(SW), .KEY(KEY), .HEX0(HEX0));
always begin
CLOCK_50 = 1'b1;
#10;
CLOCK_50 = 1'b0;
#10;
end
initial begin
// init input signals
SW <= 2'b01;
KEY <= 2'b00;
// Log file reporting
$monitor("SW:%b KEY:%b HEX0:%h # %t", SW, KEY, HEX0, $time);
// waveform dumping
$dumpfile("test.vcd");
$dumpvars(0, rate_devider_tb);
wait(CLOCK_50 === 1'b0); // initialization x->1 will trigger an posedge
#(posedge CLOCK_50);
KEY <= 2'b01; // remove reset after SW was sampled
#600; // 600ns assuming timescale is in 1ns steps
$finish();
end

Verilog - Read bits of register dynamically or using some variable

I want to read 8 bit register bit by bit. i.e first reading 0:3 , then 1:4 , then 2:5 . Reading 4 bits at one time.
Below code give error when accessing register bits using integer.
module First_Module(
clock,
reset,
enable,
counter_out
);
// input ports
input clock;
input reset;
input enable;
output [3:0] counter_out;
wire clock;
wire reset;
wire enable=1'b1;
reg[3:0] counter_out=0001;
reg[9:0] line=1101101101;
reg[3:0] testPattern=1101;
reg[3:0] temp=0000;
integer IndexStart,IndexEnd;
initial
begin
IndexStart=0;
IndexEnd=3;
end
initial
#20 $finish; //finish after 20 time units
always
begin:COUNTER
\#1
$monitor ("counter Out = %d Reset = %d",counter_out,reset);
$monitor ("Temp = %d ",temp);
if(reset==1'b1)
begin
counter_out <= 4'b0000;
end// if-end
else if (enable==1'b1)
begin
counter_out= counter_out+1;
IndexEnd=IndexEnd+1;
temp=line[IndexEnd:IndexStart]; // Error at this line
end
end// always end
endmodule
Help is required .
temp=line[IndexEnd:IndexStart];
Verilog sees this a s a dynamic length selector. Which does not make sense in hardware. from Verilog 2001 a new standard for making variable location, fixed width selections (part selects) was introduced.
You should be able to use the following for 4 bit selects:
temp=line[IndexStart +: 4];
For more info see page 23 of Using the New Verilog-2001 Standard by Stuart Sutherland

Connecting a 4 bit shift register output to a 4 bit input in another module in Verilog

For our school project I am trying to use linear feedback shift register for pseudo-random number generation on hardware (seven segment). I have written the LFSR and seven segment module, however I have trouble connecting the two modules with each other. The project synthesizes but the HDL Diagram does not show any connection between LFSR and seven segment module. Below is the code.
//main module
module expo(input clock, reset,
output a,b,c,d,e,f,g
);
wire [3:0]connect, clk, a,b,c,d,e,f,g;
LFSR_4_bit lfsr(
.clock(clock),
.LFSR(connect)
);
seven_seg seven(
.in(connect),
.reset(reset),
.a(a),
.b(b),
.c(c),
.d(d),
.e(e),
.f(f),
.g(g)
);
endmodule
//LFSR module
module LFSR_4_bit(
input clock,
output reg[3:0]LFSR = 15
);
wire feedback = LFSR[4];
always #(posedge clock)
begin
LFSR[0] <= feedback;
LFSR[1] <= LFSR[0];
LFSR[2] <= LFSR[1];
LFSR[3] <= LFSR[2] ^ feedback;
LFSR[4] <= LFSR[3];
end
endmodule
//input and output for seven seg module
module sevenseg(
input reset,
input[3:0] in, //the 4 inputs for each display
output a, b, c, d, e, f, g, //the individual LED output for the seven segment along with the digital point
output [3:0] an // the 4 bit enable signal
);
Thanks for the help.
1) You instantiate seven_seg but the module is called module sevenseg This is a compile error.
2) Your LFSR has 4 bits 0 to 3, a fifth bit LFSR[4] is used, this is also a compile error.
Due to the compile errors I am not sure that your viewing the results of the current synthesis, as it should have failed. It is quite likely that you are viewing an old result before they were connected.
Other things I would change:
a) When you define wire [3:0]connect, clk, a,b,c,d,e,f,g; they are all 4 bits.
However as clock (not clk) and a,b,c,d,e,f,g are defined in your port list they are already declared. That line could just be wire [3:0]connect.
b) When initialising values for flip-flop and not using a reset it is better practise to use an initial begin : This is valid for FPGA's not for ASICs where you should use reset signals
initial begin
LFSR = 4'd15;
end

Default values of RAM

I writing in Verilog HDL for synthesis and I want to instantiate a DUAL PORT RAM with default values (zeros), how can do it?
Thanks, Netanel
As you mentioned Virtex-7 - look in the Xilinx Synthesis manual for examples of how to write Verilog that infers a memory block.
In Appendix C you can find this code:
// Dual-Port Block RAM with Two Write Ports
// File: HDL_Coding_Techniques/rams/rams_16.v
module v_rams_16 (clka,clkb,ena,enb,wea,web,addra,addrb,dia,dib,doa,dob);
input clka,clkb,ena,enb,wea,web;
input [9:0] addra,addrb;
input [15:0] dia,dib;
output [15:0] doa,dob;
reg [15:0] ram [1023:0];
reg [15:0] doa,dob;
always #(posedge clka) begin if (ena)
begin
if (wea)
ram[addra] <= dia;
doa <= ram[addra];
end
end
always #(posedge clkb) begin if (enb)
begin
if (web)
ram[addrb] <= dib;
dob <= ram[addrb];
end
end
endmodule
I'm not a Verilogger, but I'm sure you can tweak the ram declaration to make it initialise with all zeros.

Resources