How can you drive internal signals of a DUT verilog code from testbench?
Consider this following example:
module dut(input bit clk);
logic [7:0] data;
endmodule : dut
module top;
bit clk;
dut dut1(.*);
assign dut.data = '0; // this doesn't work.
endmodule
Cross module references do work. The catch, though, is that any signal in the DUT will already be driven. You need to override that driver. Force and release are the usual way of doing this but you can also just use a stronger driver strength.
The default drive strength is "Strong" so the only thing stronger is "supply".
For your example:
assign (supply0, supply1) data = '0;
Strictly speaking, the supply1 is unnecessary as you are only driving zero. However, it eliminates the surprise you might get if you ever need to change your code to drive '1'.
Related
Note this question is not for when I am simulating. I have found numerous resources as to how to use readmemh which does not solve my problem. What I am trying to do is load the RAM for a processor that I designed with the program data. I believe that the FPGA is not getting any of the program data, just the HDL description of the processor.
I tried using Verilog's readmemh function, which I now realize is only useful for simulation. I have also tried using the /* synthesis ram_init_file = "file.mif" */; instruction (?). Either way, there was no difference in how the device worked. I simulated all these cases in ModelSim so I know the design works. I just am stumped as to how I can preload the data.
The answer is going to be tool specific because the initial blocks are, in general, not synthezisable. If you can do it, it is just because the tool has a specific template that is matched with your initial block. Initializing a memory is one of these special cases, where the 'initial' block is discarded from your logic but it is used to generate the initialization data passed along the bitstream.
From the Intel Quartus documentation we can see that there are slightly differences on the actual implementation of the two kinds of memories, dedicated RAM and MLABs, however the general idea is to use an initial block:
module ram_with_init(
output reg [7:0] q,
input [7:0] d,
input [4:0] write_address, read_address,
input we, clk
);
reg [7:0] mem [0:31];
integer i;
// Init the memory with these values
initial begin
for (i = 0; i < 32; i = i + 1)
mem[i] = i[7:0];
end
always # (posedge clk) begin
if (we)
mem[write_address] <= d;
q <= mem[read_address];
end
endmodule
Or, for the quartus pro, you can use readmemh, readmemb:
reg [7:0] ram[0:15];
initial
begin
$readmemb("ram.txt", ram);
end
I suggest you look at the documentation linked as the most updated reference.
Assume there are two different modules (first_module, second_module). Both of the modules are synchronized with clock signal. first_module has the following structure:
module first_module(
input clk,
input reset_n,
input in1,
output reg out1,
output reg out2
);
//******** some verilog codes *********
endmodule
And second_module has similar structure:
module second_module(
input clk,
input reset_n,
input in1,
input in2,
output reg out1
);
//******** some verilog codes *********
endmodule
And then there is a module called top_module which uses instances of both modules:
module top_module(
input clk,
input reset_n,
input insignal1,
input insignal2,
output outsignal1,
output outsignal2
);
first_module fm1(
.clk(clk),
.reset_n(reset_n),
.in1(insignal1),
.out1(outsignal1),
.out2(<connection1>) // to be connected to the connection2
);
second_module sm1(
.clk(clk),
.reset_n(reset_n),
.in1(insignal2),
.in2(<connection2>), // to be connected to the connection1
.out1(outsignal2)
);
endmodule
The aim is to connect connection1 to connection2. According to my knowledge (if it is correct), we can either declare a single wire (let its name be connection) and replace both <connection1> and <connection2> with it, or we can declare two distinct wires connection1 and connection2, then:
assign connection2 = connection1;
And connect them accordingly.
Are those two methods synthesized differently? If the answer is yes, I would be glad if you could explain how they are synthesized.
If the answer is no, can one of the methods be better than the other in different conditions? Not in terms of lines of code or simplicity, but in terms of synthesis.
Yes there is a difference. But not in your specific case.
Using a connection directly makes that is can be uni-directional or bi-directional depending on what the underlying ports in the module are.
But assign connection2 = connection1; is only uni-directional.
Thus between bi-directional ports should use direct connections or you should only use bi-directional Verilog constructs between them. The assign ... is not one of them.
But in you case the signal is uni-directional so it does not matter.
Note that modern FPGAs no longer have on-chip bi-directional buses. (At least I don't know one that has). Also in chip design on-chip buses are strongly discourage or outright forbidden by the manufacturers.
Therefore bi-directional signals are normally only present in the test-bench. As that does not get synthesized your question does not apply there.
Last but not least:
In HDL design I would strongly discourage from changing the name of a signal for no apparent reason. Having the same name throughout the design makes it easier to debug and trace your signals post-synthesis.
I believe that SystemVerilog is a much higher level of abstraction in coding. Is it possible to interface a SystemVerilog module with a verilog module? Are they any aspects that should be kept in mind when trying to integrate them?
Verilog and SystemVerilog are the same language - that is, anything you know about Verilog exists in SystemVerilog. From a synthesis point of view, you will sill be connecting bit of signals with other bits of signals. Its just that with SystemVerilog, you will have more advanced ways of declaring those signals, and many more operators to manipulate those signals.
Without knowing any SystemVerilog, I suggest that you learn it by itself before trying to integrate older Verilog modules with SystemVerilog modules. It will be difficult to explain what to look out for.
One thing that does carry over from Verilog to SystemVerilog is the concept of nets(wires) and variables(regs). Make sure you have a clear understanding of that, plus the new semantics SystemVerilog adds. I have a small article on it. Verilog only allowed wires to pass through ports and did not enforce directions. SV allows variables to pass through ports (meaning variables on both sides of the port connection) but strongly enforces directionality.
Yes, it is possible to interface system verilog module to verilog module.
Before that you must have understanding regarding signals (variable) which are used in verilog module.
You have to create interface from which your verilog signals are connected to system verilog module.
So, data transfer between verilog and system verilog module is possible.
Here I provide verilog module and system verilog module. Main part of code is interface from which verilog and system verilog module are connected.
verilog module code :
module dff(qn,d,clk,reset);
output qn;
input d,clk,reset;
reg qn;
always#(posedge clk,negedge reset)
begin
if (!reset)
begin
qn=1'bx;
end
else if (d==0)
begin
qn=0;
end
else if (d==1)
begin
qn=1;
end
end
endmodule
System verilog module code :
interface melay_intf(input bit clk);
logic o,clk,rst,i;
clocking c1#(posedge clk);
input o;
output i,rst;
endclocking
endinterface
module top;
bit clk;
always
#1 clk = ~clk;
melay_intf i1(clk);
dff d1(.o(i1.o),.clk(i1.clk),.rst(i1.rst),.i(i1.i));
melay_tes(i1.tes);
endmodule
program melay_tes(melay_intf i1);
initial
#100 $finish;
initial
begin
i1.rst <= 0;
#4 i1.rst <= 1;
#4 i1.rst <= 0;
i1.i = 1;
#2 i1.i = 0;
#2 i1.i = 1;
#2 i1.i = 0;
#2 i1.i = 1;
#2 i1.i = 0;
repeat(10)
begin
i1.i = 1;
#2 i1.i = $urandom_range(0,1);
end
end
initial
$monitor("output = %d clk = %d rst = %d i = %d",i1.o,i1.clk,i1.rst,i1.i);
initial
begin
$dumpfile("mem.vcd");
$dumpvars();
end
endprogram
Here important part is interface and in it I used clocking block for synchronization purpose.
Here clocking c1#(posedge clk); so all signals which are mention inside the clocking block which are i,o,rst.All this signal change its value at every posedge of clk signal.
Here dff d1(.o(i1.o),.clk(i1.clk),.rst(i1.rst),.i(i1.i));
Important thing that you find in top module I made connection between verilog signals and system verilog signals.
You can find verilog module name is "dff".
I took the instance of dff verilog module and made the connection.
Here i1.o,i1.clk,i1.rst,i1.i is system verilog signals which are connected to o,clk,rst,i signals of verilog module of with dot convention.
System verilog (SV) is mainly used for design verification, so the thing is that the DUT (Device Under Test) is written in verilog mainly because verilog can be synthesized mostly. SV is then used to write verification environment for that DUT.
Interfaces are needed in between to connect the SV with the DUT which is verilog. Separate file is written is SV to specify what are the different connection between the two files. This file say INTERFACE file is included in all the separate blocks which need those connections.
You can refer the IEEE standard https://standards.ieee.org/getieee/1800/download/1800-2012.pdf for further information on SV.
Which code is better in writing a RAM?
assigning data_out inside always block:
module memory(
output reg [7:0] data_out,
input [7:0] address,
input [7:0] data_in,
input write_enable,
input clk
);
reg [7:0] memory [0:255];
always #(posedge clk) begin
if (write_enable) begin
memory[address] <= data_in;
end
data_out <= memory[address];
end
endmodule
assigning data_out using assign statement:
module memory(
output [7:0] data_out,
input [7:0] address,
input [7:0] data_in,
input write_enable,
input clk
);
reg [7:0] memory [0:255];
always #(posedge clk) begin
if (write_enable) begin
memory[address] <= data_in;
end
end
assign data_out = memory[address];
endmodule
Any recommendations?
It depends on your requirements.
This registers your memory output. If you are synthesizing this to gates, you will have 8 more flip-flops than in case 2. That means you use a little more area. It also means your output will have less propagation delay relative to the clock than case 2. Furthermore, the output data will not be available until the next clock cycle.
Your output data will be available within the same clock cycle as it was written, albeit with longer propagation delay relative to the clock.
You need to decide which to use based on your requirements.
A third option is to use a generated RAM, which is a hard macro. This should have area, power and possibly timing advantages over both case 1 and 2.
to add to toolic's answer - if you use the asynchronous read method (case 2), it won't map to a RAM block in an FPGA, as the RAM blocks in all the major architectures I'm aware of have a synchronous read.
Both forms are valid, depending on the type of pipelining you want. I always recommend following the Xilinx RAM coding guidelines -- it's a good way to ensure that the code synthesizes into proper FGPA constructs.
For example, your example 1 would synthesize into into Xilinx BRAM (i.e., dedicated Block Ram), since it is synchronous read, and your example 2 would synthesize into Xilinx Distributed Ram (since it is asynchronous read).
See the coding guidelines in Xilinx document UG901 (Vivado Design Suite User Guide), in the RAM HDL Coding Techniques section. It also has a good description of the difference between synchronous read and asynchronous read for RAMs.
In the second program, there would be compilation error as we can not 'Assign' a value to 'Reg'.
It will give an error saying: 'Register is illegal in left-hand side of continuous assignment'
I am trying to implement a microcontroller on an FPGA, and I need to give it a ROM for its program. If I use $readmemb, will that be correctly synthesized to a ROM? If not, what is the standard way to do this?
It depends on the synthesis tool whether or not $readmemb is synthesizable.
Altera's Recommended HDL Coding Styles guide includes example 10-31 (page 10-38), which demonstrates a ROM inferred from $readmemb (reproduced below):
module dual_port_rom (
input [(addr_width-1):0] addr_a, addr_b,
input clk,
output reg [(data_width-1):0] q_a, q_b
);
parameter data_width = 8;
parameter addr_width = 8;
reg [data_width-1:0] rom[2**addr_width-1:0];
initial // Read the memory contents in the file
// dual_port_rom_init.txt.
begin
$readmemb("dual_port_rom_init.txt", rom);
end
always # (posedge clk)
begin
q_a <= rom[addr_a];
q_b <= rom[addr_b];
end
endmodule
Similarly, Xilinx's XST User Guide states that:
The $readmemb and $readmemh system
tasks can be used to initialize block
memories. For more information, see:
Initializing RAM From an External File
Coding Examples
Use $readmemb for
binary and $readmemh for hexadecimal
representation. To avoid the possible
difference between XST and simulator
behavior, Xilinx® recommends that you
use index parameters in these system
tasks. See the following coding
example.
$readmemb("rams_20c.data",ram, 0, 7);