Address Generator for Dual Port RAM

O

Oli

Guest
Hi all,

This is my first post here - I have recently started with Verilog and
FPGAs (I am not a beginner in 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 :)


// 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

always @(negedge st, negedge rst, posedge reset) // the st and rst did
not work until changed to negedge, but the st needs to be
begin //
at 1 to start the cycle? does it read the level before the edge?

if(reset)
begin
if(st)
q <= 1'b1;

if(rst)
q <= 1'b0;
end
else
q <= 1'b0;

end


assign address = add;

endmodule
 
On Sep 19, 4:43 am, Oli <o...@glasers.org> wrote:

I had to write a Verilog module to generate the addresses
Don't really know why this didn't get any replies sooner,
since it's an entirely sensible set of questions. Anyway,
here goes...

Your block that generates 'q' is really bizarre, and
doesn't follow the usual synthesis guidelines. I'm
not really quite sure what is going on. I think it's
probably quite easy to implement your logic without
that strange block but, before we look at that, let's
pick the offending code to pieces on its own terms...

always @(negedge st, negedge rst, posedge reset)
if(reset)
begin
if(st)
q <= 1'b1;
if(rst)
q <= 1'b0;
end
else
q <= 1'b0;
end
The if(reset) test is pretty much what you'd normally
do for an asynchronous active-high reset. However,
the reset action is not simply to force 'q' to a
constant value, but depends on other signals. This
implies a flop with asynch preload or, equivalently,
independent asynch set and reset. They're rare
beasts on FPGAs.

The else-branch of that if(reset) test is what would
normally be treated as the clocked part of such an
always-block. However, it's problematic because
you seem to have two clocks (negedge st, negedge rst).
This won't synthesise in general. And, of course, it
is not a smart move to use a FF's clock signal(s) in
its reset logic too. So, basically, we're in a mess.

So let's look at the remaining code to see if we can
divine what you really need to do with that reset
logic:

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
OK, so "reset" is an active-low, synchronous reset.
And 'q' is an active-low reset too! And 'st' is
just a resynchronized version of 'start'.

always @(posedge clk)
begin
if(add == 8'b11111111)
begin
rst <= 1;
end
else
begin
rst <= 0;
end
end
And this code just pulses 'rst' on the next clock cycle
after add==255. I don't really quite see how that ties
up with the expected behaviour of 'q' as controlled by
'reset'. What do you actually want to happen - the
addressing should stop as soon as it reaches 255???

I'm inevitably guessing here, but I suspect that what
you want is...
- holding "reset" true unconditionally drives the
address to zero
- if "reset" is false, pulsing "start" causes the
count to begin
- when the count reaches 255 it should stop, but it
should wrap around to zero anyway

So let's try that one again...

reg counting;
always @(posedge clk)
if (reset) begin
add <= 0;
counting <= 0;
end else if (counting) begin
if (add == 8'b11111111)
counting <= 0;
add <= add + 1;
end else if (start) begin
counting <= 1;
end

Note that this design has SYNCHRONOUS active-high reset.
If you want it to be an ASYNCHRONOUS reset, just change
the sensitivity list to be
always @(posedge clk or posedge reset)
If you want the reset active-low, that sensitivity list
for asynch reset would need to be
always @(posedge clk or negedge reset)
and, of course, the test must be "if(!reset)".

if a signal
triggers some action on itself, is the level before or after the edge
valid?
How do you mean, "valid"? If you trigger on @(posedge S)
and immediately test S, you'll find it is true - the value
you read is the value AFTER the edge; the edge has already
happened.

In books I have seen standard flipflops use posedge signals
that operate on them selves
Yes, just for asynch reset actions.

Standard flip-flop modelling code:

always @(posedge clock or posedge async_high_reset)
if (async_high_reset) begin
<<< reset flops to some constant value >>>
end else begin
<<< any actions you want to perform on the clock edge >>>
end

Note that the value of clock is NEVER sampled ANYWHERE in this
code except in the clock edge test. The value of the async
reset signal is sampled in an outermost if() statement to
decide whether you're resetting or not. Putting the active
(leading) edge of reset into the sensitivity list makes
the reset be asynchronous; if it doesn't appear in the
sensitivity list, then the reset is synchronous because
it's sampled in just the same way as any other input signal.
In general there should only be ONE clock and, possibly,
ONE asynchronous reset signal for any always-block. Multiple
clocks are a Bad Thing (TM), and multiple resets won't
synthesise except in a limited number of FPGA families.

Hope this helps, and at least partly makes up for the
group's dozy response!
--
Jonathan Bromley
 

Welcome to EDABoard.com

Sponsor

Back
Top