Author |
Message |
skrasms
Joined: Feb 21, 2008 Posts: 121 Location: Portland, OR
|
Posted: Sun Apr 12, 2009 9:55 am Post subject:
Beginner Verilog Question |
 |
|
I'm writing some basic verilog for what is essentially an asynchronous buffer, but I'm running into a fundamental problem.
I have a "full" flag that I would like to go high when data is clocked in, and low when data is clocked out.
If I set it up like this:
Code: |
always @(posedge READ)
begin
//other code will go here
FULL = 1;
end
always @(posedge WRITE)
begin
//other code will go here
FULL = 0;
end
|
I get an error "Can't resolve multiple constant drivers for net 'FULL'."
It makes sense that FULL can't be low and high at the same time, but what I am trying to do is use one case as a set and the other as a reset. Is there no simple way to do that without adding my own SR latch code?
I tried adding "assign" in front of the "FULL = x" parts in hopes that it would re-define FULL to the most recent case, but that gave me an error about Verilog not supporting continuous Procedural Assignment.
Can anyone help? _________________ Software and Hardware Design |
|
Back to top
|
|
 |
JovianPyx

Joined: Nov 20, 2007 Posts: 1988 Location: West Red Spot, Jupiter
Audio files: 224
|
Posted: Sun Apr 12, 2009 9:05 pm Post subject:
|
 |
|
The reason for the error is that you are writing to register FULL from two different always blocks. Combine all of the logic into one always block to make this work. The two always blocks *look* like they make sense, but from a Verilog standpoint, they don't know about each other.
something like:
Code: |
always @ ( READ or WRITE )
begin
if ( READ ) FULL = 1;
else if ( WRITE ) FULL = 0;
end
|
I'm not sure if what I wrote is exactly what you need for the actual logic you want to express, but whatever you do, you must make sure the FULL is written within a single always block by a logic tree that is unambiguous.
For the most part in my designs, I try to make always blocks like:
Code: |
always @ ( posedge clk ) // where 'clk' is the system clock
begin
if ( READ ) FULL <= 1;
else if ( WRITE ) FULL <= 0;
end
|
This structure makes sure that things happen only on a rising system clock edge. That may not be possible in your design, but I have found in my designs (all are music synth designs) that this has so far always been the case. While you _can_ sense an edge on other signals, I think (as in 'it is my opinion') it is usually best to try to do this with a system clock.
Hope this helps. _________________ FPGA, dsPIC and Fatman Synth Stuff
Time flies like a banana. Fruit flies when you're having fun. BTW, Do these genes make my ass look fat? corruptio optimi pessima
|
|
Back to top
|
|
 |
skrasms
Joined: Feb 21, 2008 Posts: 121 Location: Portland, OR
|
Posted: Sun Apr 12, 2009 9:49 pm Post subject:
|
 |
|
Thank you for the response.
I spent a couple more hours on this today, and have some more points/questions.
According to the Verilog book that I have, it is valid to have:
Code: |
always @(condition 1)
assign some_var = 1;
always @(condition 2)
assign some_var = 0;
|
Without the assign statements it is a conflict, but adding "assign" removes the conflict by automatically de-assigning the old value and assigning the newest. The Quartus II help file says that while Verilog supports this, Quartus does not.
Clocking this block could work, but the point is to be asynchronous. I would rather have this block be complicated and keep everything else simple than make this block simple and add in additional clocks and synchronization problems to the rest of the system.
I tried code like what you posted that groups everything together. It took some serious nesting get the kind of behavior I need. It takes 20ns in simulation on one CPLD, and doesn't work on another. I'm still trying to figure that out. The code is this:
Code: |
module testing(FULL, ADDR, CLKIN);
input CLKIN;
input [2:0] ADDR;
output FULL;
reg FULL;
reg PREV_CLK;
always
@(CLKIN or ADDR)
begin
if(CLKIN!=PREV_CLK) //check for edge on CLKIN
begin
if(CLKIN==1) //rising edge detected
begin
FULL = 1;
end
PREV_CLK = CLKIN;
end
else //change on ADDR
begin
FULL = 0;
end
end
endmodule
|
I took out everything that doesn't relate to the "FULL" bit for clarity and testing. _________________ Software and Hardware Design |
|
Back to top
|
|
 |
JovianPyx

Joined: Nov 20, 2007 Posts: 1988 Location: West Red Spot, Jupiter
Audio files: 224
|
Posted: Sun Apr 12, 2009 10:10 pm Post subject:
|
 |
|
"assign" cannot be used with a register object type, only with a wire object type. At least that's never worked for me.
If you are attempting to set a register's contents to different values under different logic conditions, then you must do so within the same always block.
-- note that my experience is with Xilinx FPGA parts... when I have tried to set a register value within more than one always block, I have received the error that you received. Combining the logic into a single always block has always fixed the problem.
It may not produce elegant looking code, however, if the code works, then I consider it correct from a pragmatic standpoint.
Are you sure that you can't do this based on an always block conditioned only by the system clock? It seems to me that you should be able to do that. What's odd about what you wrote is the sensed condition of ADDR. If you use the system clock to capture the state of ADDR as OLD_ADDR and compare OLD_ADDR to ADDR you can sense when ADDR changes and use that signal to do whatever else you want to do. But I am accustomed to using an FPGA which is an ocean of fabric compared to a CPLD. _________________ FPGA, dsPIC and Fatman Synth Stuff
Time flies like a banana. Fruit flies when you're having fun. BTW, Do these genes make my ass look fat? corruptio optimi pessima
|
|
Back to top
|
|
 |
skrasms
Joined: Feb 21, 2008 Posts: 121 Location: Portland, OR
|
Posted: Sun Apr 12, 2009 10:18 pm Post subject:
|
 |
|
ScottG wrote: | "assign" cannot be used with a register object type, only with a wire object type. At least that's never worked for me.
If you are attempting to set a register's contents to different values under different logic conditions, then you must do so within the same always block.
-- note that my experience is with Xilinx FPGA parts... when I have tried to set a register value within more than one always block, I have received the error that you received. Combining the logic into a single always block has always fixed the problem.
It may not produce elegant looking code, however, if the code works, then it I consider it correct from a pragmatic standpoint. |
This sounds like a place where theory and real life differ. If it doesn't work for Altera or Xilinx, it's probably not a good idea.
I double-checked the code I posted at the end of my last message, and it's actually not simulating how I would expect on any CPLD. It's acting like a monostable multivibrator. _________________ Software and Hardware Design |
|
Back to top
|
|
 |
JovianPyx

Joined: Nov 20, 2007 Posts: 1988 Location: West Red Spot, Jupiter
Audio files: 224
|
Posted: Sun Apr 12, 2009 10:22 pm Post subject:
|
 |
|
I'm curious - you said that you were able to construct the logic based on an always block sensing only posedge of the system clock, but that it was complex - did that logic simulate correctly? _________________ FPGA, dsPIC and Fatman Synth Stuff
Time flies like a banana. Fruit flies when you're having fun. BTW, Do these genes make my ass look fat? corruptio optimi pessima
|
|
Back to top
|
|
 |
skrasms
Joined: Feb 21, 2008 Posts: 121 Location: Portland, OR
|
Posted: Sun Apr 12, 2009 10:45 pm Post subject:
|
 |
|
The last block of code I posted was meant to combine rising edge detection (of CLKIN) with output reading detection (based on ADDR changing). In simulation it shows up as a monostable multivibrator triggered on rising edges of CLKIN. That is, when CLKIN goes from low to high, FULL goes from low to high to low. I only want it to reset when the signal on the ADDR pins changes, but it resets on its own. _________________ Software and Hardware Design |
|
Back to top
|
|
 |
JovianPyx

Joined: Nov 20, 2007 Posts: 1988 Location: West Red Spot, Jupiter
Audio files: 224
|
Posted: Sun Apr 12, 2009 10:56 pm Post subject:
|
 |
|
Have you tried to construct the logic based on:
Code: |
always @ ( posedge CLKIN )
begin
// stuff
end
|
?
Doing this means that all flipflops are clock by the same clock and all of the logic you create controls only the flip flop enables.
Like:
Code: |
always @ ( posedge CLKIN )
begin
if ( SOMETHING ) REGISTER <= VALUE;
else ...
end
|
Here, REGISTER gets VALUE only if SOMETHING is true. Otherwise, the else logic is valid instead.
------------------------------------------------------------------------------------
Another way to approach this might be to work at the gate level. I.e., if you can put this together with ANDs ORs NANDs NORs XORs etc, that might also work.
EDIT: Reading this over, I realize that you probably know this. What I'm getting at is - have you tried this, however ugly it might be? And if you did, does it simulate correctly? I also realize that you are doing something in a much smaller fabric space than I am accustomed to, so pardon my inexperience in that. _________________ FPGA, dsPIC and Fatman Synth Stuff
Time flies like a banana. Fruit flies when you're having fun. BTW, Do these genes make my ass look fat? corruptio optimi pessima
|
|
Back to top
|
|
 |
jksuperstar

Joined: Aug 20, 2004 Posts: 2503 Location: Denver
Audio files: 1
G2 patch files: 18
|
Posted: Mon Apr 13, 2009 11:08 am Post subject:
|
 |
|
For verilog, to use a clock along with an asynchronous low-assertion reset, it's coded as follows:
Code: |
always@(posedge CLK or negedge RESET)
if (!RESET) register <= 0;
else
register <= something_else;
|
Something_else only getting assigned upon a rising edge of CLK, as you would expect from a D-type flip-flop.
That last code snippet you had seemed to do what I have listed here. If you do a change detection on your address (register address, then xor it with the newly registered version, or just detect the WRITE or READ that effects ADDR in the first place), you could use that as a replacement for RESET here.
Also, you should always use non-blocking assignments ( "<=") for flops and memory elements, otherwise you could get a latch, or something else not intended if all the cases aren't defined for the register element in question.
If you needed a true asynchronous set-reset flop, you should check the part you are using, to see if they are supported by the library. The Altera documentation will have this information. It should also have a coding style example, just for clarity. |
|
Back to top
|
|
 |
skrasms
Joined: Feb 21, 2008 Posts: 121 Location: Portland, OR
|
Posted: Mon Apr 13, 2009 7:16 pm Post subject:
|
 |
|
I'm essentially trying to make a 16x1 asynchronous FIFO. I don't know if that's the right number order, but it's supposed to be 16 bits wide, 1 stage deep. I can run 4x CD74HC40105, but that seems like a lot of waste at 16x16.
The buffer fits in like this:
uP #1 -> buffer -> uP #2
Where the two microprocessors have independent (and separately variable, but that's another story) clocks.
Altera has a drop-in "FIFO" block, of course, but it doesn't allow for less than 4 stages. 4x16 = 64, which is already every macrocell in a $2 CPLD.
Quote: |
Also, you should always use non-blocking assignments ( "<=") for flops and memory elements, otherwise you could get a latch, or something else not intended if all the cases aren't defined for the register element in question.
|
Pardon my ignorance, but why don't I want latch behavior?
I'm grateful for the discussion, it's helping me understand practical Verilog. _________________ Software and Hardware Design |
|
Back to top
|
|
 |
jksuperstar

Joined: Aug 20, 2004 Posts: 2503 Location: Denver
Audio files: 1
G2 patch files: 18
|
Posted: Mon Apr 13, 2009 8:21 pm Post subject:
|
 |
|
I assume you have two different microcontrollers, each with an asynchronous bus? Hence, without a clock, you're hoping to have an asynchronous "FIFO" (honestly, I've never seen a 1-deep FIFO, though the term does seem to fit!).
If my assumptions are right, in most hardware and software terms, you're looking for a mailbox register, with hardware spin-lock. One uP writes the mailbox, and that in turn sends an IRQ, or other, to the 2nd uP. Meanwhile, the 1st uP can't write again until the mailbox has been read/cleared.
In an FPGA, the 4 deep FIFO could work just fine for you, in fact it would allow for longer messages to be passed before being locked out. There is no increase in latency, as a FIFO tracks where each data is written, so the read can happen right away. And it won't cost much, since each Logic Cell that has 1 lookup table, and 1 register, and it can turn the look up table into a "memory" to be used for a FIFO). But, you're in a CPLD...
The real dilemma in asynchronous design is in race conditions. That one in a billion chance of the timing happening just right, to foil your logic. Which is why you don't want a latch. It makes that case happen much more often. And at MHz designs, the failure can happen more often than you think!
All said, a Set-Reset flop might be ok, as long as you make sure you read that the FIFO is not full, THEN do the next write (in the 1st uP). If you can, avoid doing a check on address change, and just have the mailbox set to either a single register, or an empty range of registers (less bits to decode).
So:
Code: |
// This adress is whatever you need it to be, less bits = less logic
`DEFINE MAILBOX 0xFF0000
// uP#1 : Writes to mailbox sets spinlock
assign mbox_sel1 = (ADDR1 == `MAILBOX) & write_1;
// uP#2 : Reads from mailbox clears spinlock
assign mbox_sel2 = (ADDR2 == `MAILBOX) & read_2;
reg spinlock;
always@(mbox_sel1 or mbox_sel2)
if (mbox_sel1) // Write from 1st uP
spinlock <= 1;
else if (mbox_sel2) // Read from 2nd uP
spinlock <= 0;
else // hold previous value, this section optional, as compiler should detect this
spinlock <= spinlock;
|
Further, you can protect the write of the FIFO with the value of the spinlock, to prevent mistakes in your code from happening. Better yet, you can use it to flag an error IRQ to tell you about it! |
|
Back to top
|
|
 |
urbanscallywag

Joined: Nov 30, 2007 Posts: 317 Location: sometimes
|
Posted: Fri Apr 17, 2009 11:14 pm Post subject:
|
 |
|
Asynchronous designs in CPLD/FPGA are just asking for trouble, especially for beginners.
I think what you should be building is a dual-clock FIFO, though this is more commonly done in FPGA where you have block RAM to work with.
Cross clock domain circuits are not easy. |
|
Back to top
|
|
 |
|