Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Address Generator for Dual Port RAM

Status
Not open for further replies.

oliglaser

Junior Member level 3
Joined
Feb 26, 2010
Messages
31
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,286
Location
Manchester, UK
Activity points
1,688
Hi all,

I have recently started with Verilog and FPGAs (I have plenty of experience in most other aspects of electronics though)
I am prototyping a medium speed USB oscilloscope (>50Msps, hopefully up to 250Msps) using an Actel ProASIC3 150k gate device, and a PIC18F which handles the passing of data to the PC ans selecting gain ranges for the opamps etc.
I am using an ABC soft core on the FPGA with a UART to talk to the PIC (easy to use for now whilst learning about things, maybe use SPI or parallel, with a state machine later)
I have manged to get it working at 50Msps, using the above with a dual port RAM. All these are Actel IP cores, but I had to write a Verilog module to generate the addresses for the RAM whilst clocking the ADC (I'm using two clocks, 20MHz for the ABC CPU, and 50MHz for the address generator and ADC clock)
It was a process of trial and error but I managed to get it working and synthesised, but I would like someone to look at the code and pull it to bts, tell me where I could do things better etc. Also it didn't work in simulation (after synthesis, okay before) until I changed the st and rst sensitivities to negedge, which puzzles me - if a signal triggers some action on itself, is the level before or after the edge valid? In books I have seen standard flipflops use posedge signals that operate on them selves but this does not work in my code below..
Anyway, here it is, please feel free to tell me how bad it is :)


Code:
// AddressGen2.v


module AddressGen2
(
input wire start,
input wire reset,
input wire clk,
output wire[7:0] address
);

reg st;
reg rst;
reg q;
reg [7:0] add;


always @(posedge clk)
begin

    st <= start;

    if(reset)
    begin
        if(q)
        add <= add + 1;
        else
        add <= 8'b00000000;
    end
    else
    begin
    add <= 8'b00000000;
    end

end

always @(posedge clk)
begin

    if(add == 8'b11111111)
    begin
    rst <= 1;
    end
    else
    begin
    rst <= 0;
    end

end

// q did not work (remained at x) until changed to negedge, but the st needs 
// to be at 1 to start the cycle? does it read the level before the edge?

always @(negedge st, negedge rst, posedge reset) 
begin

    if(reset)
    begin
        if(st)
        q <= 1'b1;
        
        if(rst)
        q <= 1'b0;
    end
    else
    q <= 1'b0;

end


assign address = add;

endmodule
 

"and a PIC18F" "250MHz" I suspect you'll end up with the proasic.

keep in mind that 250MSPS will, for any useful case, require compression. 250MBps = 2Gbps. 2000Mbps > 480Mbps from USB2's ideal rate. thus 8b continous resolution isn't feasible at USB2 speeds. for snapshot cases, sure, USB will work fine.


for FPGA's it is generally best to use only two items for the synchronous always blocks:
posedge rst (for active high resets) or negedge rst (for active low resets)
posedge clk (for normal designs) or negedge clk (for special cases)

there are other style choices that you use that I disagree with (coming from a VHDL/C background, I like begin/end). that is up to your supervisors though.

The main goal of writing HDL for FPGAs is writing something that maps well to actual hardware. most vendors will give appnotes and whitepapers on good style. For example, Xilinx suggests that you list conditions resulting in 0 with the highest priority, followed by conditions resulting in 1, followed by conditions resulting in logic-based results. This is because the hardware has built in registers that give priority to resets first, then sets, then other.

As always, you must take care when using multiple clocks. Async signals can easily destroy a design without warning. Most tools won't attempt to find timing constraints between clock domains, as such is (in the general case) impossible. When skew and other optimizations (retiming is particularly bad) are used, there is little that can be said about the timing.

in your design, you might not always have an FPGA that allows three *edge events in the sensitivity list. the always block for q might not work in all cases. in general, the *edge events are reserved for registers.

your design style is better than most first attempts at HDL. (as long as you are aware that the always blocks are _evaluated_ at the same instant, then the results _assigned_ slightly later)
 
"and a PIC18F" "250MHz" I suspect you'll end up with the proasic.

keep in mind that 250MSPS will, for any useful case, require compression. 250MBps = 2Gbps. 2000Mbps > 480Mbps from USB2's ideal rate. thus 8b continous resolution isn't feasible at USB2 speeds. for snapshot cases, sure, USB will work fine.

Thanks for the reply - I understand about the USB bottleneck, the prototype is actually built and running (at 80Msps now since my post) All the PIC is doing is relaying the data to the PC, it *may* be replaced with something like a FTxxx USB to parallel/serial IC, but the PIC is reasonably cheap and can handle the other logic okay, so it may stay. I intend to start looking at compression etc (be nice if USB 3.0 was available..) and see what's possible there.
As far as the Verilog - thanks for some encouragement there, I am part of a small business so I am basically my own supervisor for stuff like this, and responsible for pretty much end to end production (to save costs initially it was decided not to hire/outsource a lot at the moment)
So I'm doing a lot of learning as quickly as possible about all aspects of PCB/digital design that I didn't know about before.
The multiple clocks is not so bad here I think, as there is only the start signal from the ABC core that "crosses" domains, as the data is read back from the other port of dual port RAM. Seems to work okay anyway, I am going to try pushing the speed up a bit more and see where I get to (I will use some sort of 8 to 32 shift register for the higher speeds so I only need to clock at 1/4 the speed for most of it, this seems sensible to me..)
The always block for q was the problem for me, took a bit of research to figure out where I was going wrong, and I thought (as you have confirmed) it may not synthesise correctly on every chip, so I was a bit uncomfortable about this bit. I wasn't sure how do it otherwise though, as I need a start signal (no problem) but then it needs to turn itself off (which was what I had problems implementing and could not find an example in the books I have (or I missed it)
I will take your advice on the vendor specific stuff and read the Actel guide to writing HDL for their chips as there is plenty I need to pick up quickly (I noticed one on the website) - looks like I have a lot more reading to do.. :roll:

Are there any good books that concentrate mostly on the synthesis side of Verilog? (I have one called "FPGA prototyping by Verilog examples" which is quite good, but would like to know about more)
Thanks again for the help.
 

"as there is only the start signal from the ABC core that "crosses" domains"
This is actually one of the classics. I've seen multiple designs where this simple assumption just outright broke the design. In synchronous state machines, any async signal -- even reset -- is a critical signal. To aid in your design process:

any async signal -- even reset -- is a critical signal.
any async signal -- even reset -- is a critical signal.
any async signal -- even reset -- is a critical signal.
(it really is worth repeating as many times as needed. Such signals can result in lab/field failures, and can easily be missed by sims)

The state will be represented "somehow" with some number of bits. Any async signals can result in some of these bits transitioning correctly, and other not. The classic design has an async reset or async "trigger", and a 1-hot state machine. in this case, there is a chance that the async signal will reach the deassert idle state logic before reaching the assert start state. in this case, the one-hot state machine transitions into a dead state. There are other, more complex cases, where the state machine enters multiple states in the same cycles.

The most important thing you can do is to absolutely confirm that async nets will NOT in any possible case adversely affect the design. This is because async signals can and will break a design at ANY clock rate (even < 1 Hz) if you are not careful.

For FPGA designs, you are mainly going to use always blocks for either registers (posedge/negedge of clk/rst as needed) and combinatorial logic. For verilog, its traditional to ONLY use non-blocking assigns within a process describing registers. For always blocks describing combinatorial logic, blocking assigns are often used to improve simulation time. (the process will not update a signal affecting its own sensitivity list as often).

(of course, in some cases, async signals will work anyways. But its very poor practice to rely on async signals to work in a logical manner. Only when both the designer and the analysis confirm the async signal work as intended should such a practice be deemed acceptable.)
 
"as there is only the start signal from the ABC core that "crosses" domains"
This is actually one of the classics. I've seen multiple designs where this simple assumption just outright broke the design. In synchronous state machines, any async signal -- even reset -- is a critical signal. To aid in your design process:

any async signal -- even reset -- is a critical signal.
any async signal -- even reset -- is a critical signal.
any async signal -- even reset -- is a critical signal.
(it really is worth repeating as many times as needed. Such signals can result in lab/field failures, and can easily be missed by sims)

Thanks, got the message loud and clear there :)
I will make sure I remember this - I am *trying* to follow the synchronous design method, as I read this is the best way to go for most (if not all) designs.

I actually thought I had got it right with the start signal in my address generator - the start signal is clocked into the st register on the posedge of clk (top always block), and it's the edge of st that starts the address incrementing.
From what I read, I got the impression that you can deal with async signals by clocking then through a flip flop - am I wrong here? If so how would I go about making sure my start signal doesn't cause problems? (i.e how would I change my code?)
Also, what I am still not sure of is why I need to use negedge for the st signal to start it off (set q to 1) in the bottom always block - I thought that on the falling edge, the logic would detect a 0 (the final position after the edge) rather than the level before the edge (1). Unless there is some magic going on I am unaware of, that is what it is doing otherwise it would not be working, as q is set to 1 if st is high, and when q is high the address starts incrementing - this does not quite add up with my understanding of flip flops.
Would really appreciate this bit clearing up..
 

The below edge sensitive always block isn't synthesizable, I fear. (Nor did I understand it's purpose, but that's less important)
Code:
always @(negedge st, negedge rst, posedge reset) 
begin

    if(reset)
    begin
        if(st)
        q <= 1'b1;
        
        if(rst)
        q <= 1'b0;
    end
    else
    q <= 1'b0;
end
There must be only one edge-sensitive condition.
 
  • Like
Reactions: blooz

    blooz

    Points: 2
    Helpful Answer Positive Rating
The below edge sensitive always block isn't synthesizable, I fear. (Nor did I understand it's purpose, but that's less important)

But it did synthesise and is working..

The block is meant to start the address incrementing with the start signal (which sets st), and then it stops itself when it reaches the highest value by toggling rst. This is apparently what is happening (it simulates correctly after synthesis too), and the data is being passed to the PIC and then the PC okay - I am viewing a 1MHz square wave on screen at the moment.

So, two questions:

1. How did it work if it's not meant be able to?

2. How can I code this in a better way to achieve the same function? (of the module turning itself off on reaching a certain address value)

Thanks for the help.
 

But it did synthesise and is working
I compiled the said block, and the compiler complained about the missing clock and generating combinational logic instead of a register.

The code is not following the rules for an edge sensitive always block, the result must be expected to be tool dependant or at worst unpredictable. I guess, the block should use clk, but I'm not sure about your intentions.
 
The async start is registered one time. This might be good enough. Its more common to see it registered twice, as this makes it very unlikely that the output will be metastable. When doing such, its also common to place attributes on these synchronization registers to prevent optimizations like retiming and register duplication. The synchronizer is really a structure, but is behaviorally inferred. I also like to give synchronization registers clear names -- that way if I see an async signal inside of a process I know that I intended it to be there. Either way, async signals are critical signals -- you have to put some thought into how they are used. I'd suggest using two registers. if latency is an issue, you might make two clocked always blocks, and clock reg1 on the negedge of the clock, reg2 on the posedge.

Verilog actually does allow three (i guess more) *edge events, but the results will be tool dependent. A register with async clear, async preset, and a clock can have all three. This is done for simulation performance -- if clear/preset is active low, then the always block only needs to be evaluated when the clear/preset signal falls or the clock rises. There isn't a need to evaluated the block on the clear rising event. Most registers will only make use of either the async clear, or the async preset.

That odd block should be moved to the clocked process. it stores the state idle/active for the design. You should then modify the design to remove the "rst". you might have "q" transition to a 1 upon st, and to 0 upon addr = 1's.
 
Thanks for the replies and clarification.

I checked the Actel HDL guide and noticed you can infer a register with three edge events - clear, preset, and clk, so maybe it has worked okay for the tools/FGPA I'm using. I got no warnings (I think) about combinational logic being inferred.

In any case, I see that it's not good practice, so I will have a mess about and try and make it more hardware/tool independent - I'll try moving the block as you say. I have done a bit more reading and am getting more of an idea of how things translate to hardware in Verilog. I guess it takes a while to get used to thinking in terms of hardware, rather than sequential C code etc. I'm enjoying the challenge though..

Thanks for all the replies, they have been most helpful.
 

I checked the Actel HDL guide and noticed you can infer a register with three edge events - clear, preset, and clk
But there is no clock defined in the said always block.
 

I know there is no clock - I thought I could use it in this way...

I am only starting off with Verilog so I probably don't get a lot of what is going on properly yet - all I know is it seems to work okay like this (not that I will leave it like this as I now know is not good) so the compiler must of figured out my intentions or something similar.

I am going through the signals now and looking at the synthesised gates etc, trying to work out why it is working. May take some time though as I am learning as I go along. I would like to understand it properly before I change the code as advised.

Any code examples of a better way to implement my module would be very much appreciated.
 

Another thing - I am looking at the signals *after* synthesis and I notice the q signal is low when the counter is incrementing, which is opposite to the actual code (it should be incrementing when q is 1, otherwise add is 00000000)
I can't figure out why this would be other than the synthesis tool doing something I am unaware of.
Does the compiler optimise stuff like this as it wishes and change signal logic levels? If so are there ways of forcing it not to?
I'm using Synplify Pro D-2009.
 

Does the compiler optimise stuff like this as it wishes and change signal logic levels? If so are there ways of forcing it not to?
Yes, it does. And it's usually reasonable to let it. The purpose of gate level logic is to implement the logic, not to visualize your Verilog code. But Synplify should have synthesis attributes to control the register inversion ("not push through") during synthesis. Check the manual.

I know there is no clock - I thought I could use it in this way...
An edge sensitive always block without a clock doesn't synthesise to flip-flop(s), it isn't effectively edge sensitive.
 

Thanks for clearing that up about the optimisation.

I removed the always block in question and put the logic in the other always block that is sensitive to the clk edge, and it works fine. Beginning to get the hang of it a bit now..

About it not synthesising to flip flop(s) - I thought you could use any signal as the edge sensitive signal, not necessarily a clock signal. What if you want to clock data in on a certain event and not on every clock cycle?
I know this could be done with next state logic and keeping it synchronous (I think I know what I mean :) ) but the purpose of that faulty always block was to use the rst edge (or st edge) as the trigger. Are you saying this is not possible? Why isn't it edge sensitive if you explicitly specify it as so? Does the compiler only recognise a clock signal? If so how does it know which is meant to be the clock signal?
To try and clarify what I am asking - is it possible to pick a signal other than a clock signal and use it to clock a flip flop? (as the edge sensitivity)

Sorry for all the questions, just want to be sure of this as it seems like a pretty fundamental point.
Thanks for all the help..
 

If signal is recognized as a clock in an edge sensitive always blocks is a matter of Verilog syntax. A clock only appears in the event condition, not in the block logic itself. You have it this way in the clock sensitive always block in your code.
 

Right I see what you mean, thanks. I'm going to do some more reading on how to infer the correct logic in Verilog. Trying to find some good books on the synthesis side of Verilog.
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top