FPGARelated.com
Forums

FPGA to SRAM port interface

Started by oen_br October 9, 2006
I'm interfacing an FPGA to a multiplexed SRAM port (ALE, READ, WRITE,
DATA/ADDR bus).
I want to read from/write to the FPGA internal block RAM (SPARTAN 3E),
using burst accesses.

This is a write access example.
           ____
ALE    ___/    \__________________________________________________
       _______________        __        __        __        ______
WRITE#                \______/  \______/  \______/  \______/
            ________  ________  ________  ________  ________
DTADD  ____/  ADDR  \/ DATA0  \/ DATA1  \/ DATA2  \/ DATA3  \______
           \________/\________/\________/\________/\________/

For the address load and increment I combined ALE, READ and WRITE
signals to generate one clock signal.
CLOCK <= WRITE# and READ# and (not ALE);

The problem is, to determine if I must load a new address I must know
if it is the ALE cycle:

if rising_edge (CLOCK) then
   if (ALE = '1') then  -- problem
      ADDRESS_REG <= DTADD;
   else
      ADDRESS_REG <= ADDRESS_REG+1;
   end if;
end if;

But the clock is a delayed version ALE, READ# and WRITE#, so the
setup/hold times will no be met!

What's the best way of doing this?

Of course I can use an auxiliar signal:
if rising_edge (ALE) then
   LOAD_ADDR <= '1';
end if;
if ((WRITE# = '0') or (READ# = '0')) then  -- asyncronous clear
   LOAD_ADDR <= '0';
end if;

And substitute:
   if (ALE = '1') then
for:
   if (LOAD_ADDR = '1') then

But now I have two clock sources/nets (CLOCK and ALE)!

Any suggestions?

Luiz Carlos

oen_br schrieb:

> I'm interfacing an FPGA to a multiplexed SRAM port (ALE, READ, WRITE, > DATA/ADDR bus). > I want to read from/write to the FPGA internal block RAM (SPARTAN 3E), > using burst accesses. > > This is a write access example. > ____ > ALE ___/ \__________________________________________________ > _______________ __ __ __ ______ > WRITE# \______/ \______/ \______/ \______/ > ________ ________ ________ ________ ________ > DTADD ____/ ADDR \/ DATA0 \/ DATA1 \/ DATA2 \/ DATA3 \______ > \________/\________/\________/\________/\________/ > > For the address load and increment I combined ALE, READ and WRITE > signals to generate one clock signal. > CLOCK <= WRITE# and READ# and (not ALE);
Clock signal for what? The BRAM inside the FPGA? NO WAY!
> The problem is, to determine if I must load a new address I must know > if it is the ALE cycle: > > if rising_edge (CLOCK) then > if (ALE = '1') then -- problem > ADDRESS_REG <= DTADD; > else > ADDRESS_REG <= ADDRESS_REG+1; > end if; > end if; > > But the clock is a delayed version ALE, READ# and WRITE#, so the > setup/hold times will no be met! > > What's the best way of doing this?
Use a clean clock (from a XO or so) to clock the FPGA logic. Not clock gating etc.! Build text book style FSMs to contol the BRAM and generate appropiate signals for your external SRAM. Than it will work fine. Hint. Register at least WRITE# to the SRAM, so it will not glitch.
> But now I have two clock sources/nets (CLOCK and ALE)!
No, you have just one system clock, that generates all other signals. A clean 1 clock design. Just too easy ;-) Regards Falk
Hi Falk,

> Clock signal for what? The BRAM inside the FPGA? NO WAY!
Yes, for the BRAM too. Why not? The ALE, READ# and WRITE# signals will never overlap!
> Use a clean clock (from a XO or so) to clock the FPGA logic. Not clock > gating etc.! Build text book style FSMs to contol the BRAM and generate > appropiate signals for your external SRAM. Than it will work fine. > > Hint. Register at least WRITE# to the SRAM, so it will not glitch.
I don't know what 'XO' means, but I think you mean a crystal (it reminded me Galactica Colonel Tigh :-) ). Anyway the tranfer rate is 60MHz (mega transfers per second), so, to sample ALE, etc, I will need a very high frequency clock signal (200MHz maybe?). Even if it is possible, it will spend a lot of power! Did I misunderstand you? There is no external SRAM, just the internal BRAM used as a mail box! Two processors, each one using one BRAM port. Thank's, Luiz Carlos.
oen_br wrote:
> I'm interfacing an FPGA to a multiplexed SRAM port (ALE, READ, WRITE, > DATA/ADDR bus). > I want to read from/write to the FPGA internal block RAM (SPARTAN 3E), > using burst accesses. > > This is a write access example. > ____ > ALE ___/ \__________________________________________________ > _______________ __ __ __ ______ > WRITE# \______/ \______/ \______/ \______/ > ________ ________ ________ ________ ________ > DTADD ____/ ADDR \/ DATA0 \/ DATA1 \/ DATA2 \/ DATA3 \______ > \________/\________/\________/\________/\________/ > > For the address load and increment I combined ALE, READ and WRITE > signals to generate one clock signal. > CLOCK <= WRITE# and READ# and (not ALE); > > The problem is, to determine if I must load a new address I must know > if it is the ALE cycle: > > if rising_edge (CLOCK) then > if (ALE = '1') then -- problem > ADDRESS_REG <= DTADD; > else > ADDRESS_REG <= ADDRESS_REG+1; > end if; > end if;
In order for the CLOCK signal to go high, ALE must be low, in your logic, since (not ALE) is AND'd with WRITE# and READ#. So that implies inside your 'if' the ALE='1' can never be true. Perhaps changing your logic to falling_edge(CLOCK) might fix it within your approach. Or invert the CLOCK signal from what it is now. -Dave -- David Ashley http://www.xdr.com/dash Embedded linux, device drivers, system architecture
> In order for the CLOCK signal to go high, ALE must > be low, in your logic, since (not ALE) is AND'd with > WRITE# and READ#. So that implies inside your > 'if' the ALE='1' can never be true. > > Perhaps changing your logic to falling_edge(CLOCK) > might fix it within your approach. Or invert the CLOCK > signal from what it is now.
Hi David, The clock is right, I need to load the address at the falling edge of ALE. If you consider ALE falling edge generated the rising clock edge, ALE must be low at this point. So, ok, it should be "if (ALE = '0') then". But I'm not sure if the time taken by logic (inverting and anding ALE), and buffering this signal/clock will offer the sufficient setup time for the test. I mean, will it always work? Can I change the speed grade or the family of the FPGA ? Do I need to use some type of time constraint? Luiz Carlos
oen_br schrieb:

>>Clock signal for what? The BRAM inside the FPGA? NO WAY! > > > Yes, for the BRAM too. Why not? > The ALE, READ# and WRITE# signals will never overlap!
You better learn about synchronous design. And glitching of clocks.
> I don't know what 'XO' means, but I think you mean a crystal (it
Yes.
> reminded me Galactica Colonel Tigh :-) ). > Anyway the tranfer rate is 60MHz (mega transfers per second), so, to > sample ALE, etc, I will need a very high frequency clock signal (200MHz > maybe?). Even if it is possible, it will spend a lot of power! > Did I misunderstand you?
> > There is no external SRAM, just the internal BRAM used as a mail box! > Two processors, each one using one BRAM port.
Ahhhh, the FPGA is used to connect two processors, right? Hmm, in this xase why do you want to use a FPGA? There are dedicaded dual port memories, ready to use. www.idt.com Regards Falk
oen_br wrote:
>>In order for the CLOCK signal to go high, ALE must >>be low, in your logic, since (not ALE) is AND'd with >>WRITE# and READ#. So that implies inside your >>'if' the ALE='1' can never be true. >> >>Perhaps changing your logic to falling_edge(CLOCK) >>might fix it within your approach. Or invert the CLOCK >>signal from what it is now. > > > Hi David, > > The clock is right, I need to load the address at the falling edge of > ALE. > If you consider ALE falling edge generated the rising clock edge, ALE > must be low at this point. > So, ok, it should be "if (ALE = '0') then". > But I'm not sure if the time taken by logic (inverting and anding ALE), > and buffering this signal/clock will offer the sufficient setup time > for the test. I mean, will it always work? Can I change the speed grade > or the family of the FPGA ? > Do I need to use some type of time constraint? > > Luiz Carlos >
The whole point is you want to write the first data at the address specified, the next data at the next address... what if when you load the first address you do a "-1" calculation right then? So when the first data is to get loaded, it does its "+1" and you're at the real address you wanted. So you are loading the address right at the start of each cycle, plenty of setup + hold time in all cases. I just don't like your logic of testing ALE inside the clocked section -- when the clock itself depends on ALE. This is really questionable, get that out of the picture and things will get simpler. -Dave -- David Ashley http://www.xdr.com/dash Embedded linux, device drivers, system architecture
David Ashley wrote:
> oen_br wrote: > >>>In order for the CLOCK signal to go high, ALE must >>>be low, in your logic, since (not ALE) is AND'd with >>>WRITE# and READ#. So that implies inside your >>>'if' the ALE='1' can never be true. >>> >>>Perhaps changing your logic to falling_edge(CLOCK) >>>might fix it within your approach. Or invert the CLOCK >>>signal from what it is now. >> >> >>Hi David, >> >>The clock is right, I need to load the address at the falling edge of >>ALE. >>If you consider ALE falling edge generated the rising clock edge, ALE >>must be low at this point. >>So, ok, it should be "if (ALE = '0') then". >>But I'm not sure if the time taken by logic (inverting and anding ALE), >>and buffering this signal/clock will offer the sufficient setup time >>for the test. I mean, will it always work? Can I change the speed grade >>or the family of the FPGA ? >>Do I need to use some type of time constraint? >> >>Luiz Carlos >> > > > The whole point is you want to write the first data at > the address specified, the next data at the next address... > what if when you load the first address you do a "-1" > calculation right then? So when the first data is to > get loaded, it does its "+1" and you're at the real > address you wanted. So you are loading the address > right at the start of each cycle, plenty of setup + hold > time in all cases. > > I just don't like your logic of testing ALE inside the > clocked section -- when the clock itself depends on > ALE. This is really questionable, get that out of the > picture and things will get simpler. > > -Dave >
I've been looking at this more...it seems easy on the face of it but it's somewhat complicated. You want when ALE goes from high to low for the address latch to get the initial address you want to load. And when READ# or WRITE# go from low to high, you want the address latch to get its current value plus one. This implies 2 clocks...which is out of my experience but I suspect isn't synthesizable. Now, if you could have a set-reset latch in the picture that would make everything easy. When ALE is high, the SR goes to 1. When READ# or WRITE# go low, the SR goes to 0. Your original post had the LOAD_ADDR signal getting set when there was a rising_edge of ALE, and an async clear when READ# or WRITE# go low, which is the 2 clock problem in the first place. When would do it is an async set instead of the clocked set. You don't need any clocking on this. I suppose you could describe the logic as 2 nand gates. I looked at xst.pdf and couldn't find a simple set/reset flip flop. Unisim has an entity FDCP which is: D Flip-Flop with Asynchronous Clear and Preset architecture FDCP_V of FDCP is begin VITALBehavior : process(C, CLR, PRE) variable FIRST_TIME : boolean := true ; begin if (FIRST_TIME = true) then Q <= TO_X01(INIT); FIRST_TIME := false; end if; if (CLR = '1') then Q <= '0'; elsif (PRE = '1') then Q <= '1'; elsif (rising_edge(C)) then Q <= D after 100 ps; end if; end process; end FDCP_V; So that would translate to if ALE = '1' then LOAD_ADDR <= '1'; else if READ# = '0' or WRITE# = '0' then LOAD_ADDR <= '0'; end if; However this is an implied latch...which is probably ok in this instance because there is no combinatorial feedback. I'm in over my head. I wish one of the gurus would offer some advice here. :) -Dave -- David Ashley http://www.xdr.com/dash Embedded linux, device drivers, system architecture
oen_br wrote:

> ____ > ALE ___/ \__________________________________________________
CLK _-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-
> _______________ __ __ __ ______ > WRITE# \______/ \______/ \______/ \______/ > ________ ________ ________ ________ ________ > DTADD ____/ ADDR \/ DATA0 \/ DATA1 \/ DATA2 \/ DATA3 \______ > \________/\________/\________/\________/\________/ >
> But the clock is a delayed version ALE, READ# and WRITE#, so the > setup/hold times will no be met!
No, you want the continuous clock that generated ALE. In a synchronous system, ALE is an input, not a clock. -- Mike Treseler
> You better learn about synchronous design. And glitching of clocks.
Falk, I'm aware of the danger of gererated clocks, but in this case I couldn't see any problem (at least until now). The signals are clean and have some nano-seconds between their activation.
> Ahhhh, the FPGA is used to connect two processors, right? > Hmm, in this xase why do you want to use a FPGA? There are dedicaded > dual port memories, ready to use.
Not really. The FPGA, besides other functions, connects 4 DSPs, a shared external SRAM and a PCI controller, everybody talking to everybody. I thought this kind of problem was very common (combinatorial clocks using it's source signals as clock enables)! Thanks, Luiz Carlos