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'
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.
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'.
I am trying to write something like this:
always#(posedge bus_start)
begin
#(posedge scl) buffer[7] = sda;
#(posedge scl) buffer[6] = sda;
#(posedge scl) buffer[5] = sda;
#(posedge scl) buffer[4] = sda;
#(posedge scl) buffer[3] = sda;
#(posedge scl) buffer[2] = sda;
#(posedge scl) buffer[1] = sda;
#(posedge scl) buffer[0] = sda;
end
But it is not synthesizable according to the error I got.
I may use FSM to solve this, but that could make it complicated, is there any way to make it synthesizable?
You don't give enough information.
Answer from #Krabby127 is also not synthesisable.
I think you have a lot of more work to do. You should to learn the difference between Verilog and C,first. RTL code is to describe the hardware in FPGA.So the concept of synthesisable is very important for you.
And you have to take care of debounce of I2C signal.Take care of tristate signal.
After all I suggest you to get some I2C project from opencores.org to study.
Forgive my poor English.
It looks like you're trying to capture data from an I2C interface.
Here is a simple solution for capturing 8 bits of data from sda and storing that into a register called buffer.
// starts on rising edge of scl or bus_start
always#(posedge bus_start or posedge scl)
begin
buffer[0] <= sda; // loads sda into the lowest bit of buffer
buffer[7:1] <= buffer[6:0]; // shifts the lower 6 bits one to
// the left, acting as a shift register
end
More information about I2C in verilog can be found here
In addition, a basic I2C slave can be found here (you must register and login to view the source code).
I2C slaves mostly use a sampling clock other than SCL. I don't mean that it's impossible otherwise, but the common practice is to use a faster clock for sampling SCL and SDA signals.
I definitely recommend to start the design with the below ports at minimum. Since SDA is a tristate signal, I also recommend not to deal with it at this stage. You can assume that it's done out of your module and can continue with separate input and output ports.
input clk; // system clock
input rst; // system reset
input scl; // i2c clock
input sda_in; // i2c input data
output sda_out; // i2c output data
To be honest, I2C is not a good choice to learn an HDL (Verilog/SV/VHDL) and digital design. It will bring some complex issues.
I write simple code using ISE 14.7 to generate clock signal, but the output in iSim is always 1, until I change = with <= then the clock works, could you tell me why?
module nonblocking( clk );
output reg clk;
initial
#10 clk =0;
always # (clk)
#10 clk = ~ clk; // change to <= to work
endmodule
This code honestly doesn't make any sense.
Your current code states that based on clk, the value of clk should be ~clk.
When you use <= you are at least specifying a nonblocking assignment, which makes slightly more sense, but still doesn't.
If you want a clock generator for simulation, use the following within an initial block (giving a 10ns period):
forever begin
#5 clk <= ~clk;
end
If you want a clock generator for FPGA synthesis, either connect a physical oscillator to your device's clock input pin, or use a built-in oscillator (if available on your device). You can always use a DCM/PLL/CMT/MMCM/whatever your FPGA calls it to adjust the clock frequency.
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);