Intel® Quartus® Prime Software
Intel® Quartus® Prime Design Software, Design Entry, Synthesis, Simulation, Verification, Timing Analysis, System Design (Platform Designer, formerly Qsys)
17252 Discussions

SRAM IP that work on some builds, and some it doesn't!

Altera_Forum
Honored Contributor II
3,018 Views

Hello All! 

 

 

I'm having an issue implementing some VERY simple IP for an asynchronous SRAM chip (on digikey: http://www.digikey.com/product-detail/en/is61wv25616bll-10bli/706-1104-nd/1831380). It's really making me doubt myself.  

 

 

It's just a dumb bit of code, that's I've used years ago on an old project (Quartus II 9.1 I think) 

module sram( 

// global clk/reset 

clk, 

reset_n, 

// avalon slave 

s_chipselect_n, 

s_byteenable_n, 

s_write_n, 

s_read_n, 

s_address, 

s_writedata, 

s_readdata, 

 

// SRAM interface 

SRAM_DQ, 

SRAM_ADDR, 

SRAM_UB_n, 

SRAM_LB_n, 

SRAM_WE_n, 

SRAM_CE_n, 

SRAM_OE_n 

); 

parameter DATA_BITS = 16; 

parameter ADDR_BITS = 18; 

input clk; 

input reset_n; 

input s_chipselect_n; 

input [(DATA_BITS/8-1):0] s_byteenable_n; 

input s_write_n; 

input s_read_n; 

input [(ADDR_BITS-1):0] s_address; 

input [(DATA_BITS-1):0] s_writedata; 

output [(DATA_BITS-1):0] s_readdata; 

output SRAM_CE_n; 

output SRAM_OE_n; 

output SRAM_LB_n; 

output SRAM_UB_n; 

output SRAM_WE_n; 

output [(ADDR_BITS-1):0] SRAM_ADDR; 

inout [(DATA_BITS-1):0] SRAM_DQ; 

assign SRAM_DQ = SRAM_WE_n ? 'hz : s_writedata; 

assign s_readdata = SRAM_DQ; 

assign SRAM_ADDR = s_address; 

assign SRAM_WE_n = s_write_n; 

assign SRAM_OE_n = s_read_n; 

assign SRAM_CE_n = s_chipselect_n; 

assign {SRAM_UB_n,SRAM_LB_n} = s_byteenable_n; 

endmodule 

[/INDENT] 

 

 

That's it, just 54 lines with white space.  

 

The issue I'm having is that: 

 

  1. Using Quartus II 12.1 Build 177, I will build the project, and it works 100%. 

  2. Then, I'll change something very very simple in the Verilog, recompile and find that my Nios2 will not run - and gives me a verify failed error: 

  3. https://mail.google.com/mail/u/1/?ui=2&ik=13b831dd1d&view=att&th=13e8b81cdbc4b34e&attid=0.0.1&disp=emb&realattid=ii_13e8b7772d7b4a5d&zw&atsh=1  

  4. The change can be as simple as moving a single output to a different pin on the device, and then nios2 just won't execute for SRAM verify failure. I'm losing my cool by this point. 

  5. Now, if I go back to Quartus and just hit *compile* again, without making any changes at all, the new SOF works fine, Nios2 verifies and runs from SRAM... really lost my cool now. 

 

 

 

If Quartus uses the same fitter seed each time where's the random'ness come from? It should compile exactly the same sof each time... but I'm getting different results. 

 

 

The SRAM doesn't have any electrical faults - it's highly reliable when Quartus builds it right. It's fast enough to read single cycle (10ns cycle) on a Nios2/e running at 50MHz. I have two working tested boards that I'm testing on, both give me identical results. I've sprayed them with cold spray to test for bad soldering, damage to the devices from reflow, etc. All Quartus settings are default, and I have rebuilt my project from scratch many times - I use Quartus shell and a TCL script to load assigmnents for pins and IO voltage - nothing else is changed. 

 

Is this my fault or is Quartus screwing me over here... ? I'm downloading 13.0 to see if it does the same. I'm not great with TimeQuest, but I can't see any warnings, all my slack is +ve as it's a simple design. There are NO critical warnings in the whole compilation.  

 

Please critique my code and tell me if it's my fault - am I having asynchronous issues? Should I register the signals in and out? It's an asychronous RAM with 10ns performance, it shouldn't be necessary right? The avalon bus will make all synchronous when it samples? 

 

Please help... (whimpering noise)...
0 Kudos
9 Replies
Altera_Forum
Honored Contributor II
1,523 Views

Yes, you're having timing issues. I'm actually amazed that design works at all...  

 

Asynchronous SRAMs have a number of timing relationships that you need to take care of. The timings of the write sequence are particularly tricky. 

Simply connecting the async SRAM signals to the Avalon bus won't work.
0 Kudos
Altera_Forum
Honored Contributor II
1,523 Views

It probably only works at all because there is a bus width adapter just before it that is likely to sanitise the write signals.

0 Kudos
Altera_Forum
Honored Contributor II
1,523 Views

Thanks Guys, 

 

To take care of the timing sequences, do i just need to constrain the device IO in an SDC file? Is that the best way to go about it? 

 

My understanding was that the aSRAM would latch the data out upon presentation of WE_n, CS_n and ADDR. The timing of this device is 4.5ns setup for a read, with 0ns hold requirement. The avalon bus would then sample the DATA on clock rising, job done...
0 Kudos
Altera_Forum
Honored Contributor II
1,523 Views

The write enable signal (from the Avalon faric) is only valid on the relevant clock edge (and probably qualified by some other signals). 

It could quite possibly be asserted (for short times) at any other time - which will generate random writes to your SRAM. 

So while you can do completely async reads, you have to synchronise the writes to the avalon clock.
0 Kudos
Altera_Forum
Honored Contributor II
1,523 Views

Thanks DSL, 

 

I've tried that, with this code, which has the same behaviour: 

 

module sram ( // global clk/reset input wire clk, input wire reset_n, // avalon slave input wire s_chipselect_n, input wire s_byteenable_n, input wire s_write_n, input wire s_read_n, input wire s_address, input wire s_writedata, output wire s_readdata, // SRAM interface inout wire SRAM_DQ, output reg SRAM_ADDR, output reg SRAM_UB_n, output reg SRAM_LB_n, output reg SRAM_WE_n, output reg SRAM_CE_n, output reg SRAM_OE_n ); parameter DATA_BITS = 16; parameter ADDR_BITS = 18; // internal registers reg writedata_reg; // combinatorial outputs assign SRAM_DQ = SRAM_WE_n ? 'hz : writedata_reg; assign s_readdata = SRAM_DQ; // synchronous registers always @ ( posedge clk ) begin if ( s_chipselect_n == 0 ) // if this component selected begin writedata_reg <= s_writedata; // register the write data off the bus SRAM_ADDR <= s_address; // clock through other outputs to sram SRAM_WE_n <= s_write_n; SRAM_OE_n <= s_read_n; SRAM_CE_n <= s_chipselect_n; { SRAM_UB_n,SRAM_LB_n } <= s_byteenable_n; end end endmodule  

 

What SignalTap is tell me, is that there is no chip select, no write and no read signal. So the bus is trying to read from the SRAM address space, but the control signals are not being asserted... In Nios I'm looping a memory test over the SRAM space. Could this be a problem on the avalon bus side of things? Is my code being optimised out for some reason?
0 Kudos
Altera_Forum
Honored Contributor II
1,523 Views

Also, note that these pins aren't shared. There's no flash or anything - the interface just belongs to the SRAM IC.

0 Kudos
Altera_Forum
Honored Contributor II
1,523 Views

Well... in your most recent paste of code, your "if ( s_chipselect_n == 0 )" doesn't have any "else" to it, so SRAM_CE_n in particular is going to be stuck low the first time the if() gets hit. 

 

Taking a step back: 

 

In your original code and statement of problem, ignoring the correctness of your approach, if it works in one compile and doesn't work in another compile, this is a somewhat typical symptom of bad / insufficient timing constraints. You should fix that first. 

 

As far as your direct attempt at simply mapping SRAM pins to Avalon pins, you can probably get something workable that way using the _hw.tcl parameters to control the strobes if necessary. But I think the "Generic Tri-State Controller" component in Qsys is possibly the off-the-shelf component you are seeking. It has presets for several NOR flash and SRAM chips, and I don't think your chip can be too different.
0 Kudos
Altera_Forum
Honored Contributor II
1,523 Views

Thanks Ted, 

 

I've fixed the ( CS == 0 ) issue. :-) 

 

I'm hoping to fix this in TimeQuest with constraints. I've added below to my sdc, to account for SRAM time to clock out (tCO) and board delay (BDa): 

 

set_output_delay -add_delay -clock "clk_50" -max [expr $local_osc_period - $SRAM_tCO_max - $SRAM_BDa_max] [get_ports {sram_*}]  

 

Where  

[LIST] 

local_osc_period = 20 

SRAM_tCO_max = 10.5 

SRAM_BDa = 0.15 

[/LIST] 

 

My understanding is that this would ensure the fitter places the design so the propagation delay from FPGA -> Pin is less than 20-10.5-.15 = 9.35ns. That way I can keep the memory single cycle access; I don't want latency, so don't want to over-register everything. It works right now, but I'm going to need to test and look closer to ensure it's a solution, not just luck of the fitter. 

 

Can you advise what other constraints I should add?
0 Kudos
Altera_Forum
Honored Contributor II
1,523 Views

No, you got that reverse. 

You're telling the fitter it has 9.35 of maximum external delay, so in this case it will try to keep the internal FPGA delays it under 10.65 ns. 

 

 

Note that with aSRAM, the write sequence generaly needs to ensure you setup valid address and data a bit before you activate the write enable and you hold those valid address and data for a bit after you've disabled the write enable. 

Otherwise, you risk writing random stuff into random addresses. 

You need a small state machine to ensure that...
0 Kudos
Reply