- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
All, Here is one of my Verilog trial-learning code:
==============================================================// Verilog learning example
module SRAM_Read_Write_Sync ( nrst, Writeclk, Readclk, EQ, write_addr, read_addr);
input nrst, Writeclk, Readclk;
output EQ, write_addr, read_addr;
// Declare the address counters as 9-bit counters
reg write_addr;
reg read_addr;
reg EQ;
// reset address to 0 if NRST goes LO
always @ (negedge nrst)
begin
write_addr = 0;
read_addr = 0;
end
// increment Write address
always @ (posedge Writeclk)
begin
write_addr = write_addr + 1;
end
// increment Read address
always @ (posedge Readclk)
begin
read_addr = read_addr + 1;
if (read_addr == write_addr)
EQ = 1'b1;
else
EQ = 1'b0;
end
endmodule
================================================================== All, (the text in RED) when I try to use the negative edge of my nrst as a reset for my address counters I get the Error (10028): Can't resolve multiple constant drivers for net "read_addr[3]" at SRAM_Read_Write_Sync.v(26) If I remove the RED code it compiles fine. How should I implement a nrst signal that take precedence over any other signals that reset the address counters? Thanks, Keith
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
All, I figured it out.
Following is code that seems to compile, don't know about the EQ yet, but I think I figured a way to reset my counters and increment my counters.// Verilog learning example
module SRAM_Read_Write_Sync ( nrst, Writeclk, Readclk, EQ, write_addr, read_addr);
input nrst, Writeclk, Readclk;
output EQ;
output write_addr;
output read_addr;
// Declare the address counters as 9-bit counters
reg write_addr;
reg read_addr;
reg EQ;
// increment Write address or Read address or do a reset
always @ (posedge Writeclk or posedge Readclk or negedge nrst)
begin
if (!nrst)
begin
write_addr = 0;
read_addr = 0;
end
else if (Writeclk)
write_addr = write_addr + 1;
else if (Readclk)
read_addr = read_addr + 1;
end
always @ (posedge Readclk)
begin
if (read_addr == write_addr)
EQ = 1'b1;
else
EQ = 1'b0;
end
endmodule
So I needed to add all 3 checks in the first "ALWAYS" then check for active LO (!nrst) to reset the counters. Then complete the other edge clocks to increment the appropriate address_counter. Then start another "ALWAYS" and start expanding from here with more behavior!! Thanks all, Keith
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Be aware that this design is likely to have problems as you are reading the write_address with the readclk, as you may violate the setup and hold time of the write_addr when reading causing metastability - look into safe clock domain crossing techniques.
I would also be wary of putting both read and write clock in the same always block. there are several issues: 1. You may accidentally put a variable in both clocks, which is not supported in an FPGA 2. In a simulation, in your code, if the read and write clocks are exactly aligned then only the write_addr will be incremented (as you have given precedence to the writeclk over the readclk) 3. It can be confusing for others.- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Ok, I see your point... and that would definitely come back and bite me sooner or later... but the following code gives me the same Error 10028, so how do I:
1) check for a negative edge on nrst to reset my counters 2) increment my 9-bit counters on their appropriate rising clock edges I've been trying to go through several tutorials and examples and I thought I understood some of it, but..... What/where can I find what is being meant by the "multiple constant drivers for ?????" As you can see I am very "green" to Verilog programming.. Hard for me to see the "hardware behavior picture" since I usually do schematic entry....// Verilog learning example
module SRAM_Read_Write_Sync_Verilog ( nrst, Writeclk, Readclk, EQ, write_addr, read_addr);
input nrst, Writeclk, Readclk;
output EQ;
output write_addr;
output read_addr;
// Declare the address counters as 9-bit counters
reg write_addr;
reg read_addr;
reg EQ;
// increment Write address or Read address or do a reset
always @ (negedge nrst)
begin
if (!nrst)
begin
write_addr <= 0; // non-blocking
read_addr <= 0; // non-blocking
end
end
always @ (posedge Writeclk)
begin
write_addr = write_addr + 1;
end
always @ (posedge Readclk)
begin
read_addr = read_addr + 1;
end
endmodule
Thanks again, Keith
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The reset must be in the same always block as the clock. You're actually not checking for a negative edge of reset - you're waiting for when the reset is low in real hardwarfe - the negedge is a quirk of verilog and the way it is event driven.
always @(posedge Writeclk or negedge nrst)
begin
if(!nrst) write_addr <= 0;
else write_addr <= write_addr + 1;
end
always @(posedge readclk or negedge nrst) begin
if(!nrst) read_addr <= 0;
else read_addr <= read_addr + 1;
end
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
AHH-HA... I never thought of it that way..
Thanks for helping me look at things a little bit differently!!! Keith- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Keith -
There's a difference between code that is legal verilog and will compile without errors in a simulator, and code that will synthesize to hardware, which is usually the ultimate goal unless you're just trying to model behavior in simulation. Your second post has an always block that is sensitive to the rising edge of two different clocks. This doesn't make much sense even for modeling, and it would definitely not synthesize. This might work better:
// Verilog learning example
module SRAM_Read_Write_Sync ( nrst, Writeclk, Readclk, EQ, write_addr, read_addr);
input nrst, Writeclk, Readclk;
output EQ;
output write_addr;
output read_addr;
// Declare the address counters as 9-bit counters
reg write_addr;
reg read_addr;
reg EQ;
// increment Write address or do a reset
always @ (posedge Writeclk or negedge nrst)
begin
if (!nrst)
write_addr <= 9'h0;
else // Unlike VHDL, you don't need to check for Writeclk high here.
write_addr <= write_addr + 1;
end
// increment Read address or do a reset
always @ (posedge Readclk or negedge nrst)
begin
if (!nrst)
read_addr <= 9'h0;
else // Unlike VHDL, you don't need to check for Readclk high here.
read_addr <= read_addr + 1;
end
// read_addr and write_addr are generated from different clocks so
// you probably don't want to compare them directly in one clock domain.
// Maybe just do a combinational compare (not clocked).
always @*
begin
if (read_addr == write_addr)
EQ = 1'b1;
else
EQ = 1'b0;
end
endmodule
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks for the info rsefton. I see you set write_addr <= 9'h0.... why would you prefer that over write_addr <= 0?
Also, you answered one of my other questions I have currently been trying to figure out, by using the combinational compare always @*. Thanks, Keith- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Comparing both addresses asynchronously is potentially worse than in a clock domain as it will be very glitchy, especially as you're using a count and not a grey code.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Keith -
In verilog integers are always 32 bits wide, so when you assign 0 (32 bits) to write_addr (9 bits) you'll always get a synthesis warning about the size mismatch. It can be safely ignored, but assigning the size correctly will eliminate that warning. I always try to be explicit with size in reset assignments, partly because it shows you clearly the size of the variable you're resetting (so you don't have to go up to the declaration to find out). Kind of a self-documentation practice. But it has the side-benefit of reducing the number of synthesis warnings, which can get into the many thousands for a large design. On the other hand, when I code counters (counter <= counter + 1) I'm almost never explicit about the size just because I like the look of "counter + 1" better than "counter + 9'h1". To each his own. Most of us are creatures of habit, some good some bad! In the early days of FPGA/CPLD design I would try to eliminate all compile warnings, and back then it was usually possible. But now with rtl design and IP used everywhere it's virtually impossible to eliminate all warnings and I don't even try. But I always review the synthesis, fitter, and timing reports. Bob- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
OK, now I am trying to expand on the mess I've made. Now I want to do some control with the EQ signal, (either in a clocked or unclocked domain). I am wanting to reset the read address under certain conditions,.... make the read address=write address.... and once again.... I get the (multiple constant drivers....) so it has to be back in the always @ portion. There is getting to be quite a few ORs in it, just so that I can change my read_address.
Example: always @(posedge Readclk or negedge nrst or negedge Read_RST or posedge Read_EQ_Write or negedge EQ) and then a ton of if () else if () else if () else.... Is this correct or am I using the proper technique here or is there some other statement I should be using? I know what I want to do schematically (mostly) but wanting to try using Verilog at this project. Thanks again, Keith- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
if you have a clock, the the only thing that should be in the sensitivity list (inside the brackets of the always) are the Readclk and nrst. You only care what happens on the clock edge, hence you dont want anything else. If you are trying to do logic with the clock, you are going to fail as this wont be possible in an FPGA. at the top level you should have:
always @(posedge Readclk or negedge nrst) begin
if(~nrst) begin
// asynchronous reset goes here
else begin
// this is for synchronous logic
end
// NOTHING ELSE HERE
end
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
OK Thanks Tricky, I'll concentrate on this approach!! If I can't get the hang of it I will go back to schematic entry just so that i can get the design done and out the door.
Thanks again, Keith- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- Quote Start --- Comparing both addresses asynchronously is potentially worse than in a clock domain as it will be very glitchy, especially as you're using a count and not a grey code. --- Quote End --- Of course you're right, Tricky. I was just trying to solve one problem at a time. I was not going to get into safe clock domain crossing.

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page