electro-music.com   Dedicated to experimental electro-acoustic
and electronic music
 
    Front Page  |  Radio
 |  Media  |  Forum  |  Wiki  |  Links
Forum with support of Syndicator RSS
 FAQFAQ   CalendarCalendar   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   LinksLinks
 RegisterRegister   ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in  Chat RoomChat Room 
 Forum index » DIY Hardware and Software » Microcontrollers and Programmable Logic
Beginner Verilog Question
Post new topic   Reply to topic Moderators: State Machine
Page 1 of 1 [12 Posts]
View unread posts
View new posts in the last week
Mark the topic unread :: View previous topic :: View next topic
Author Message
skrasms



Joined: Feb 21, 2008
Posts: 121
Location: Portland, OR

PostPosted: Sun Apr 12, 2009 9:55 am    Post subject: Beginner Verilog Question Reply with quote  Mark this post and the followings unread

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
View user's profile Send private message
JovianPyx



Joined: Nov 20, 2007
Posts: 1988
Location: West Red Spot, Jupiter
Audio files: 224

PostPosted: Sun Apr 12, 2009 9:05 pm    Post subject: Reply with quote  Mark this post and the followings unread

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
View user's profile Send private message Visit poster's website
skrasms



Joined: Feb 21, 2008
Posts: 121
Location: Portland, OR

PostPosted: Sun Apr 12, 2009 9:49 pm    Post subject: Reply with quote  Mark this post and the followings unread

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
View user's profile Send private message
JovianPyx



Joined: Nov 20, 2007
Posts: 1988
Location: West Red Spot, Jupiter
Audio files: 224

PostPosted: Sun Apr 12, 2009 10:10 pm    Post subject: Reply with quote  Mark this post and the followings unread

"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
View user's profile Send private message Visit poster's website
skrasms



Joined: Feb 21, 2008
Posts: 121
Location: Portland, OR

PostPosted: Sun Apr 12, 2009 10:18 pm    Post subject: Reply with quote  Mark this post and the followings unread

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
View user's profile Send private message
JovianPyx



Joined: Nov 20, 2007
Posts: 1988
Location: West Red Spot, Jupiter
Audio files: 224

PostPosted: Sun Apr 12, 2009 10:22 pm    Post subject: Reply with quote  Mark this post and the followings unread

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
View user's profile Send private message Visit poster's website
skrasms



Joined: Feb 21, 2008
Posts: 121
Location: Portland, OR

PostPosted: Sun Apr 12, 2009 10:45 pm    Post subject: Reply with quote  Mark this post and the followings unread

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
View user's profile Send private message
JovianPyx



Joined: Nov 20, 2007
Posts: 1988
Location: West Red Spot, Jupiter
Audio files: 224

PostPosted: Sun Apr 12, 2009 10:56 pm    Post subject: Reply with quote  Mark this post and the followings unread

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
View user's profile Send private message Visit poster's website
jksuperstar



Joined: Aug 20, 2004
Posts: 2503
Location: Denver
Audio files: 1
G2 patch files: 18

PostPosted: Mon Apr 13, 2009 11:08 am    Post subject: Reply with quote  Mark this post and the followings unread

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
View user's profile Send private message Visit poster's website
skrasms



Joined: Feb 21, 2008
Posts: 121
Location: Portland, OR

PostPosted: Mon Apr 13, 2009 7:16 pm    Post subject: Reply with quote  Mark this post and the followings unread

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
View user's profile Send private message
jksuperstar



Joined: Aug 20, 2004
Posts: 2503
Location: Denver
Audio files: 1
G2 patch files: 18

PostPosted: Mon Apr 13, 2009 8:21 pm    Post subject: Reply with quote  Mark this post and the followings unread

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
View user's profile Send private message Visit poster's website
urbanscallywag



Joined: Nov 30, 2007
Posts: 317
Location: sometimes

PostPosted: Fri Apr 17, 2009 11:14 pm    Post subject: Reply with quote  Mark this post and the followings unread

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
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic Moderators: State Machine
Page 1 of 1 [12 Posts]
View unread posts
View new posts in the last week
Mark the topic unread :: View previous topic :: View next topic
 Forum index » DIY Hardware and Software » Microcontrollers and Programmable Logic
Jump to:  

You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Forum with support of Syndicator RSS
Powered by phpBB © 2001, 2005 phpBB Group
Copyright © 2003 through 2009 by electro-music.com - Conditions Of Use