500 lines
10 KiB
ArmAsm
500 lines
10 KiB
ArmAsm
# Copyright (c) 2003 Red Hat, Inc. All rights reserved.
|
|
#
|
|
# This copyrighted material is made available to anyone wishing to use, modify,
|
|
# copy, or redistribute it subject to the terms and conditions of the BSD
|
|
# License. This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY expressed or implied, including the implied
|
|
# warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. A copy of
|
|
# this license is available at http://www.opensource.org/licenses. Any Red Hat
|
|
# trademarks that are incorporated in the source code or documentation are not
|
|
# subject to the BSD License and may only be used or replicated with the express
|
|
# permission of Red Hat, Inc.
|
|
#
|
|
# Toshiba Media Processor startup file (crt0.S)
|
|
#
|
|
# Designed for user programs running in the 0-2Mb startup section.
|
|
# Designed for the simulator by default.
|
|
#
|
|
# Exception/Interrupt Handler Locations
|
|
# CFG.EVM CFG.EVA CFG.IVA Exception INTn
|
|
## 0 - - 0x0000_0000 0x0000_0030 rom
|
|
## 1 0 0 0x0020_0000 0x0020_0030 local RAM / local RAM
|
|
## 1 1 0 0x0080_0000 0x0020_0000 ext RAM / local RAM
|
|
## 1 0 1 0x0020_0000 0x0080_0000 local RAM / ext RAM
|
|
## 1 1 1 0x0080_0000 0x0080_0030 ext RAM / ext RAM
|
|
#
|
|
# Exceptions
|
|
# Reset 0x0000_0000
|
|
# NMI 0x0000_0000+4
|
|
# RI (Base Address) +0x08
|
|
# ZDIV (Base Address) +0x0C
|
|
# BRK (Base Address) +0x10
|
|
# SWI (Base Address) +0x14
|
|
# DSP (Base Address) +0x1C
|
|
# COP (Base Address) +0x20
|
|
|
|
.set _local_ram_base, 0x00200000
|
|
.set _ext_ram_base, 0x00800000
|
|
.set _int_base_offset, 0x30
|
|
|
|
#include "syscall.h"
|
|
|
|
.macro if_bitfield_zero reg, start, length, label
|
|
ldc $0, \reg
|
|
srl $0, \start
|
|
and3 $0, $0, (1 << \length) - 1
|
|
beqz $0,\label
|
|
.endm
|
|
|
|
.macro if_bitfield_notN reg, start, length, N, label
|
|
ldc $0, \reg
|
|
srl $0, \start
|
|
and3 $0, $0, (1 << \length) - 1
|
|
bnei $0,\N, \label
|
|
.endm
|
|
|
|
.macro if_bitfield_eqN reg, start, length, N, label
|
|
ldc $0, \reg
|
|
srl $0, \start
|
|
and3 $0, $0, (1 << \length) - 1
|
|
beqi $0,\N, \label
|
|
.endm
|
|
|
|
.macro if_bitfield_ltN reg, start, length, N, label
|
|
ldc $0, \reg
|
|
srl $0, \start
|
|
and3 $0, $0, (1 << \length) - 1
|
|
blti $0,\N, \label
|
|
.endm
|
|
|
|
.section .hwinit, "ax"
|
|
# CCFG.ICSZ
|
|
if_bitfield_zero reg=$ccfg, start=16, length=7, label=.Lend_enable_icache
|
|
__enable_icache:
|
|
# set ICE(cfg[1])
|
|
ldc $1,$cfg
|
|
or3 $1,$1,2
|
|
stc $1,$cfg
|
|
nop
|
|
nop
|
|
nop
|
|
nop
|
|
nop
|
|
.Lend_enable_icache:
|
|
ret
|
|
|
|
__enable_dcache:
|
|
# CCFG.DCSZ
|
|
if_bitfield_zero reg=$ccfg, start=0, length=7, label=.Lend_enable_dcache
|
|
# set DCE(cfg[0])
|
|
ldc $1,$cfg
|
|
or3 $1,$1,1
|
|
stc $1,$cfg
|
|
nop
|
|
nop
|
|
nop
|
|
nop
|
|
nop
|
|
ret
|
|
.Lend_enable_dcache:
|
|
|
|
.text
|
|
|
|
#ifdef NOVEC
|
|
.global _reset
|
|
_reset:
|
|
#endif
|
|
|
|
.global _start
|
|
_start:
|
|
mov $fp, 0 # for unwinding
|
|
|
|
# $sp set
|
|
movh $sp, %uhi(__stack_table)
|
|
or3 $sp, $sp, %lo(__stack_table)
|
|
|
|
# initialize sp, gp, tp
|
|
# get CPU ID
|
|
ldc $0, $id
|
|
srl $0, 16
|
|
|
|
# load ID-specific stack pointer
|
|
sl2ad3 $0, $0, $sp # $0 = ($0 << 2) + $sp
|
|
lw $sp,($0) # $sp = *($0)
|
|
mov $0,0xfffffff8
|
|
and $sp, $0
|
|
|
|
#ifndef NOVEC
|
|
# copy exception vector table
|
|
|
|
# RCFG.IRSZ
|
|
if_bitfield_zero reg=$rcfg, start=16, length=7, label=.Lend_ev_imem
|
|
# handle imem
|
|
movh $11,%uhi(_local_ram_base)
|
|
or3 $11,$11,%lo(_local_ram_base)
|
|
# clear CFG.EVA ([23])
|
|
ldc $0,$cfg
|
|
movh $1, %uhi(0xff7fffff)
|
|
or3 $1, $1, %lo(0xff7fffff)
|
|
and $0,$1
|
|
stc $0,$cfg
|
|
bra .Ldo_repeat_ev
|
|
.Lend_ev_imem:
|
|
#ifdef UseSDRAM
|
|
movh $11,%uhi(_ext_ram_base)
|
|
or3 $11,$11,%lo(_ext_ram_base)
|
|
# set CFG.EVA ([23])
|
|
ldc $0,$cfg
|
|
movh $1,%uhi(1<<23)
|
|
or3 $1,$1,%lo(1<<23)
|
|
or $0,$1
|
|
stc $0,$cfg
|
|
#else
|
|
# handle ROM
|
|
bra .Lend_ev
|
|
#endif
|
|
.Ldo_repeat_ev:
|
|
# set CFG.EVM ([4])
|
|
ldc $0,$cfg
|
|
or3 $0,$0,(1<<4)
|
|
stc $0,$cfg
|
|
# copy _exception_table to $11
|
|
movh $12,%uhi(_exception_table)
|
|
or3 $12,$12,%lo(_exception_table)
|
|
mov $13,8
|
|
repeat $13,.Lrepeat_ev
|
|
lw $1,0($12)
|
|
add $12,4
|
|
.Lrepeat_ev:
|
|
sw $1,0($11)
|
|
add $11,4
|
|
.Lend_ev:
|
|
|
|
# copy interrupt vector table
|
|
# RCFG.IRSZ
|
|
if_bitfield_zero reg=$rcfg, start=16, length=7, label=.Lend_iv_imem
|
|
# handle imem
|
|
movh $11,%uhi(_local_ram_base)
|
|
or3 $11,$11,%lo(_int_base_offset)
|
|
# clear CFG.IVA ([22])
|
|
ldc $0,$cfg
|
|
movh $1,%uhi(0xffbfffff) # ~(1<<22)
|
|
or3 $1,$1,%lo(0xffbfffff)
|
|
and $0,$1
|
|
stc $0,$cfg
|
|
bra .Ldo_repeat_iv
|
|
.Lend_iv_imem:
|
|
#ifdef UseSDRAM
|
|
movh $11,%uhi(_ext_ram_base)
|
|
or3 $11,$11,%lo(_int_base_offset)
|
|
# set CFG. IVA ([22])
|
|
ldc $0,$cfg
|
|
movh $1,%uhi(1<<22)
|
|
or3 $1,$1,%lo(1<<22)
|
|
or $0,$1
|
|
stc $0,$cfg
|
|
#else
|
|
# handle ROM
|
|
bra .Lend_iv
|
|
#endif
|
|
.Ldo_repeat_iv:
|
|
# set CFG.IVM ([3])
|
|
ldc $0,$cfg
|
|
or3 $0,$0,(1<<3)
|
|
stc $0,$cfg
|
|
# copy _interrupt_table to $11
|
|
movh $12,%uhi(_interrupt_table)
|
|
or3 $12,$12,%lo(_interrupt_table)
|
|
mov $13,32
|
|
add $13,-1
|
|
and3 $13,$13,127
|
|
repeat $13,.Lrepeat_iv
|
|
lw $1,0($12)
|
|
add $12,4
|
|
.Lrepeat_iv:
|
|
sw $1,0($11)
|
|
add $11,4
|
|
.Lend_iv:
|
|
|
|
# initialize instruction cache
|
|
# Icache Size CCFG.ICSZ ([22..16]) KByte
|
|
if_bitfield_zero reg=$ccfg, start=16, length=7, label=.Lend_ic
|
|
mov $3,$0 # cache size in KB
|
|
# ID.ID
|
|
if_bitfield_ltN reg=$ID, start=8, length=8, N=3, label=.Lend_mepc3_ic
|
|
# Line Size CCFG.ICSZ ([26..24]) Byte
|
|
if_bitfield_ltN reg=$ccfg, start=24, length=3, N=2, label=.Lend_ic
|
|
bgei $0,5,.Lend_ic
|
|
|
|
add3 $1,$0,3 # bit width of line size
|
|
mov $0,$3
|
|
# clear tag
|
|
mov $2,10
|
|
sub $2,$1
|
|
sll $0,$2 # *KByte/(line size)
|
|
add $0,-1
|
|
mov $2,1
|
|
sll $2,$1 # line size
|
|
bra .Ldo_repeat_icache
|
|
.Lend_mepc3_ic:
|
|
# ICache: $0 KByte
|
|
mov $0,$3
|
|
# clear tag
|
|
sll $0,(10-5) # *KByte/(32byte=linesize)
|
|
add $0,-1
|
|
mov $2,32
|
|
.Ldo_repeat_icache:
|
|
mov $1,0
|
|
bra 0f
|
|
# Align this code on an 8 byte boundary in order to keep the repeat
|
|
# loop entirely within the instruction fetch buffer.
|
|
.p2align 3
|
|
0:
|
|
movh $3,%hi(0x00310000) # for tag
|
|
repeat $0,.Lrepeat_icache
|
|
add $0,-1
|
|
.Lrepeat_icache:
|
|
sw $1,0($3)
|
|
add3 $3,$3,$2
|
|
.Lenable_icache:
|
|
movh $1,%hi(__enable_icache)
|
|
add3 $1,$1,%lo(__enable_icache)
|
|
jsr $1
|
|
.Lend_ic:
|
|
|
|
# initialize data cache
|
|
# Dcache Size CCFG.DCSZ ([6..0]) KByte
|
|
if_bitfield_zero reg=$ccfg, start=0, length=7, label=.Lend_dc
|
|
mov $3,$0 # cache size in KB
|
|
# ID.ID
|
|
if_bitfield_ltN reg=$ID, start=8, length=8, N=3, label=.Lend_mepc3_dc
|
|
# Line Size CCFG.DCSZ ([10..8]) Byte
|
|
if_bitfield_ltN reg=$ccfg, start=8, length=3, N=2, label=.Lend_dc
|
|
bgei $0,5,.Lend_dc
|
|
|
|
add3 $1,$0,3 # bit width of line size
|
|
mov $0,$3
|
|
# clear tag
|
|
mov $2,10
|
|
sub $2,$1
|
|
sll $0,$2 # *KByte/(line size)
|
|
add $0,-1
|
|
mov $2,1
|
|
sll $2,$1 # line size
|
|
bra .Ldo_repeat_dcache
|
|
.Lend_mepc3_dc:
|
|
# DCache: $0 KByte
|
|
mov $0,$3
|
|
# clear tag
|
|
sll $0,(10-5) # *KByte/(32byte=linesize)
|
|
add $0,-1
|
|
mov $2,32
|
|
.Ldo_repeat_dcache:
|
|
mov $1,0
|
|
movh $3,%hi(0x00330000) # for tag
|
|
|
|
repeat $0,.Lrepeat_dcache
|
|
add $0,-1
|
|
.Lrepeat_dcache:
|
|
sw $1,0($3)
|
|
add3 $3,$3,$2
|
|
.Lenable_dcache:
|
|
movh $1,%hi(__enable_dcache)
|
|
add3 $1,$1,%lo(__enable_dcache)
|
|
jsr $1
|
|
.Lend_dc:
|
|
# NOVEC
|
|
#endif
|
|
mov $0, 0
|
|
|
|
movh $gp, %uhi(__sdabase)
|
|
or3 $gp, $gp, %lo(__sdabase)
|
|
|
|
movh $tp, %uhi(__tpbase)
|
|
or3 $tp, $tp, %lo(__tpbase)
|
|
|
|
# zero out BSS
|
|
movh $1, %uhi(__bss_start)
|
|
or3 $1, $1, %lo(__bss_start)
|
|
mov $2, 0
|
|
movh $3, %uhi(_end)
|
|
or3 $3, $3, %lo(_end)
|
|
sub $3, $1
|
|
bsr memset
|
|
|
|
movh $1, %uhi(__sbss_start)
|
|
or3 $1, $1, %lo(__sbss_start)
|
|
mov $2, 0
|
|
movh $3, %uhi(__sbss_end)
|
|
or3 $3, $3, %lo(__sbss_end)
|
|
sub $3, $1
|
|
bsr memset
|
|
|
|
movh $1, %uhi(__farbss_start)
|
|
or3 $1, $1, %lo(__farbss_start)
|
|
mov $2, 0
|
|
movh $3, %uhi(__farbss_end)
|
|
or3 $3, $3, %lo(__farbss_end)
|
|
sub $3, $1
|
|
bsr memset
|
|
|
|
# enable interrupts
|
|
ei
|
|
|
|
# construct global class variables
|
|
bsr __invoke_init_section
|
|
|
|
# invoke main
|
|
mov $1, 0 # argc, argv, envp
|
|
mov $2, 0
|
|
mov $3, 0
|
|
bsr main
|
|
mov $1, $0
|
|
bsr exit
|
|
|
|
.global _exit
|
|
_exit:
|
|
# Prevent _exit recursion
|
|
movh $3, %uhi(_exit_in_progress)
|
|
or3 $3, $3, %lo(_exit_in_progress)
|
|
lw $5, ($3)
|
|
bnez $5, _skip_fini
|
|
mov $5, 1
|
|
sw $5, ($3)
|
|
|
|
# We don't need to preserve $5 because we're going to exit anyway.
|
|
mov $5,$1
|
|
|
|
# destruct global class variables
|
|
bsr __invoke_fini_section
|
|
mov $1,$5
|
|
|
|
_skip_fini:
|
|
|
|
#ifdef NOSIM
|
|
_exit_loop:
|
|
bra _exit_loop
|
|
#else
|
|
.2byte 0x7800 | ((SYS_exit & 0xe) << 7) | ((SYS_exit & 1) << 4)
|
|
ret
|
|
#endif
|
|
|
|
.data
|
|
_exit_in_progress: .word 0
|
|
|
|
|
|
|
|
# For these two, the epilogue is in crtn.S
|
|
|
|
.section .init
|
|
__invoke_init_section:
|
|
add $sp, -8
|
|
ldc $0, $lp
|
|
sw $0, ($sp)
|
|
|
|
.section .fini
|
|
__invoke_fini_section:
|
|
add $sp, -8
|
|
ldc $0, $lp
|
|
sw $0, ($sp)
|
|
|
|
#ifndef NOVEC
|
|
.section .vec, "ax"
|
|
.core
|
|
.org 0x0, 0
|
|
.global _exception_table
|
|
.type _exception_table,@function
|
|
_exception_table:
|
|
.p2align 2
|
|
.org 0x0000, 0
|
|
.global _reset
|
|
_reset:
|
|
jmp _handler_RESET
|
|
.org 0x0004, 0
|
|
jmp _handler_NMI
|
|
.org 0x0008, 0
|
|
jmp _handler_RI
|
|
.org 0x000c, 0
|
|
jmp _handler_ZDIV
|
|
.org 0x0010, 0
|
|
jmp _handler_BRK
|
|
.org 0x0014, 0
|
|
jmp _handler_SWI
|
|
.org 0x0018, 0
|
|
jmp _handler_DEBUG
|
|
.org 0x001c, 0
|
|
jmp _handler_DSP
|
|
.org 0x0020, 0
|
|
jmp _handler_COP
|
|
|
|
.org 0x30, 0
|
|
.global _interrupt_table
|
|
.type _interrupt_table,@function
|
|
_interrupt_table:
|
|
.org 0x0030
|
|
jmp _handler_INT0
|
|
.org 0x0034
|
|
jmp _handler_INT1
|
|
.org 0x0038
|
|
jmp _handler_INT2
|
|
.org 0x003c
|
|
jmp _handler_INT3
|
|
.org 0x0040
|
|
jmp _handler_INT4
|
|
.org 0x0044
|
|
jmp _handler_INT5
|
|
.org 0x0048
|
|
jmp _handler_INT6
|
|
.org 0x004c
|
|
jmp _handler_INT7
|
|
.org 0x0050
|
|
jmp _handler_INT8
|
|
.org 0x0054
|
|
jmp _handler_INT9
|
|
.org 0x0058
|
|
jmp _handler_INT10
|
|
.org 0x005c
|
|
jmp _handler_INT11
|
|
.org 0x0060
|
|
jmp _handler_INT12
|
|
.org 0x0064
|
|
jmp _handler_INT13
|
|
.org 0x0068
|
|
jmp _handler_INT14
|
|
.org 0x006c
|
|
jmp _handler_INT15
|
|
.org 0x0070
|
|
jmp _handler_INT16
|
|
.org 0x0074
|
|
jmp _handler_INT17
|
|
.org 0x0078
|
|
jmp _handler_INT18
|
|
.org 0x007c
|
|
jmp _handler_INT19
|
|
.org 0x0080
|
|
jmp _handler_INT20
|
|
.org 0x0084
|
|
jmp _handler_INT21
|
|
.org 0x0088
|
|
jmp _handler_INT22
|
|
.org 0x008c
|
|
jmp _handler_INT23
|
|
.org 0x0090
|
|
jmp _handler_INT24
|
|
.org 0x0094
|
|
jmp _handler_INT25
|
|
.org 0x0098
|
|
jmp _handler_INT26
|
|
.org 0x009c
|
|
jmp _handler_INT27
|
|
.org 0x00a0
|
|
jmp _handler_INT28
|
|
.org 0x00a4
|
|
jmp _handler_INT29
|
|
.org 0x00a8
|
|
jmp _handler_INT30
|
|
.org 0x00ac
|
|
jmp _handler_INT31
|
|
# NOVEC
|
|
#endif
|