/* $NetBSD: start.S,v 1.3 2014/02/06 19:20:11 matt Exp $ */
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code was written by Alessandro Forin and Neil Pittman
* at Microsoft Research and contributed to The NetBSD Foundation
* by Microsoft Corporation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/* Trivial support for printing stuff on the serial line from C pgms.
*/
#include <mips/asm.h>
#include <mips/cpuregs.h>
#define __ASSEMBLER__ 1
#include <machine/emipsreg.h>
/* Offsets in the CXTINFO structure
*/
#define TS_AT (1 * 4)
#define TS_V0 (2 * 4)
#define TS_V1 (3 * 4)
#define TS_A0 (4 * 4)
#define TS_A1 (5 * 4)
#define TS_A2 (6 * 4)
#define TS_A3 (7 * 4)
#define TS_T0 (8 * 4)
#define TS_T1 (9 * 4)
#define TS_T2 (10 * 4)
#define TS_T3 (11 * 4)
#define TS_T4 (12 * 4)
#define TS_T5 (13 * 4)
#define TS_T6 (14 * 4)
#define TS_T7 (15 * 4)
#define TS_S0 (16 * 4)
#define TS_S1 (17 * 4)
#define TS_S2 (18 * 4)
#define TS_S3 (19 * 4)
#define TS_S4 (20 * 4)
#define TS_S5 (21 * 4)
#define TS_S6 (22 * 4)
#define TS_S7 (23 * 4)
#define TS_T8 (24 * 4)
#define TS_T9 (25 * 4)
#define TS_K0 (26 * 4)
#define TS_K1 (27 * 4)
#define TS_GP (28 * 4)
#define TS_SP (29 * 4)
#define TS_FP (30 * 4)
#define fp s8
#define TS_RA (31 * 4)
#define TS_PC (32 * 4)
#define TS_SR (33 * 4)
#define TS_HI (34 * 4)
#define TS_LO (35 * 4)
#define TS_EC (36 * 4)
#define SIZEOF_CXTINFO (37*4)
/* PROM_MODE means the user plans to keep this code around while running an OS.
* So we act kind of like PROM code (BIOS?), but we live in RAM.
* So we need to safeguard ourselves against corruptions, some unavoidable.
* Like the overriding of the exception vectors, rigth where our "start" code is.
*/
IMPORT(main,4)
IMPORT(_end,4)
.set noreorder
EXPORT(start)
bgezal zero,_C_LABEL(real_start)
nop
/* Does not handle the exception, really.
* But to test interrupts should be enough
*/
.org 0x00000080
NESTED_NOPROFILE(ExceptionHandler,SIZEOF_CXTINFO,$31)
la k1, UserInterruptHandler
lw k1,0(k1)
bne k1,zero,Dispatch
mfc0 k0, MIPS_COP_0_EXC_PC
j k0
nop /* do not! pop status */
EXPORT(UserInterruptHandler)
.word 0
EXPORT(Dispatch)
/* Save state on stack */
addiu sp, sp, -SIZEOF_CXTINFO
/* save registers */
.set noat
sw AT, TS_AT(sp)
.set at
sw v0, TS_V0(sp)
sw v1, TS_V1(sp)
sw a0, TS_A0(sp)
sw a1, TS_A1(sp)
sw a2, TS_A2(sp)
sw a3, TS_A3(sp)
sw t0, TS_T0(sp)
sw t1, TS_T1(sp)
sw t2, TS_T2(sp)
sw t3, TS_T3(sp)
sw t4, TS_T4(sp)
sw t5, TS_T5(sp)
sw t6, TS_T6(sp)
sw t7, TS_T7(sp)
sw s0, TS_S0(sp)
sw s1, TS_S1(sp)
sw s2, TS_S2(sp)
sw s3, TS_S3(sp)
sw s4, TS_S4(sp)
sw s5, TS_S5(sp)
sw s6, TS_S6(sp)
sw s7, TS_S7(sp)
sw t8, TS_T8(sp)
sw t9, TS_T9(sp)
sw k0, TS_K0(sp)
sw k1, TS_K1(sp)
sw gp, TS_GP(sp)
/* sp: later */
sw fp, TS_FP(sp)
sw ra, TS_RA(sp)
mfc0 a0, MIPS_COP_0_STATUS
mflo t0
mfhi t1
sw a0, TS_SR(sp)
sw t0, TS_LO(sp)
sw t1, TS_HI(sp)
sw k0, TS_PC(sp)
/* Save original stack */
move a0,sp
addiu t0, sp, SIZEOF_CXTINFO
jalr k1
sw t0, TS_SP(sp)
/* Returned value is new PCXINFO */
move a0,v0
/* First load most registers */
.set noat
lw AT, TS_AT(a0)
lw v0, TS_V0(a0)
lw v1, TS_V1(a0)
/* a0 later */
lw a1, TS_A1(a0)
lw a2, TS_A2(a0)
lw a3, TS_A3(a0)
lw t0, TS_T0(a0)
lw t1, TS_T1(a0)
lw t2, TS_T2(a0)
lw t3, TS_T3(a0)
lw t4, TS_T4(a0)
lw t5, TS_T5(a0)
lw t6, TS_T6(a0)
lw t7, TS_T7(a0)
lw s0, TS_S0(a0)
lw s1, TS_S1(a0)
lw s2, TS_S2(a0)
lw s3, TS_S3(a0)
lw s4, TS_S4(a0)
lw s5, TS_S5(a0)
lw s6, TS_S6(a0)
lw s7, TS_S7(a0)
lw t8, TS_T8(a0)
lw t9, TS_T9(a0)
/* k0,k1 not restored */
lw gp, TS_GP(a0)
/* sp later */
lw fp, TS_FP(a0)
lw ra, TS_RA(a0)
lw k1, TS_HI(a0)
lw k0, TS_LO(a0)
mthi k1
mtlo k0
lw k1, TS_SR(a0)
mtc0 k1, MIPS_COP_0_STATUS
/* NB: After this instruction we cannot take any interrupts or traps
*/
lw sp, TS_SP(a0)
/* Put pc into k0 */
lw k0, TS_PC(a0)
lw a0, TS_A0(a0)
j k0
rfe
.set at
END(ExceptionHandler)
.org 0x00000200
EXPORT(real_start)
.ent _C_LABEL(real_start)
#ifdef SECONDARY_BOOTBLOCK
/*
* If this is the program that goes into FLASH we must copy ourselves down to RAM.
* FLASH default on the MLx is at 0xf0000000, DRAM at 0.
*/
addi a0,ra,-8 /* Compensate for the first two instructions */
/* Get the address(relative) of TextStart
*/
bgezal zero, _C_LABEL(MipsStart2) /* Always jumps */
nop
/* All of the static data, since we are at it.
*/
TextStart: /* + 0 */
/* Text start at final link address */
.int start
DataEnd: /* + 4 */
/* Data end == bss start */
.int _edata
BssEnd: /* + 8 */
/* Bss end */
.int _end
RelocToRAM: /* *+12 */
.int InRAM
MipsStart2:
/* Source = a0, Dst = t2 */
lw t2, 0(ra) /* _C_LABEL(TextStart) */
/* EndPtr = t3 */
/* in bdelay slot */
/* If a0 != t2 then we are running in Flash but should run in RAM
* In that case copy .text. Otherwise skip to .bss.
*/
beq a0,t2,ZroLoop-4
lw t3, 4(ra) /* _C_LABEL(DataEnd) */
CpyLoop:
/* loop copying 2 words at a time */
lw t4,0(a0)
lw t5,4(a0)
addiu a0,a0,8
sw t4,0(t2)
addiu t2,t2,8
sltu t1,t2,t3
bne t1,zero,CpyLoop
sw t5,-4(t2)
/* zero the bss
*/
lw t4, 8(ra) /* _C_LABEL(BssEnd) */
ZroLoop:
sltu t1,t3,t4
sw zero,0(t3)
bne t1,zero,ZroLoop
addiu t3,t3,4
/* Jump to RAM copy (below)
*/
lw t1, 12(ra) /* _C_LABEL(RelocToRAM) */
jr t1
nop
/*
* Execute from here after copying out of FLASH into RAM
*/
InRAM:
#endif /* SECONDARY_BOOTBLOCK */
/* Get a stack
*/
#ifdef __GP_SUPPORT__
la gp, _C_LABEL (_gp)
#endif
la sp,_end
addiu sp,sp,(8*1024) /* BUGBUG arbitrary */
/* Jump to main
*/
jal main
add a0,sp,zero
/* Load failed, reset the processor and jump back to the origins.
*/
EXPORT(_rtt) /* ahem */
li t0,0x1260ff80 /* NB: On new builds this is a SYS-RESET as well */
mtc0 t0,MIPS_COP_0_STATUS
lui t0,(BRAM_DEFAULT_ADDRESS>>16) /* nb: knows about 16bit chop */
jr t0
nop
EXPORT(Stop)
b Stop
nop
END(real_start)
.set noreorder
.set noat
.set nomacro
/* void Delay(UINT32 count)
*/
LEAF(Delay)
bne a0,zero,_C_LABEL(Delay)
subu a0,1
j ra
nop
END(Delay)
/* UINT32 GetPsr(void)
* Returns the PSR (coprocessor 0 status)
*/
LEAF(GetPsr)
mfc0 v0, MIPS_COP_0_STATUS
j ra
nop
END(GetPsr)
/* void SetPsr(UINT32 Psr)
* Sets the PSR (coprocessor 0 status)
*/
LEAF(SetPsr)
mtc0 a0,MIPS_COP_0_STATUS
j ra
nop
END(SetPsr)
/* UINT32 GetCause(void)
* Returns the Cause register (coprocessor 0)
*/
LEAF(GetCause)
mfc0 v0,MIPS_COP_0_CAUSE
j ra
nop
END(GetCause)
/* UINT32 GetEpc(void)
* Returns the Epc register (coprocessor 0)
*/
LEAF(GetEpc)
mfc0 v0,MIPS_COP_0_EXC_PC
j ra
nop
END(GetEpc)
/* int PutWord(UINT32 Word);
* Returns: 0 if ok, -1 otherwise
*/
NESTED(PutWord,12,$31)
subu sp,sp,12
sw s0,8(sp)
sw s1,4(sp)
sw ra,0(sp)
or s1,a0,zero
/* Spit all nibbles
*/
li s0,8
PutWordLoop:
srl a0,s1,32-4
li t0,10
sltu t1,a0,t0
bnez t1,$Digit
li a1,'0'
subu a0,a0,t0
li a1,'a'
$Digit:
sll s1,s1,4
jal PutChar
add a0,a0,a1
subu s0,s0,1
bne v0,zero,PutWordDone /* printed ok? */
li v0,-1
/* done yet? */
bne s0,zero,PutWordLoop
nop
/* done
*/
li v0,0
PutWordDone:
lw ra,0(sp)
lw s1,4(sp)
lw s0,8(sp)
jr ra
addiu sp,sp,12
END(PutWord)
/* int Puts(char *String);
* Returns: 0 if ok, -1 otherwise
*/
NESTED(Puts,8,$31)
subu sp,sp,8
sw s0,4(sp)
sw ra,0(sp)
or s0,a0,zero
/* Spit all chars until zero
*/
PutsLoop:
lbu a0,0(s0)
addiu s0,s0,1
beq a0,zero,PutsDoneOk
nop
jal PutChar
nop
beq v0,zero,PutsLoop
nop
/* Timed out
*/
b PutsDone
li v0,-1
/* done
*/
PutsDoneOk:
li v0,0
PutsDone:
lw ra,0(sp)
lw s0,4(sp)
jr ra
addiu sp,sp,8
END(Puts)
/* int GetChar(void);
* Returns: a non-negative value if ok, -1 otherwise
*/
LEAF(GetChar)
lui t0,(USART_DEFAULT_ADDRESS>>16) /* nb: knows about 16bit chop */
lui t1,1000 /* n*65k spins max */
RxNotReady:
lw t4,USARTST(t0) /* ChannelStatus */
andi t4,t4,USI_RXRDY
bgtz t4,$GotByte
subu t1,t1,1
/* still ok to spin? */
bgtz t1,RxNotReady
nop
/* Timed out
*/
jr ra
li v0,-1
/* Gottabyte
*/
$GotByte:
lw v0,USARTRX(t0) /* RxData */
jr ra
andi v0,0xff
END(GetChar)
/* int PutChar(UINT8 v);
* Returns: 0 if ok, -1 otherwise
*/
LEAF(PutChar)
lui t0,(USART_DEFAULT_ADDRESS>>16) /* nb: knows about 16bit chop */
lui t1,1000 /* n*65k spins max */
li v0,0
TxNotReady:
lw t4,USARTST(t0) /* ChannelStatus */
andi t4,t4,USI_TXRDY
bgtz t4,TxReady
subu t1,t1,1
/* still ok to spin? */
bgtz t1,TxNotReady
nop
/* Timed out
*/
jr ra
li v0,-1
/* Send it
*/
TxReady:
jr ra
sw a0,USARTTX(t0)
END(PutChar)
/* Second arg is a function to call with the first arg:
* void switch_stack_and_call(void *arg, void (*function)(void *));
*/
LEAF(switch_stack_and_call)
/* Get a stack and jump. It would be a very bad idea to return but..
*/
lui sp,%hi(_end)
addiu sp,%lo(_end)
jr a1
addiu sp,sp,(2*1024) /* BUGBUG arbitrary */
END(switch_stack_and_call)