Skip to content

Commit

Permalink
Merge pull request #101 from DC-SWAT/master
Browse files Browse the repository at this point in the history
Improved cache management
  • Loading branch information
ljsebald committed Feb 10, 2023
2 parents 497683a + 678c374 commit 73e6bd8
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 40 deletions.
56 changes: 53 additions & 3 deletions kernel/arch/dreamcast/include/arch/cache.h
@@ -1,17 +1,20 @@
/* KallistiOS ##version##
arch/dreamcast/include/cache.h
(c)2001 Dan Potter
Copyright (C) 2001 Dan Potter
Copyright (C) 2014, 2016, 2023 Ruslan Rostovtsev (SWAT)
*/

/** \file arch/cache.h
\brief Cache management functionality.
This file contains definitions for functions that manage the cache in the
Dreamcast, including functions to flush and invalidate the caches.
Dreamcast, including functions to flush, invalidate, purge, prefetch and
allocate the caches.
\author Dan Potter
\author Ruslan Rostovtsev (SWAT)
*/

#ifndef __ARCH_CACHE_H
Expand All @@ -22,6 +25,13 @@ __BEGIN_DECLS

#include <arch/types.h>

/** \brief SH4 cache block size.
The physical address will be aligned to this size in all
functions except dcache_alloc_write.
*/
#define CPU_CACHE_BLOCK_SIZE 32

/** \brief Flush the instruction cache.
This function flushes a range of the instruction cache.
Expand All @@ -48,13 +58,53 @@ void dcache_inval_range(uint32 start, uint32 count);
back on all of the data in the specified range. This does not invalidate the
cache in the process (meaning the blocks will still be in the cache, just
not marked as dirty after this has completed). If you wish to invalidate the
cache as well, call dcache_inval_range() after calling this function.
cache as well, call dcache_inval_range() after calling this function or
use dcache_purge_range() instead of dcache_flush_range().
\param start The physical address to begin flushing at.
\param count The number of bytes to flush.
*/
void dcache_flush_range(uint32 start, uint32 count);

/** \brief Purge the data/operand cache.
This function flushes a range of the data/operand cache, forcing a write-
back and invalidate on all of the data in the specified range.
\param start The physical address to begin purging at.
\param count The number of bytes to purge.
*/
void dcache_purge_range(uint32 start, uint32 count);

/** \brief Prefetch memory to the data/operand cache.
This function prefetch a range of the data/operand cache.
\param start The physical address to begin prefetching at.
\param count The number of bytes to prefetch.
\return The physical address aligned to cache block size.
*/
void *dcache_pref_range(uint32 start, uint32 count);

/** \brief Prefetch one block to the data/operand cache.
This function prefetch a range of the data/operand cache.
\param src The buffer to prefetch.
\return The buffer aligned to cache block size.
*/
static inline __attribute__((always_inline))
void *dcache_pref_block(const void *src)
{
uint32 __cache_aligned = ((uint32)src) & ~(CPU_CACHE_BLOCK_SIZE - 1);
__asm__ volatile ("pref @%[ptr]\n"
:
: [ptr] "r" (__cache_aligned)
:
);
return (void *)__cache_aligned;
}

__END_DECLS

#endif /* __ARCH_CACHE_H */
Expand Down
84 changes: 47 additions & 37 deletions kernel/arch/dreamcast/kernel/cache.s
Expand Up @@ -9,6 +9,8 @@
.globl _icache_flush_range
.globl _dcache_inval_range
.globl _dcache_flush_range
.globl _dcache_purge_range
.globl _dcache_pref_range

! r4 is starting address
! r5 is count
Expand Down Expand Up @@ -52,7 +54,7 @@ flush_loop:
mov r4,r7 ! v & 0xfffffc00
and r3,r7

add #32,r4 ! += L1_CACHE_BYTES
add #32,r4 ! += CPU_CACHE_BLOCK_SIZE
cmp/hs r4,r5
bt/s flush_loop
mov.l r7,@r6 ! *addr = data
Expand Down Expand Up @@ -96,26 +98,10 @@ _dcache_inval_range:

dinval_loop:
! Invalidate the O cache
ocbi @r4 ! r4

mov #0x10,r0 ! r4 | 0x1000
shll8 r0
or r4,r0
ocbi @r0

mov #0x20,r0 ! r4 | 0x2000
shll8 r0
or r4,r0
ocbi @r0

mov #0x30,r0 ! r4 | 0x3000
shll8 r0
or r4,r0
ocbi @r0

ocbi @r4
cmp/hs r4,r5
bt/s dinval_loop
add #32,r4 ! += L1_CACHE_BYTES
add #32,r4 ! += CPU_CACHE_BLOCK_SIZE

rts
nop
Expand All @@ -135,31 +121,55 @@ _dcache_flush_range:
dflush_loop:
! Write back the O cache
ocbwb @r4

mov #0x10,r0 ! r4 | 0x1000
shll8 r0
or r4,r0
ocbwb @r0

mov #0x20,r0 ! r4 | 0x2000
shll8 r0
or r4,r0
ocbwb @r0

mov #0x30,r0 ! r4 | 0x3000
shll8 r0
or r4,r0
ocbwb @r0

cmp/hs r4,r5
bt/s dflush_loop
add #32,r4 ! += L1_CACHE_BYTES
add #32,r4 ! += CPU_CACHE_BLOCK_SIZE

rts
nop


! This routine just goes through and forces a write-back and invalidate
! on the specified data range.
! r4 is starting address
! r5 is count
_dcache_purge_range:
! Get ending address from count and align start address
add r4,r5
mov.l l1align,r0
and r0,r4

dpurge_loop:
! Write back and invalidate the O cache
ocbp @r4
cmp/hs r4,r5
bt/s dpurge_loop
add #32,r4 ! += CPU_CACHE_BLOCK_SIZE

rts
nop

! This routine prefetch to operand cache the specified data range.
! r4 is starting address
! r5 is count
_dcache_pref_range:
! Get ending address from count and align start address
add r4,r5
mov.l l1align,r0
and r0,r4
mov r4,r6

dpref_loop:
! Prefetch to the O cache
pref @r4
cmp/hs r4,r5
bt/s dpref_loop
add #32,r4 ! += CPU_CACHE_BLOCK_SIZE

rts
mov r6,r0


.align 2
l1align:
.long ~31 ! ~(L1_CACHE_BYTES-1)
.long ~31 ! ~(CPU_CACHE_BLOCK_SIZE-1)
2 changes: 2 additions & 0 deletions kernel/exports.txt
Expand Up @@ -165,6 +165,8 @@ thd_block_now
icache_flush_range
dcache_inval_range
dcache_flush_range
dcache_purge_range
dcache_pref_range

# Low-level debug I/O
dbgio_set_irq_usage
Expand Down

0 comments on commit 73e6bd8

Please sign in to comment.