# 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
