| /* | 
 |  * (C) Copyright 2004, Psyent Corporation <www.psyent.com> | 
 |  * Scott McNutt <smcnutt@psyent.com> | 
 |  * | 
 |  * See file CREDITS for list of people who contributed to this | 
 |  * project. | 
 |  * | 
 |  * This program 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 of | 
 |  * the License, or (at your option) any later version. | 
 |  * | 
 |  * This program 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; if not, write to the Free Software | 
 |  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | 
 |  * MA 02111-1307 USA | 
 |  */ | 
 |  | 
 |  | 
 | #include <config.h> | 
 | #include <version.h> | 
 |  | 
 | /************************************************************************* | 
 |  * RESTART | 
 |  ************************************************************************/ | 
 |  | 
 | 	.text | 
 | 	.global _start | 
 |  | 
 | _start: | 
 | 	/* ICACHE INIT -- only the icache line at the reset address | 
 | 	 * is invalidated at reset. So the init must stay within | 
 | 	 * the cache line size (8 words). If GERMS is used, we'll | 
 | 	 * just be invalidating the cache a second time. If cache | 
 | 	 * is not implemented initi behaves as nop. | 
 | 	 */ | 
 | 	ori	r4, r0, %lo(CFG_ICACHELINE_SIZE) | 
 | 	movhi	r5, %hi(CFG_ICACHE_SIZE) | 
 | 	ori	r5, r5, %lo(CFG_ICACHE_SIZE) | 
 | 	mov	r6, r0 | 
 | 0:	initi	r6 | 
 | 	add	r6, r6, r4 | 
 | 	bltu	r6, r5, 0b | 
 | 	br	_except_end	/* Skip the tramp */ | 
 |  | 
 | 	/* EXCEPTION TRAMPOLINE -- the following gets copied | 
 | 	 * to the exception address (below), but is otherwise at the | 
 | 	 * default exception vector offset (0x0020). | 
 | 	 */ | 
 | _except_start: | 
 | 	movhi	et, %hi(_exception) | 
 | 	ori	et, et, %lo(_exception) | 
 | 	jmp	et | 
 | _except_end: | 
 |  | 
 | 	/* INTERRUPTS -- for now, all interrupts masked and globally | 
 | 	 * disabled. | 
 | 	 */ | 
 | 	wrctl	status, r0		/* Disable interrupts */ | 
 | 	wrctl	ienable, r0		/* All disabled	*/ | 
 |  | 
 | 	/* DCACHE INIT -- if dcache not implemented, initd behaves as | 
 | 	 * nop. | 
 | 	 */ | 
 | 	movhi	r4, %hi(CFG_DCACHELINE_SIZE) | 
 | 	ori	r4, r4, %lo(CFG_DCACHELINE_SIZE) | 
 | 	movhi	r5, %hi(CFG_DCACHE_SIZE) | 
 | 	ori	r5, r5, %lo(CFG_DCACHE_SIZE) | 
 | 	mov	r6, r0 | 
 | 1:	initd	0(r6) | 
 | 	add	r6, r6, r4 | 
 | 	bltu	r6, r5, 1b | 
 |  | 
 | 	/* RELOCATE CODE, DATA & COMMAND TABLE -- the following code | 
 | 	 * assumes code, data and the command table are all | 
 | 	 * contiguous. This lets us relocate everything as a single | 
 | 	 * block. Make sure the linker script matches this ;-) | 
 | 	 */ | 
 | 	nextpc	r4 | 
 | _cur:	movhi	r5, %hi(_cur - _start) | 
 | 	ori	r5, r5, %lo(_cur - _start) | 
 | 	sub	r4, r4, r5		/* r4 <- cur _start */ | 
 | 	mov	r8, r4 | 
 | 	movhi	r5, %hi(_start) | 
 | 	ori	r5, r5, %lo(_start)	/* r5 <- linked _start */ | 
 | 	beq	r4, r5, 3f | 
 |  | 
 | 	movhi	r6, %hi(_edata) | 
 | 	ori	r6, r6, %lo(_edata) | 
 | 2:	ldwio	r7, 0(r4) | 
 | 	addi	r4, r4, 4 | 
 | 	stwio	r7, 0(r5) | 
 | 	addi	r5, r5, 4 | 
 | 	bne	r5, r6, 2b | 
 | 3: | 
 |  | 
 | 	/* ZERO BSS/SBSS -- bss and sbss are assumed to be adjacent | 
 | 	 * and between __bss_start and _end. | 
 | 	 */ | 
 | 	 movhi	r5, %hi(__bss_start) | 
 | 	 ori	r5, r5, %lo(__bss_start) | 
 | 	 movhi	r6, %hi(_end) | 
 | 	 ori	r6, r6, %lo(_end) | 
 | 	 beq	r5, r6, 5f | 
 |  | 
 | 4:	stwio	r0, 0(r5) | 
 | 	 addi	r5, r5, 4 | 
 | 	 bne	r5, r6, 4b | 
 | 5: | 
 |  | 
 | 	/* GLOBAL POINTER -- the global pointer is used to reference | 
 | 	 * "small data" (see -G switch). The linker script must | 
 | 	 * provide the gp address. | 
 | 	 */ | 
 | 	 movhi	gp, %hi(_gp) | 
 | 	 ori	gp, gp, %lo(_gp) | 
 |  | 
 | 	/* JUMP TO RELOC ADDR */ | 
 | 	movhi	r4, %hi(_reloc) | 
 | 	ori	r4, r4, %lo(_reloc) | 
 | 	jmp	r4 | 
 | _reloc: | 
 |  | 
 | 	/* COPY EXCEPTION TRAMPOLINE -- copy the tramp to the | 
 | 	 * exception address. Define CONFIG_ROM_STUBS to prevent | 
 | 	 * the copy (e.g. exception in flash or in other | 
 | 	 * softare/firmware component). | 
 | 	 */ | 
 | #if !defined(CONFIG_ROM_STUBS) | 
 | 	movhi	r4, %hi(_except_start) | 
 | 	ori	r4, r4, %lo(_except_start) | 
 | 	movhi	r5, %hi(_except_end) | 
 | 	ori	r5, r5, %lo(_except_end) | 
 | 	movhi	r6, %hi(CFG_EXCEPTION_ADDR) | 
 | 	ori	r6, r6, %lo(CFG_EXCEPTION_ADDR) | 
 | 	beq	r4, r6, 7f	/* Skip if at proper addr */ | 
 |  | 
 | 6:	ldwio	r7, 0(r4) | 
 | 	stwio	r7, 0(r6) | 
 | 	addi	r4, r4, 4 | 
 | 	addi	r6, r6, 4 | 
 | 	bne	r4, r5, 6b | 
 | 7: | 
 | #endif | 
 |  | 
 | 	/* STACK INIT -- zero top two words for call back chain. | 
 | 	 */ | 
 | 	movhi	sp, %hi(CFG_INIT_SP) | 
 | 	ori	sp, sp, %lo(CFG_INIT_SP) | 
 | 	addi	sp, sp, -8 | 
 | 	stw	r0, 0(sp) | 
 | 	stw	r0, 4(sp) | 
 | 	mov	fp, sp | 
 |  | 
 | 	/* | 
 | 	 * Call board_init -- never returns | 
 | 	 */ | 
 | 	movhi	r4, %hi(board_init@h) | 
 | 	ori	r4, r4, %lo(board_init@h) | 
 | 	callr	r4 | 
 |  | 
 | 	/* NEVER RETURNS -- but branch to the _start just | 
 | 	 * in case ;-) | 
 | 	 */ | 
 | 	br	_start | 
 |  | 
 |  | 
 | /* | 
 |  * dly_clks -- Nios2 (like Nios1) doesn't have a timebase in | 
 |  * the core. For simple delay loops, we do our best by counting | 
 |  * instruction cycles. | 
 |  * | 
 |  * Instruction performance varies based on the core. For cores | 
 |  * with icache and static/dynamic branch prediction (II/f, II/s): | 
 |  * | 
 |  * 	Normal ALU (e.g. add, cmp, etc):	1 cycle | 
 |  * 	Branch (correctly predicted, taken):	2 cycles | 
 |  *	Negative offset is predicted (II/s). | 
 |  * | 
 |  * For cores without icache and no branch prediction (II/e): | 
 |  * | 
 |  * 	Normal ALU (e.g. add, cmp, etc):	6 cycles | 
 |  * 	Branch (no prediction):			6 cycles | 
 |  * | 
 |  * For simplicity, if an instruction cache is implemented we | 
 |  * assume II/f or II/s. Otherwise, we use the II/e. | 
 |  * | 
 |  */ | 
 |  	.globl dly_clks | 
 |  | 
 | dly_clks: | 
 |  | 
 | #if (CFG_ICACHE_SIZE > 0) | 
 | 	subi	r4, r4, 3		/* 3 clocks/loop	*/ | 
 | #else | 
 | 	subi	r4, r4, 12		/* 12 clocks/loop	*/ | 
 | #endif | 
 | 	bge	r4, r0, dly_clks | 
 | 	ret | 
 |  | 
 |  | 
 | #if !defined(CONFIG_IDENT_STRING) | 
 | #define CONFIG_IDENT_STRING "" | 
 | #endif | 
 | 	.data | 
 | 	.globl	version_string | 
 |  | 
 | version_string: | 
 | 	.ascii U_BOOT_VERSION | 
 | 	.ascii " (", __DATE__, " - ", __TIME__, ")" | 
 | 	.ascii CONFIG_IDENT_STRING, "\0" |