This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RFC: SH4 instruction cache invalidation


The cache coherency code for usermode only works right for the 8 KB
direct-mapped icache of the SH4-100 series.  The SH4-200 series uses
an 16 KB two-way set-associative cache, and there is now a whole zoo of
different cache sizes for two-way associativity coming out.
We don't want to burden small MCUs with huge ROM requirements to properly
invalidate huge caches they don't have, so we want to use just as much code
as we actually need.
The SH4A also has 4-way associative caches, so it needs different code
again.  It has a new opcode for icache invalidation, so it seems prudent
to use this.
I've used .word for icbi so we can assemble this with the current binutils,
but I don't know what the right value to put there is - the Renesas
web site appears to be very slow or down from here.

A lot of programs don't use nested-function trampolines, but we want
the linking to work automatically for those that do use them.
Thus, specifing the right icache invalidation object with --defsym or
a special object on the link line would be inappropriate, since that
would always pull the icache invalidation code in.  Using --wrap would
be a possibility, but a rather ugly one, as each --wrap option makes
only a binary choice (how to implement a multi-way choice with multiple
--wrap options and a number of symbol forwarding objects in a library
is left as an exercise to the reader ;-).
Thus, I use multiple libraries, each of which contain one implementation
of the ic_invalidate function.
I've set the default for 8 KB * 2 ways cache, since that works both
for the SH4-100 and the SH4-200 that have been made so far.
ICACHE_LINK_SPEC can be overridden in subtarget header files to
set a different default.

2004-03-09  J"orn Rennecke <joern.rennecke@superh.com>

	* config/sh/icache.asm, config/sh/lib1funcs.h:
	New files, broken out of:
	(config/sh/lib1funcs.asm).
	* config/sh/icache.asm (ic_invalidate): Support different cache
	sizes and associativities.
	* config/sh/icache-icbi.asm: New file.
	* sh.h (EXTRA_SPECS): Add icache_link_spec.
	(ICACHE_LINK_SPEC): Define.
	(LINK_SPEC): Use icache_link_spec.
	* t-sh: ($(T)icache08x1.a): Add new rule.
	($(T)icache02x2.a, $(T)icache04x2.a, $(T)icache08x2.a): Likewise.
	($(T)icache16x2.a, $(T)icache32x2.a, $(T)icache-icbi.a): Likewise.
	(EXTRA_MULTILIB_PARTS): Set to icache08x1.a.
	* t-elf: (EXTRA_MULTILIB_PARTS): Add icache*.a parts.

diff -p --new-file before/icache-icbi.asm ./icache-icbi.asm
*** before/icache-icbi.asm	Thu Jan  1 01:00:00 1970
--- ./icache-icbi.asm	Tue Mar  9 20:44:04 2004
***************
*** 0 ****
--- 1,37 ----
+ /* Copyright (C) 2004 Free Software Foundation, Inc.
+ 
+ This file is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+ 
+ In addition to the permissions in the GNU General Public License, the
+ Free Software Foundation gives you unlimited permission to link the
+ compiled version of this file into combinations with other programs,
+ and to distribute those combinations without any restriction coming
+ from the use of this file.  (The General Public License restrictions
+ do apply in other respects; for example, they cover modification of
+ the file, and distribution when not linked into a combine
+ executable.)
+ 
+ This file is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ General Public License for more details.
+ 
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING.  If not, write to
+ the Free Software Foundation, 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.  */
+ 
+ #include "lib1funcs.h"
+ 
+ #if defined(__SH4_SINGLE__) || defined(__SH4__) || defined(__SH4_SINGLE_ONLY__) || defined(__SH4_NOFPU__) && ! defined(__SH5__)
+ 	.global GLOBAL(ic_invalidate)
+ 	FUNC(GLOBAL(ic_invalidate))
+ GLOBAL(ic_invalidate):
+ 	ocbwb	@r4
+ 	rts
+ 	.word	0 ! ??? what value? ! icbi	@r4
+ 	ENDFUNC(GLOBAL(ic_invalidate))
+ #endif /* SH4 */
diff -p --new-file before/icache.asm ./icache.asm
*** before/icache.asm	Thu Jan  1 01:00:00 1970
--- ./icache.asm	Tue Mar  9 20:22:58 2004
***************
*** 0 ****
--- 1,64 ----
+ /* Copyright (C) 2000, 2001, 2002, 2004 Free Software Foundation, Inc.
+ 
+ This file is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+ 
+ In addition to the permissions in the GNU General Public License, the
+ Free Software Foundation gives you unlimited permission to link the
+ compiled version of this file into combinations with other programs,
+ and to distribute those combinations without any restriction coming
+ from the use of this file.  (The General Public License restrictions
+ do apply in other respects; for example, they cover modification of
+ the file, and distribution when not linked into a combine
+ executable.)
+ 
+ This file is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ General Public License for more details.
+ 
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING.  If not, write to
+ the Free Software Foundation, 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.  */
+ 
+ #include "lib1funcs.h"
+ 
+ #if defined(__SH4_SINGLE__) || defined(__SH4__) || defined(__SH4_SINGLE_ONLY__) || defined(__SH4_NOFPU__) && ! defined(__SH5__)
+ 	.global GLOBAL(ic_invalidate)
+ 	FUNC(GLOBAL(ic_invalidate))
+ GLOBAL(ic_invalidate):
+ 	ocbwb	@r4
+ 	mova	0f,r0
+ 	mov.w	1f,r1
+ /* Compute how many cache lines 0f is away from r4.  */
+ 	sub	r0,r4
+ 	and	r1,r4
+ /* Prepare to branch to 0f plus the cache-line offset.  */
+ 	add	# 0f - 1f,r4
+ 	braf	r4
+ 	add	#32-4,r1
+ 1:
+ 	.short	WAY_SIZE - 32
+ 	.p2align 5
+ /* This must be aligned to the beginning of a cache line.  */
+ 0:
+ 	.rept	WAYS-1
+ 	.rept	WAY_SIZE / 32 /* 8x1: there are 256 cache lines of 32 bytes.  */
+ 	braf	r1
+ 	.rept	15
+ 	nop
+ 	.endr
+ 	.endr
+ 	.endr
+ 	.rept	WAY_SIZE / 32 /* 8x1: there are 256 cache lines of 32 bytes.  */
+ 	rts
+ 	.rept	15
+ 	nop
+ 	.endr
+ 	.endr
+ 
+ 	ENDFUNC(GLOBAL(ic_invalidate))
+ #endif /* SH4 */
diff -p --new-file before/lib1funcs.asm ./lib1funcs.asm
*** before/lib1funcs.asm	Mon Feb 23 16:37:08 2004
--- ./lib1funcs.asm	Tue Mar  9 19:56:41 2004
*************** Boston, MA 02111-1307, USA.  */
*** 37,56 ****
     ELF local label prefixes by J"orn Rennecke
     amylaar@cygnus.com  */
  
! #ifdef __ELF__
! #define LOCAL(X)	.L_##X
! #define FUNC(X)		.type X,@function
! #define ENDFUNC0(X)	.Lfe_##X: .size X,.Lfe_##X-X
! #define ENDFUNC(X)	ENDFUNC0(X)
! #else
! #define LOCAL(X)	L_##X
! #define FUNC(X)
! #define ENDFUNC(X)
! #endif
! 
! #define	CONCAT(A,B)	A##B
! #define	GLOBAL0(U,X)	CONCAT(U,__##X)
! #define	GLOBAL(X)	GLOBAL0(__USER_LABEL_PREFIX__,X)
  
  #if ! __SH5__
  #ifdef L_ashiftrt
--- 37,43 ----
     ELF local label prefixes by J"orn Rennecke
     amylaar@cygnus.com  */
  
! #include "lib1funcs.h"
  
  #if ! __SH5__
  #ifdef L_ashiftrt
*************** GLOBAL(ic_invalidate):
*** 2082,2115 ****
  	synci
  	blink	tr0, r63
  	ENDFUNC(GLOBAL(ic_invalidate))
! #elif defined(__SH4_SINGLE__) || defined(__SH4__) || defined(__SH4_SINGLE_ONLY__)
! 	.global GLOBAL(ic_invalidate)
! 	FUNC(GLOBAL(ic_invalidate))
! GLOBAL(ic_invalidate):
! 	ocbwb	@r4
! 	mova	0f,r0
! 	mov.w	1f,r1
! /* Compute how many cache lines 0f is away from r4.  */
! 	sub	r0,r4
! 	and	r1,r4
! /* Prepare to branch to 0f plus the cache-line offset.  */
! 	add	# 0f - 1f,r4
! 	braf	r4
! 	nop
! 1:
! 	.short	0x1fe0
! 	.p2align 5
! /* This must be aligned to the beginning of a cache line.  */
! 0:
! 	.rept	256 /* There are 256 cache lines of 32 bytes.  */
! 	rts
! 	.rept	15
! 	nop
! 	.endr
! 	.endr
! 
! 	ENDFUNC(GLOBAL(ic_invalidate))
! #endif /* SH4 */
  #endif /* L_ic_invalidate */
  
  #if defined (__SH5__) && __SH5__ == 32
--- 2069,2075 ----
  	synci
  	blink	tr0, r63
  	ENDFUNC(GLOBAL(ic_invalidate))
! #endif /* SH5 */
  #endif /* L_ic_invalidate */
  
  #if defined (__SH5__) && __SH5__ == 32
diff -p --new-file before/lib1funcs.h ./lib1funcs.h
*** before/lib1funcs.h	Thu Jan  1 01:00:00 1970
--- ./lib1funcs.h	Tue Mar  9 19:55:00 2004
***************
*** 0 ****
--- 1,40 ----
+ /* Copyright (C) 1998, 2000, 2002 Free Software Foundation, Inc.
+ 
+ This file is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+ 
+ In addition to the permissions in the GNU General Public License, the
+ Free Software Foundation gives you unlimited permission to link the
+ compiled version of this file into combinations with other programs,
+ and to distribute those combinations without any restriction coming
+ from the use of this file.  (The General Public License restrictions
+ do apply in other respects; for example, they cover modification of
+ the file, and distribution when not linked into a combine
+ executable.)
+ 
+ This file is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ General Public License for more details.
+ 
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING.  If not, write to
+ the Free Software Foundation, 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.  */
+ 
+ #ifdef __ELF__
+ #define LOCAL(X)	.L_##X
+ #define FUNC(X)		.type X,@function
+ #define ENDFUNC0(X)	.Lfe_##X: .size X,.Lfe_##X-X
+ #define ENDFUNC(X)	ENDFUNC0(X)
+ #else
+ #define LOCAL(X)	L_##X
+ #define FUNC(X)
+ #define ENDFUNC(X)
+ #endif
+ 
+ #define	CONCAT(A,B)	A##B
+ #define	GLOBAL0(U,X)	CONCAT(U,__##X)
+ #define	GLOBAL(X)	GLOBAL0(__USER_LABEL_PREFIX__,X)
diff -p --new-file before/sh.h ./sh.h
*** before/sh.h	Mon Feb 23 16:37:12 2004
--- ./sh.h	Tue Mar  9 19:40:32 2004
*************** extern int target_flags;
*** 414,419 ****
--- 414,420 ----
    { "link_default_cpu_emul", LINK_DEFAULT_CPU_EMUL },		\
    { "subtarget_link_emul_suffix", SUBTARGET_LINK_EMUL_SUFFIX },	\
    { "subtarget_link_spec", SUBTARGET_LINK_SPEC },		\
+   { "icache_link_spec", ICACHE_LINK_SPEC },			\
    { "subtarget_asm_endian_spec", SUBTARGET_ASM_ENDIAN_SPEC },	\
    { "subtarget_asm_relax_spec", SUBTARGET_ASM_RELAX_SPEC },	\
    { "subtarget_asm_isa_spec", SUBTARGET_ASM_ISA_SPEC },		\
*************** extern int target_flags;
*** 465,470 ****
--- 466,473 ----
  #define SUBTARGET_LINK_EMUL_SUFFIX ""
  #define SUBTARGET_LINK_SPEC ""
  
+ #define ICACHE_LINK_SPEC "-licache08x2"
+ 
  /* svr4.h redefines LINK_SPEC inappropriately, so go via SH_LINK_SPEC,
     so that we can undo the damage without code replication.  */
  #define LINK_SPEC SH_LINK_SPEC
*************** extern int target_flags;
*** 475,481 ****
  %{m5-64media*:64}\
  %{!m1:%{!m2:%{!m3*:%{!m4*:%{!m5*:%(link_default_cpu_emul)}}}}}\
  %(subtarget_link_emul_suffix) \
! %{mrelax:-relax} %(subtarget_link_spec)"
  
  #define OPTIMIZATION_OPTIONS(LEVEL,SIZE)				\
  do {									\
--- 478,484 ----
  %{m5-64media*:64}\
  %{!m1:%{!m2:%{!m3*:%{!m4*:%{!m5*:%(link_default_cpu_emul)}}}}}\
  %(subtarget_link_emul_suffix) \
! %{mrelax:-relax} %(subtarget_link_spec) %{!licache*:%(icache_link_spec)}"
  
  #define OPTIMIZATION_OPTIONS(LEVEL,SIZE)				\
  do {									\
diff -p --new-file before/t-elf ./t-elf
*** before/t-elf	Mon Feb 23 16:37:16 2004
--- ./t-elf	Tue Mar  9 20:42:35 2004
***************
*** 1,5 ****
  EXTRA_MULTILIB_PARTS= crt1.o crti.o crtn.o \
! 	crtbegin.o crtend.o crtbeginS.o crtendS.o gcrt1.o
  
  # Compile crtbeginS.o and crtendS.o with pic.
  CRTSTUFF_T_CFLAGS_S = -fPIC
--- 1,7 ----
  EXTRA_MULTILIB_PARTS= crt1.o crti.o crtn.o \
! 	crtbegin.o crtend.o crtbeginS.o crtendS.o gcrt1.o \
! 	icache08x1.a icache02x2.a icache04x2.a icache08x2.a icache16x2.a \
! 	icache-icbi.a
  
  # Compile crtbeginS.o and crtendS.o with pic.
  CRTSTUFF_T_CFLAGS_S = -fPIC
diff -p --new-file before/t-sh ./t-sh
*** before/t-sh	Tue Mar  9 20:11:45 2004
--- ./t-sh	Tue Mar  9 20:42:05 2004
*************** $(T)crti.o: $(srcdir)/config/sh/crti.asm
*** 37,44 ****
--- 37,68 ----
  $(T)crtn.o: $(srcdir)/config/sh/crtn.asm $(GCC_PASSES)
  	$(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -c -o $(T)crtn.o -x assembler-with-cpp $(srcdir)/config/sh/crtn.asm
  
+ $(T)icache08x1.a: $(srcdir)/config/sh/icache.asm $(srcdir)/config/sh/lib1funcs.h $(GCC_PASSES)
+ 	$(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -c -o $(T)icache08x1.o -x assembler-with-cpp -DWAYS=1 -DWAY_SIZE=0x2000 $(srcdir)/config/sh/icache.asm
+ 	$(AR) $(AR_FLAGS) $(T)icache08x1.a $(T)icache08x1.o
+ $(T)icache02x2.a: $(srcdir)/config/sh/icache.asm $(srcdir)/config/sh/lib1funcs.h $(GCC_PASSES)
+ 	$(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -c -o $(T)icache02x2.o -x assembler-with-cpp -DWAYS=2 -DWAY_SIZE=0x800 $(srcdir)/config/sh/icache.asm
+ 	$(AR) $(AR_FLAGS) $(T)icache02x2.a $(T)icache02x2.o
+ $(T)icache04x2.a: $(srcdir)/config/sh/icache.asm $(srcdir)/config/sh/lib1funcs.h $(GCC_PASSES)
+ 	$(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -c -o $(T)icache04x2.o -x assembler-with-cpp -DWAYS=2 -DWAY_SIZE=0x1000 $(srcdir)/config/sh/icache.asm
+ 	$(AR) $(AR_FLAGS) $(T)icache04x2.a $(T)icache04x2.o
+ $(T)icache08x2.a: $(srcdir)/config/sh/icache.asm $(srcdir)/config/sh/lib1funcs.h $(GCC_PASSES)
+ 	$(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -c -o $(T)icache08x2.o -x assembler-with-cpp -DWAYS=2 -DWAY_SIZE=0x2000 $(srcdir)/config/sh/icache.asm
+ 	$(AR) $(AR_FLAGS) $(T)icache08x2.a $(T)icache08x2.o
+ $(T)icache16x2.a: $(srcdir)/config/sh/icache.asm $(srcdir)/config/sh/lib1funcs.h $(GCC_PASSES)
+ 	$(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -c -o $(T)icache16x2.o -x assembler-with-cpp -DWAYS=2 -DWAY_SIZE=0x4000 $(srcdir)/config/sh/icache.asm
+ 	$(AR) $(AR_FLAGS) $(T)icache16x2.a $(T)icache16x2.o
+ $(T)icache32x2.a: $(srcdir)/config/sh/icache.asm $(srcdir)/config/sh/lib1funcs.h $(GCC_PASSES)
+ 	$(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -c -o $(T)icache32x2.o -x assembler-with-cpp -DWAYS=2 -DWAY_SIZE=0x8000 $(srcdir)/config/sh/icache.asm
+ 	$(AR) $(AR_FLAGS) $(T)icache32x2.a $(T)icache32x2.o
+ $(T)icache-icbi.a: $(srcdir)/config/sh/icache-icbi.asm $(srcdir)/config/sh/lib1funcs.h $(GCC_PASSES)
+ 	$(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -c -o $(T)icache-icbi.o -x assembler-with-cpp $(srcdir)/config/sh/icache-icbi.asm
+ 	$(AR) $(AR_FLAGS) $(T)icache-icbi.a $(T)icache-icbi.o
+ 
  $(out_object_file): gt-sh.h
  gt-sh.h : s-gtype ; @true
  
  # These are not suitable for COFF.
  # EXTRA_MULTILIB_PARTS= crt1.o crti.o crtn.o crtbegin.o crtend.o
+ # SH4-100 has been used with coff
+ EXTRA_MULTILIB_PARTS= icache08x1.a


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]