Nios® V/II Embedded Design Suite (EDS)
Support for Embedded Development Tools, Processors (SoCs and Nios® V/II processor), Embedded Development Suites (EDSs), Boot and Configuration, Operating Systems, C and C++

Avalon-MM master and cache

Altera_Forum
Honored Contributor II
1,291 Views

Hi, 

I have designed a fifo controller for a sopc system based on Nios II -f with data cache. It is used to read data from FIFO to SRAM and consists of a avalon-MM slave interface and a master interface. The avalon-MM slave interface is used to config 4 registers: status, control, base address, length of transfer. 

 

The HDL design is all right, and the following program is a simple test for it:  

Step1, define a buffer and initialize it with a constant value.  

Step2, Config and start FIFO controller to read data from FIFO to buffer defined in step 1;  

Step3, Check the data. 

 

As the FIFO controller will write data directly to SRAM rather than cache, the Nios II processor is expected to write/read data directly to/from SRAM too. That's why address is bypassed through setting bit-31. The program runs ok as the data are exactly that in FIFO in step 3. 

 

Now the problem is that: 

Problem 1. Without alt_dcache_flush(fifo_data, sizeof(fifo_data)) in step 1, the first 4 words are 0x56789abc, which is the initial value, and the other data are right. I think alt_dcache_flush() should not matter as the initialization is done with cache bypassed? 

Problem 2. if alt_u32 fifo_data[64] is defined as global or static, the problem 1 disappears. I am sure that stack is sufficient. I think there is nothing to do with whether fifo_data[] is global or local? 

 

I am sure the problems have something to do with cache, but can't explain. 

Hope somebody can give me some clues. Thanks very much! 

 

 

int main() { 

alt_u32 i; 

alt_u32 fifo_data[64]; 

volatile alt_u32 *fifo_data_uncached; 

alt_u32 fifo_status, fifo_ctrl, fifo_base, fifo_length; 

alt_printf("The program is testing fifo controller.\r\n"); 

/* 1. Initialize buffer. 

* 1) As FIFO_CTRL has no data cache, it always access memory directly. 

* 2) Nios II processor should also access memory directly so that 

* the data is consistent with FIFO_CTRL. 

* 3) Call alt_remap_uncached() to remap a region of memory for 

* un-cached access, or set the 31-th bit of address to make a 

* direct access. */ 

fifo_data_uncached = (alt_u32 *)((alt_u32)fifo_data | (1<<31)); 

for(i=0;i<sizeof(fifo_data)/4;i++){ 

fifo_data_uncached = 0x56789abc; 

alt_dcache_flush(fifo_data, sizeof(fifo_data)); 

/* 2. configure fifo controller and then start it. 

* 1) there are four registers: status, control, length and base. 

* write base register with the address of buffer, 

* the length register with the length of transfer, 

* and then set the go_bit of control register to start. 

* 2) check the done_bit of status register to determine when 

* the transfer is completed. */ 

iowr_fifo_base(fifo_ctrl_0_base, ((alt_u32)fifo_data)); 

iowr_fifo_length(fifo_ctrl_0_base, sizeof(fifo_data)); 

iowr_fifo_ctrl(fifo_ctrl_0_base, (1<<go_bit)); 

while(1){ 

fifo_status = iord_fifo_status(fifo_ctrl_0_base); 

if(fifo_status & (1<<done_bit)) break; 

/* 3. check the data written by fifo controller. */ 

for(i=0;i<sizeof(fifo_data)/4;i++){ 

if(i%16==0) alt_printf("\r\n"); 

alt_printf("%x ", fifo_data_uncached); 

while(1); 

}
0 Kudos
2 Replies
Altera_Forum
Honored Contributor II
303 Views

First using the cache flush or invalidate functions on data buffers that aren't aligned with cache lines (32 bytes by default I think) can lead to all sort of problems. You may end up with one part of the cache line that contains valid data while the other doesn't, and executing a flush or invalidate function on that line will lead to memory corruption. When you declare your table as a local variable, it is allocated on the stack and probably not aligned correctly. The best way to ensure correct alignment is to declare it as static or glabal, and use gcc's __aligned__ attribute. 

You are right that you shouldn't use the flush function if you use a cache bypass pointer. In fact the flush function can only make things worse, as it can overwrite the values you just put in memory with old values from the cache. On the other hand you should use an invalidate function to signal the CPU that you put new values in memory and that its cache line isn't valid anymore. If you don't do it, the CPU may overwrite your fifo_data buffer with values from its cache at any moment. But As I said before, this is dangerous if the buffer isn't aligned on a cache line. As the area is the stack, you could end up having bad values in other local variables.
0 Kudos
Altera_Forum
Honored Contributor II
303 Views

In this case the addresses you are accessing uncached are presumably an avalon slave. 

The important thing there is to ensure that you NEVER access those addresses with cache enabled accesses.
0 Kudos
Reply