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++
Announcements
FPGA community forums and blogs on community.intel.com are migrating to the new Altera Community and are read-only. For urgent support needs during this transition, please visit the FPGA Design Resources page or contact an Altera Authorized Distributor.
12748 Discussions

dcache questions, bug in alt_dcache_flush

Altera_Forum
Honored Contributor II
1,913 Views

The alt_dcache_flush function from the hal may not correctly flush all dirty data in the cache. Consider the case where I want to flush the contents of a video buffer that is larger than the data cache. 

 

const alt_u32 VideoRamSize = 38400; 

BYTE videoRam[VideoRamSize]; 

 

alt_dcache_flush(videoRam, sizeof(videoRam)); 

 

The current hal implementation uses the flushda instruction. If the data cache size is 8k the function limits the address range that may be flushed to the first 8k of the videoRam buffer (comment: "This is the most we would ever need to flush"). If the buffer was modified beyond this range and these addresses are cached they will not be flushed. This results in a screen full of garbled pixels. 

I changed the hal function to use the flushd instruction as in earlier versions. Then everything works as expected. One can also comment out: len = NIOS2_DCACHE_SIZE; now flushda also works but this leads to more iterations in the for loop. 

 

 

Could someone explain how flushd really works? In alt_dcache_flush(void *start, alt_u32 length) flushd is passed an address and in alt_dcache_flush_all an index starting at 0. 

 

 

Is there a way to invalidate an address range in the cache even if it is never modified by the processor? In my case some component other than the processor continuously writes data to a memory buffer. A program running on the NIOSII reads this data for further processing. So the data is never dirty from the processor's point of view. I would like to force the processor to invalidate any cached addresses from this buffer before starting a read-out cycle. If I read the documentation correctly the flushd instruction won't work and I have to use the IORD_32DIRECT macro. 

 

 

Are there any recommendations what cache line size to use depending on the data cache size and application type?
0 Kudos
4 Replies
Altera_Forum
Honored Contributor II
1,173 Views

Hi orsino, 

 

> alt_dcache_flush(videoRam, sizeof(videoRam)); 

>  

> The current hal implementation uses the flushda instruction. If the data cache 

> size is 8k the function limits the address range that may be flushed to the first 8k 

> of the videoRam buffer (comment: "This is the most we would ever need to flush"). 

 

Sounds like a bug. Based on the documentation, flushda does recognize the tag, 

so alt_dcache_flush() should (must) flush the entire effective address range. 

 

> I changed the hal function to use the flushd instruction as in earlier versions. Then 

> everything works as expected. 

 

This makes sense ... since flushd ignores the tag, the address range (span, 

whatever) would be limited to the size of the dcache. 

 

> Could someone explain how flushd really works? 

 

flushd ignores the tag, flushes the line if dirty, then invalidates. The key phrase 

being: "ignores the tag". When you use flushd, you may end up flushing data that 

is not actually in the effective address range of your buffer (only the line indexes 

are the same). This is actually a cool feature when your I/O buffers are larger 

than your cache -- you save time by (more or less) flushing cache lines, rather 

than entire effective address ranges. 

 

flushda is new ... so my experience is with it is limited. However the docs do 

suggest that the tags are _not_ ignored -- when using flushda, you need to 

check the entire effective address range. (That's why it sounds like a bug to me). 

 

Perhaps the HAL gurus could comment on this. 

 

> Is there a way to invalidate an address range in the cache even if it is 

> never modified by the processor? 

 

This always bothered me. The flushd documentation states, "if the line is dirty, 

flushd writes the line back to memory and invalidates the line". But it doesn't 

state what happens if the line is _not_ dirty -- I've always assumed that the 

line is invalidated in either case ... but I really don't know for sure. 

 

Regards, 

--Scott
0 Kudos
Altera_Forum
Honored Contributor II
1,173 Views

This does look like a bug in alt_dcache_flush(). I'll get it fixed. The fix should be to# ifdef out the code that limits len when flushda exists. Here's what what a fixed version looks like: 

 

void alt_dcache_flush (void* start, alt_u32 len) 

{# if NIOS2_DCACHE_SIZE > 0 

 

char* i; 

char* end;  

# ifndef NIOS2_FLUSHDA_SUPPORTED 

/* 

* This is the most we would ever need to flush. 

*/ 

 

if (len > NIOS2_DCACHE_SIZE) 

len = NIOS2_DCACHE_SIZE; 

}# endif /* NIOS2_FLUSHDA_SUPPORTED */ 

 

end = ((char*) start) + len;  

 

for (i = start; i < end; i+= NIOS2_DCACHE_LINE_SIZE) 

{  

ALT_FLUSH_DATA(i);  

 

/*  

* For an unaligned flush request, we&#39;ve got one more line left. 

* Note that this is dependent on NIOS2_DCACHE_LINE_SIZE to be a  

* multiple of 2 (which it always is). 

*/ 

 

if (((alt_u32) start) & (NIOS2_DCACHE_LINE_SIZE - 1)) 

ALT_FLUSH_DATA(i); 

# endif /* NIOS2_DCACHE_SIZE > 0 */ 

 

As for the behavior of the flushd instruction when the line is not dirty, it is invalidated.
0 Kudos
Altera_Forum
Honored Contributor II
1,173 Views

Hi All, 

 

> > I would like to force the processor to invalidate any cached addresses from this 

> > buffer before starting a read-out cycle. 

 

> > I&#39;ve always assumed that the line is invalidated in either case ... but I really don&#39;t 

> > know for sure. 

 

> As for the behavior of the flushd instruction when the line is not dirty, it is invalidated. 

 

And there you have it ... thanks James! ... ya gotta love this forum :-) 

 

So you can call flushd to invalidate ... regardless of the dirty state. If your buffer 

is larger than the cache, you&#39;ll do best just calling alt_dcache_flush_all() ... and 

save the extra iterations. 

 

Regards, 

--Scott
0 Kudos
Altera_Forum
Honored Contributor II
1,173 Views

Hi all, 

 

In my system, I have gotten 6 buffers for splash screens, video and OSD.  

 

pOSDFrameBufferLA = (unsigned short*)alt_uncached_malloc(DUAL_VIEW_FRAME_SIZE*2 + 128); 

 

The expression above will allocate a OSD buffer which will never be cached. 

 

Nios have 4GB address space, but we can use only 2G. Because the higher 2GB is mapped to the lower 2GB. The only difference between higher 2GB and lower 2GB is that the higher 2GB will always bypass the cache. 

 

FYI http://forum.niosforum.com/work2/style_emoticons/<#EMO_DIR#>/biggrin.gif  

 

David
0 Kudos
Reply