From 44edce8311606c70594c8072cd0f04530148f924 Mon Sep 17 00:00:00 2001
From: Thomas Chou <thomas@wytron.com.tw>
Date: Mon, 31 Dec 2007 18:05:51 +0800
Subject: [PATCH] nios2: redirect exception vector outside sdram

The default exception vector was located at sdram. But some designs
locate the exception vector at onchip memory or sram, and the
default exception hook won't work without regenerate hardware.

This patch copy a sequence of instructions to the hardwired exception
location. So that exceptions are redirected to inthandler at sdram.

FIXME: It won't work if the exception slave is not writable. An error
should be generated then.

Signed-off-by: Thomas Chou <thomas@wytron.com.tw>
---
 linux-2.6.x/arch/nios2nommu/kernel/asm-offsets.c   |    4 +++
 linux-2.6.x/arch/nios2nommu/kernel/head.S          |   22 +++++++++++++++++++-
 .../arch/nios2nommu/scripts/PTF/SystemPTF/CPU.pm   |   12 ++++++++++
 .../arch/nios2nommu/scripts/gen_nios2_system.h.pl  |   11 ++++++++++
 4 files changed, 48 insertions(+), 1 deletions(-)

diff --git a/linux-2.6.x/arch/nios2nommu/kernel/asm-offsets.c b/linux-2.6.x/arch/nios2nommu/kernel/asm-offsets.c
index dd93a81..242ca9f 100644
--- a/linux-2.6.x/arch/nios2nommu/kernel/asm-offsets.c
+++ b/linux-2.6.x/arch/nios2nommu/kernel/asm-offsets.c
@@ -156,6 +156,10 @@ int main(void)
 	DEFINE(NIOS2_ICACHE_LINE_SIZE, nasys_icache_line_size);
 	DEFINE(NIOS2_DCACHE_SIZE, nasys_dcache_size);
 	DEFINE(NIOS2_DCACHE_LINE_SIZE, nasys_dcache_line_size);
+
+#if defined(CPU_EXCEPT_ADDRESS)
+	DEFINE(CPU_EXCEPT_ADDRESS_ASM, CPU_EXCEPT_ADDRESS);
+#endif
 	
 #if defined(na_enet)
 	DEFINE(NA_ENET_ASM, na_enet);
diff --git a/linux-2.6.x/arch/nios2nommu/kernel/head.S b/linux-2.6.x/arch/nios2nommu/kernel/head.S
index ba9ea12..d067468 100644
--- a/linux-2.6.x/arch/nios2nommu/kernel/head.S
+++ b/linux-2.6.x/arch/nios2nommu/kernel/head.S
@@ -87,7 +87,7 @@ text_flush:
 	/* This is the default location for the exception 
 	 * handler. Code in jump to our handler
 	 */
-	
+exc_hook:	
 	movia	r24,inthandler
 	jmp	r24
 1:		
@@ -129,6 +129,26 @@ loop_move:				// r1: src, r2: dest, r3: last dest
 
 finish_move:
 
+#if defined(CPU_EXCEPT_ADDRESS_ASM) && (CPU_EXCEPT_ADDRESS_ASM != (LINUX_SDRAM_START + 0x20))
+/*	Copy an instruction sequence to put at the exception address */	
+        movia	r2,exc_hook
+        movia	r3,CPU_EXCEPT_ADDRESS_ASM
+        ldw     r1,0(r2)
+        stw     r1,0(r3)
+        ldw     r1,4(r2)
+        stw     r1,4(r3)
+        ldw     r1,8(r2)
+        stw     r1,8(r3)
+        flushd  0(r3)
+        flushd  4(r3)
+        flushd  8(r3)
+        flushi  r3
+        addi    r3,r3,4
+        flushi  r3
+        addi    r3,r3,4
+        flushi  r3
+#endif
+
 	//------------------------------------
 	// Disable interrupts on known devices
 	//
diff --git a/linux-2.6.x/arch/nios2nommu/scripts/PTF/SystemPTF/CPU.pm b/linux-2.6.x/arch/nios2nommu/scripts/PTF/SystemPTF/CPU.pm
index ea10598..810886d 100644
--- a/linux-2.6.x/arch/nios2nommu/scripts/PTF/SystemPTF/CPU.pm
+++ b/linux-2.6.x/arch/nios2nommu/scripts/PTF/SystemPTF/CPU.pm
@@ -72,6 +72,18 @@ sub getResetLocationOffset {
 	return ($location, $offset);
 }
 
+sub getExceptLocationOffset {
+	my ($self) = @_;
+	
+	$wsa = $self->{ptf}->getSection('WIZARD_SCRIPT_ARGUMENTS', '');
+	$wsa or return;
+	
+	my $location = $wsa->getAssignment ('exc_slave');
+	my $offset = $wsa->getAssignment ('exc_offset');
+	
+	return ($location, $offset);
+}
+
 sub isEnabled {
 	my ($self) = @_;
 	
diff --git a/linux-2.6.x/arch/nios2nommu/scripts/gen_nios2_system.h.pl b/linux-2.6.x/arch/nios2nommu/scripts/gen_nios2_system.h.pl
index b7bcff5..1855cbf 100644
--- a/linux-2.6.x/arch/nios2nommu/scripts/gen_nios2_system.h.pl
+++ b/linux-2.6.x/arch/nios2nommu/scripts/gen_nios2_system.h.pl
@@ -304,6 +304,17 @@ printf ("#define %-33s %30s\n",
 		("CPU_RESET_ADDRESS", $reset_address));
 }
 
+{	
+	my ($except_location, $except_offset) = $cpu->getExceptLocationOffset();
+	my ($except_module_name, $except_port_name) = ($except_location =~ /(.*)\/(.*)/);
+	my $except_module = $system->getModule ($except_module_name);
+	my $except_address = $except_module->getBaseAddress ($except_port_name);
+	
+	$except_address = hex ($except_address) + hex ($except_offset);
+	printf ("#define %-53s %#010x\n", 
+		("CPU_EXCEPT_ADDRESS", $except_address));
+}
+
 print "\n";
 
 #
-- 
1.5.3.3

