.globl  _start
.globl  _exit


#ifdef BOOT_FROM_FLASH
.text
.section .rhcw,"a"	    # Reset configuration half word (RCHW)
# ifdef __PPC_VLE__
	.long	0x015a0000  # Magic BOOT_ID for Freescale VLE code
# else
	.long	0x005a0000  # Magic BOOT_ID for Power Architecture code
# endif
	.long	_start
#endif


.macro li32 reg,imm
	lis  	\reg,\imm@h
	ori  	\reg,\reg,\imm@l
.endm

.macro ivor spr,reg,imm
	lis  	\reg,0
	ori  	\reg,\reg,\imm@l   # "li reg,\imm@l" should work too
	mtspr	\spr,\reg
.endm


.text
.section .start,"xa"
_start:
	li   	%r0,0
	li   	%r1,0
	li   	%r2,0
	li   	%r3,0
	li   	%r4,0
	li   	%r5,0
	li   	%r6,0
	li   	%r7,0
	li   	%r8,0
	li   	%r9,0
	li   	%r10,0
	li   	%r11,0
	li   	%r12,0
	li   	%r13,0
	li   	%r14,0
	li   	%r15,0
	li   	%r16,0
	li   	%r17,0
	li   	%r18,0
	li   	%r19,0
	li   	%r20,0
	li   	%r21,0
	li   	%r22,0
	li   	%r23,0
	li   	%r24,0
	li   	%r25,0
	li   	%r26,0
	li   	%r27,0
	li   	%r28,0
	li   	%r29,0
	li   	%r30,0
	li   	%r31,0

init_stackpointer:
	li32 	%sp,__stack_end

init_int_vector_prefix:
	lis  	%r3,IVOR0_entry@h
	mtspr	63,%r3     # IVPR

# ifdef __PPC_VLE__
check_cpu:
	mfspr	%r7,287    # read Processor Version Register (PVR)
	srwi 	%r7,%r7,20 # get only upper 12 bit, which contain Manuf.ID and processor type fields
	cmpwi	%r7,0x817  # check if its an Freescale e200z0 core (0b100000010111)
	beq  	end_mmu    # for e200z0 branch over initialization of Interrupt Vector Offset table (hardwired) and MMU (MMU not available)
#endif

init_int_vector_offsets:
	ivor 	400,%r3,IVOR0_entry    # IVOR0
	ivor 	401,%r3,IVOR1_entry    # IVOR1
	ivor 	402,%r3,IVOR2_entry    # IVOR2
	ivor 	403,%r3,IVOR3_entry    # IVOR3
	ivor 	404,%r3,IVOR4_entry    # IVOR4
	ivor 	405,%r3,IVOR5_entry    # IVOR5
	ivor 	406,%r3,IVOR6_entry    # IVOR6
	ivor 	407,%r3,IVOR7_entry    # IVOR7
	ivor 	408,%r3,IVOR8_entry    # IVOR8
	ivor 	409,%r3,IVOR9_entry    # IVOR9
	ivor 	410,%r3,IVOR10_entry   # IVOR10
	ivor 	411,%r3,IVOR11_entry   # IVOR11
	ivor 	412,%r3,IVOR12_entry   # IVOR12
	ivor 	413,%r3,IVOR13_entry   # IVOR13
	ivor 	414,%r3,IVOR14_entry   # IVOR14
	ivor 	415,%r3,IVOR15_entry   # IVOR15
	ivor 	528,%r3,IVOR32_entry   # IVOR32
	ivor 	529,%r3,IVOR33_entry   # IVOR33
	ivor 	530,%r3,IVOR34_entry   # IVOR34

#ifdef BOOT_FROM_FLASH

init_mmu:
	li32 	%r4,__tlbdata_size
	mtctr	%r4
	li32 	%r4,__tlbdata_start
	subi 	%r4,%r4,4
init_mmu_loop:
	lwzu 	%r3, 4(%r4)
	mtspr	624,%r3         # MAS0
	lwzu 	%r3, 4(%r4)
	mtspr	625,%r3         # MAS1
	lwzu 	%r3, 4(%r4)
	mtspr	626,%r3         # MAS2
	lwzu 	%r3, 4(%r4)
	mtspr	627,%r3         # MAS3
	tlbwe
	isync
	bdnz 	init_mmu_loop
#endif
end_mmu:

disable_watchdog:
	li32 	%r4,0xFFF38000  #Software Watchdog Timer (SWT) base address
	li32   	%r3,0xC520
	stw  	%r3,0x10(%r4)   # SWT_SR : 1st magic word to clear the soft lock bit
	li32   	%r3,0xD928
	stw  	%r3,0x10(%r4)   # SWT_SR : 2nd magic word to clear the soft lock bit
	li32 	%r3,0xC000011A
	stw  	%r3,0x00(%r4)   # SWT_CR : disable watchdog and set soft lock bit

#ifdef BOOT_FROM_FLASH
init_sram:
	# Init ECC of SRAM (and clear BSS section at the same time)
	# For ECC we wouldn't care about the content of the registers,
	# but for the BSS section we're lucky that we've set r16-r31 to zero before
	li32 	%r3,__SRAM_start
	li32 	%r4,__SRAM_size
	srwi 	%r4,%r4,6       # divide size of SRAM by 64=16*4 (16-Registers with 4 Bytes)
	mtctr	%r4
init_sram_loop:
	stmw 	%r16,0(%r3)     # write r16-r31 to SRAM to initialize ECC
	addi 	%r3,%r3,64
	bdnz 	init_sram_loop

init_data:
	li32 	%r3,__data_vaddr
	li32 	%r4,__data_laddr
	li32 	%r5,__data_size
	bl   	memcpy

#else

init_stack:
	li   	%r0,0
	stw  	%r0,0(%sp)      # clear Back Chain Word
bss_clear:
	li32 	%r3,__bss_start
	li32 	%r4,__bss_size
	cmpwi	%r4,0
	beq  	gomain
	srwi 	%r4,%r4,2
	mtctr	%r4
	subi 	%r3,%r3,4
bss_clear_loop:
	stwu 	%r0,4(%r3)
	bdnz 	bss_clear_loop
#endif


gomain:
	li   	%r3,0
	li   	%r4,0
	li   	%r5,0
	bl   	main

_exit:
	b    	_exit


_start_background:    # very reduced start-sequence for secondary core of a Bolero3M
	li32 	%r0,_sp_background
	lwz  	%sp,0(%r0)      # load initial value of stack pointer from memory
	li   	%r0,0
	stw  	%r0,0(%sp)      # clear Back Chain Word
	bl   	background
	b    	_exit

.align  2
_sp_background:
	.long	0x40020000


#ifdef BOOT_FROM_FLASH
.rodata
.section .mmudata,"a"
__tlbdata_start:
	/*** TLB1 entry 0 -> FLASH ***/
	.long	0x10000000  # MAS0: ESL 0
	.long	0x80000600  # MAS1: valid, no-protect, global, 4 MB
# ifdef __PPC_VLE__
	.long	0x00000020  # MAS2: log.addr.0x00000000, big-endian, VLE
# else
	.long	0x00000000  # MAS2: log.addr.0x00000000, big-endian
# endif
	.long	0x0000003F  # MAS3: phy.addr.0x00000000, full-access
	/*** TLB1 entry 1 -> SRAM  ***/
	.long	0x10010000  # MAS0: ESL 1
	.long	0x80000400  # MAS1: valid, no-protect, global, 256 KBytes
	.long	0x40000000  # MAS2: log.addr.0x40000000, big-endian
	.long	0x4000003F  # MAS3: phy.addr.0x40000000, full-access
	/*** TLB1 entry 2 -> Flash configuration ***/
	.long	0x10020000  # MAS0: ESL 2
	.long	0xC0000500  # MAS1: valid, no-protect, global, 1 MB
	.long	0xC3F0000A  # MAS2: log.addr.0xC3F00000, cache-inhibited, guarded (no speculative access), big-endian
	.long	0xC3F0003F  # MAS3: phy.addr.0xC3F00000, full-access
	/*** TLB1 entry 3 -> Peripherals ***/
	.long	0x10030000  # MAS0: ESL 3
	.long	0xC0000500  # MAS1: valid, no-protect, global, 1 MB
	.long	0xFFF0000A  # MAS2: log.addr.0xFFF00000, cache-inhibited, guarded (no speculative access), big-endian
	.long	0xFFF0003F  # MAS3: phy.addr.0xFFF00000, full-access
	/*** TLB1 entry 4 -> disable default entry of SPC564A80-V2 ***/
	.long	0x10040000  # MAS0: ESL 4
	.long	0x00000000  # MAS1: invalid 
	.long	0x00000000  # MAS2 
	.long	0x00000000  # MAS3 
__tlbdata_end:
	.set __tlbdata_size, (__tlbdata_end-__tlbdata_start)/16
#endif


.section .ivec,"xa"  # for e200z0 cores this section must be aligned to 4096 bytes (since this e200z0 has a hardwired Interrupt Vector Offset table)
.align  4
IVOR0_entry:  #Critical Input
	nop
	nop
	nop
	b IVOR0_entry

.align  4
IVOR1_entry:  #Machine Check
	nop
	nop
	nop
	b IVOR1_entry

.align  4
IVOR2_entry:  #Data Storage
	nop
	nop
	nop
	b IVOR2_entry

.align  4
IVOR3_entry:  #Instruction Storage
	nop
	nop
	nop
	b IVOR3_entry

.align  4
IVOR4_entry:  #External Input
	nop
	nop
	nop
	b IVOR4_entry

.align  4
IVOR5_entry:  #Alignment
	nop
	nop
	nop
	b IVOR5_entry

.align  4
IVOR6_entry:  #Program
	nop
	nop
	nop
	b IVOR6_entry

.align  4
IVOR7_entry:  #Floating-Point Unavailable
	nop
	nop
	nop
	b IVOR7_entry

.align  4
IVOR8_entry:  #System Call
	nop
	nop
	nop
	b IVOR8_entry

.align  4
IVOR9_entry:  #Auxiliary Processor Unavailable
	nop
	nop
	nop
	b IVOR9_entry

.align  4
IVOR10_entry:  #Decrementer
	nop
	nop
	nop
	b IVOR10_entry

.align  4
IVOR11_entry:  #Fixed Interval Timer
	nop
	nop
	nop
	b IVOR11_entry

.align  4
IVOR12_entry:  #Watchdog
	nop
	nop
	nop
	b IVOR12_entry

.align  4
IVOR13_entry:  #Data TLB Error
	nop
	nop
	nop
	b IVOR13_entry

.align  4
IVOR14_entry:  #Instruction TLB Error
	nop
	nop
	nop
	b IVOR14_entry

.align  4
IVOR15_entry:  #Debug
	nop
	nop
	nop
	b IVOR15_entry

.align  4
IVOR32_entry:  #SPE APU unavailable
	nop
	nop
	nop
	b IVOR15_entry

.align  4
IVOR33_entry:  #SPE Floating-point Data
	nop
	nop
	nop
	b IVOR15_entry

.align  4
IVOR34_entry:  #SPE Floating-point Round
	nop
	nop
	nop
	b IVOR15_entry

