Community
cancel
Showing results for 
Search instead for 
Did you mean: 
Altera_Forum
Honored Contributor I
775 Views

Off by 1 error with Altera SRAM controller IP?

I have a Nios II system running on a DE2-115 that is connected to both the DRAM and SRAM on board. I have written a VGA driver that uses the avalon bus to fetch pixel data from either DRAM or SRAM, depending on the address stored in a register. The system works flawlessly when reading from DRAM. However, when I change the address to point at the SRAM chip instead, the output on the monitor shifts right by 1 pixel. 1 Pixel is 16 bits, the word size of the SRAM chip.  

 

Memory is written by the Nios II core and read by this simple module I wrote:  

 

module vga_dram_master( //clk domain input clk, input resetn, input start, input read_from_addr, //avalon master for accessing SDRAM output master_address, output master_read, input master_read_data, input master_wait_request, input master_read_data_valid, //VGA_CLK domain input VGA_CLK, input read_pixel, output pixel_out ); //draw green on the screen if the fifo bottoms out wire data_out; assign pixel_out = rdempty ? 16'h03E0 : data_out; //fifo to buffer data and bridge clock domains wire rdempty, wrfull; wire wrusedw; vga_pixel F1(!resetn | start, master_read_data, VGA_CLK, read_pixel, clk, master_read_data_valid, data_out, rdempty, wrfull, wrusedw); //pipelined access assign master_address = currAddress; assign master_read = !wrusedw && (wordsRead < 19'd480000) && (currAddress != 0); reg currAddress; reg wordsRead; always @ (posedge clk or negedge resetn) begin if(!resetn) begin currAddress <= 32'd0; wordsRead <= 19'd0; end else begin if (start) begin currAddress <= read_from_addr; wordsRead <= 19'd0; end else if (!master_wait_request && master_read) begin wordsRead <= wordsRead + 1'd1; currAddress <= currAddress + 2'd2; end end end endmodule  

 

I have poured over this code looking for mistakes, but I haven't found any. And, everything works perfectly when accessing DRAM! Here is a simple program I wrote for the Nios Core to demonstrate the problem. I can flick the switch back and forth and see the image on monitor move by 1 pixel.  

 

int main(void) { uint16_t *SRAM = (uint16_t*)0x20000000; uint16_t *DRAM = (uint16_t*)0x08000000; VGA = 0; //disable the screen for a second //draw the same gradient background into both buffers gradient(SRAM); gradient(DRAM); flush_dcache(); //this commented line fixes the issue. But why is it happening in the first place!!!?!? //SRAM++; uint16_t* buff = {SRAM , DRAM }; while(1) { //wait for screen refresh while(!VGA); //read from DRAM or SRAM based on 0th switch VGA = (uint32_t)buff & 1]; } return 0; }  

 

Really unsure what is happening here.
0 Kudos
3 Replies
Altera_Forum
Honored Contributor I
71 Views

Have you tried memory testing the SRAM using Nios by itself? It almost sounds like the off-chip timings are incorrect and you are reading data too late.

Altera_Forum
Honored Contributor I
71 Views

 

--- Quote Start ---  

Have you tried memory testing the SRAM using Nios by itself? It almost sounds like the off-chip timings are incorrect and you are reading data too late. 

--- Quote End ---  

 

 

Talking about timings made me check my timequest settings, they were wrong. After fixing them, I'm now failing timing with a Recovery path between read_from_addr on the clk domain and the output of the VGA pixel fifo (from the verilog in the first post) 

 

slack: -2.156 ns 

from_node: nios2:u0|VGA_Controller:vga_controller|fbAddr[7]  

to_node: nios2:u0|VGA_Controller:vga_controller|VGA_driver:VGA0|vga_dram_master:DM0|vga_pixel:F1|dcfifo_mixed_widths:dcfifo_mixed_widths_component|dcfifo_c1l1:auto_generated|altsyncram_mv61:fifo_ram|q_b[0] 

launch clock: P0|altpll_component|auto_generated|pll1|clk[0] (my 90 MHz system clock) 

latch clock: P0|altpll_component|auto_generated|pll1|clk[2] (the VGA pixel clock - 40 MHz) 

 

I don't really understand what is happening here - I have the register 'currAddress' in between the input 'read_from_addr' (which is driven by fbAddr). So why is timing failing on this path, when it shouldn't even exist? Shouldn't there be a node 'currAddress' in the middle of that path? 

 

The SRAM issue is probably a symptom of this problem - when I was running the FPGA again today, the offset was different.
Altera_Forum
Honored Contributor I
71 Views

What does the full path show in Timequest? It should show you all the hops between the from_node and the to_node. A recovery timing failure means that an asynchronous signal is arriving too late to the latch destination. The full path might show why the launching address has an asynchronous path to the output of the FIFO RAM. I suspect the full path will look something like this: fbAddr[7] --> Qsys decode logic --> rdreq of DCFIFO --> q_b[0] but I'm not sure why DCFIFO would have an asynchronous load/set/reset in this case dependent on the read request coming at it though. 

 

Did you recompile the design after making the timing changes? If not I would close the Quartus project, delete the /db directories, then recompile because it could be that the fitter spent so much time fixing a setup issue that it introduced recovery failures and re-running the fitter might fix that.
Reply