/***************************************************************************/
/*

FILE
	__ppc_eabi_init.cpp

DESCRIPTION

	Use this file for C++.  Contains calls to initialize memory pools
	for use with malloc/free, exceptions and static initializers.  You
	may use it with C if you wish.  If used with C, your program will be
	a little bigger (368 bytes).

	Interface for board-level initialization and user-level initialization.
	
	If hardware initialization and pre-main user initialization are required,
	copy this file to your project directory and customize it (instead of
	customizing __start.c).
	
	Note that __init_hardware should not write on the stack until the
	memory controller is properly configured.

	
	void __init_hardware(void)
	
		Initialize the hardware, including the memory controller.
	
	void __init_user(void)
	
		Allow the user to perform initialization before calling main().
	
	void __init_cpp(void)
	
		CodeWarrior C++ initialization before calling main().
	
	void __init(void)
	
		CodeWarrior linker generated function for calling static 
		constructors.  Do not touch!

	void _ExitProcess(void)
 		
 		This function simply stalls the debugger.  You may want to rewrite this
 		function if you are using an OS.
	
 	abort and exit
 
 	In order to correctly implement the required startup/termination sequence for
 	C and C++ programs, we need to have an exit() routine that can be called by
 	the program startup code. The exit() routine is supposed to
 
 		(1)	call any functions registered via atexit()
 		(2) call destructors for any global objects
 		(3)	flush any unwritten buffers, close any open files, etc.
 		(4) terminates the program
 
 	We don't, however, want to require the ANSI C library for every CodeWarrior
 	program, since it drags in lots of code that may not be needed.
 
 	Instead we provide a dummy exit() function which simply calls the destructors
 	and terminates the program. We assume that any program which uses atexit()
 	or <stdio.h> and which requires those cleanup behaviors will have linked with
 	the ANSI C library, whose definition of exit() will override the one here.
 
 	We similarly define a dummy abort() function (which is called by the default
 	terminate() handler).
 
 	Programs which rely on the proper ANSI C/C++ behavior must use the ANSI C
 	library, and order it in the CodeWarrior project or command-line so that
 	its definitions supersede these definitions in the runtime support library.

COPYRIGHT	
	(c) 1997 Metrowerks Corporation
	All rights reserved.

HISTORY
	97 APR 17 LLY	Created.
	97 JUN 24 MEA	Added support for C++ and malloc memory heaps.
	97 JUL 17 SCM	Customized for MPC821 ADS board.
	97 JUL 20 MEA	Changed __exit to _ExitProcess so as not to conflict with MSL.
					_ExitProcess added to this file; removed form __start.c.

*/
/***************************************************************************/

#include <__ppc_eabi_init.h>
#include <__ppc_eabi_linker.h>		/* linker-generated symbol declarations */
#include <pool_alloc.h>
#include <NMWException.h>
#include <stdlib.h>

#ifdef __cplusplus
extern "C" {
#endif

extern void __sinit(void);
static void __init_cpp(void);

#ifdef __cplusplus
}
#endif

static int fragmentID;			/* ID given to fragment by exception-handling		*/


#define SRR0	26
#define SRR1	27
#define CTR
#define LR
#define IMMR	638
#define ICR		148
#define DER		149
#define ICTRL	158
#define IC_CST	560
#define DC_CST	568
#define SIUMCR	0x0000
#define SYPCR	0x0004
#define MAR		0x0164
#define MCR		0x0168
#define MAMR	0x0170
#define MBMR	0x0174
#define MPTPR	0x017a
#define MDR		0x017c
#define BR0		0x0100
#define OR0		0x0104
#define BR1		0x0108
#define OR1		0x010c
#define BR2		0x0110
#define OR2		0x0114
#define BR3		0x0118
#define OR3		0x011c
#define BR4		0x0120
#define OR4		0x0124
#define BR5		0x0128
#define OR5		0x012c
#define TBSCR	0x0200
#define	PISCR	0x0240
#define DISABLE_CACHE	0x0400
#define INVALID_CACHE	0x0C00

const unsigned int UpmATable[] =
{
/* Normal read */
0x8fffec24, 0x0fffec04, 0x0cffec04, 0x00ffec04,
0x00ffec00, 0x37ffec47, 0xffffffff, 0xffffffff,

/* Burst read */
0x8fffec24, 0x0fffec04, 0x08ffec04, 0x00ffec0c,
0x03ffec00, 0x00ffec44, 0x00ffcc08, 0x0cffcc44,
0x00ffec0c, 0x03ffec00, 0x00ffec44, 0x00ffcc00,
0x3fffc847, 0xffffffff, 0xffffffff, 0xffffffff,

/* Normal write */
0x8fafcc24, 0x0fafcc04, 0x0cafcc00, 0x11bfcc47,
0xc0ffcc84, 0xffffffff, 0xffffffff, 0xffffffff,

/* Burst write */
0x8fafcc24, 0x0fafcc04, 0x0cafcc00, 0x03afcc4c,
0x0cafcc00, 0x03afcc4c, 0x0cafcc00, 0x03afcc4c,
0x0cafcc00, 0x33bfcc4f, 0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,

/* Refresh */
0xc0ffcc84, 0x00ffcc04, 0x07ffcc04, 0x3fffcc06,
0xffffcc85, 0xffffcc05, 0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,

/* Exception */
0x33ffcc07, 0xffffffff, 0xffffffff, 0xffffffff

};

const unsigned int UpmBTable[] =
{
/* Normal read */
0x1f07fc04, 0xeeaefc04, 0x11adfc04, 0xefbbbc00,
0x1ff77c47, 0x1ff77c34, 0xefeabc34, 0x1fb57c35,

/* Burst read */
0x1f07fc04, 0xeeaefc04, 0x10adfc04, 0xf0affc00,
0xf0affc00, 0xf1affc00, 0xefbbbc00, 0x1ff77c47,
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,

/* Normal write */
0x1f27fc04, 0xeeaebc00, 0x01b93c04, 0x1ff77c47,
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,

/* Burst write */
0x1f07fc04, 0xeeaebc00, 0x10ad7c00, 0xf0affc00,
0xf0affc00, 0xe1bbbc04, 0x1ff77c47, 0xffffffff,
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,

/* Refresh */
0x1ff5fc84, 0xfffffc04, 0xfffffc04, 0xfffffc04,
0xfffffc84, 0xfffffc07, 0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,

/* Exception */
0x7ffffc07, 0xffffffff, 0xffffffff, 0xffffffff

};

asm void __init_hardware(void)
{
	/*
	 *	Initialize Motorola ADS board unless running with MWDebug.
	 *	Uncomment the initialization below if running with MPC8BUG
	 *	or standalone.  You may need to perform other initializations.
	 */
	nofralloc
	
	/*
	 *	When customizing, be aware that the memory controller may not be
	 *	configured.  R1, R2, and R13 are already initialized and cannot be used.
	 *  Stack pointer is configured, but the memory it points to is not!
	 */

	/* Our address is really in high Flash ROM space.  When reset, execution
	 * starts at 0x0100.  This code fragment jumps us to the correct 
	 * high memory area */
	
	lis r3, __init_hardware@h  /* high address of __start */
	ori r3, r3, __init_hardware@l
	addi r3, r3, 0x0014  /* Jumps us into the NOPs below */
	mtctr r3
	bctr
	
	nop
	nop

    /* Now we need to fix the LR since it points back to 0x0000_010x,
     * not 0x0280_010x like it needs to after we muck up the BCSR's */
     
    mflr r3
    oris r3, r3, 0x0280
    mtlr r3

//Setup MSR
	addi r4, r0, 0x1002
	mtmsr r4
	mtspr SRR1, r4

//Setup IMMR	
	lis r4, 0x0220 
	ori r4, r4, 0x0000
	mtspr IMMR, r4

//Disable and Invalidate I and D caches
	lis r3, DISABLE_CACHE
	mtspr IC_CST, r3
	isync
	mtspr DC_CST, r3
	
	lis r3, INVALID_CACHE
	mtspr IC_CST, r3
	isync
	mtspr DC_CST, r3
	
//Setup SYPCR & disable software watchdog
	lis r3, 0xffff
	ori r3, r3, 0xff08
	stw	r3, SYPCR(r4)


//Setup SIUMCR to 0x0101_2440
	addis r5, r0, 0x0101
	ori r5, r5, 0x2440
	stw r5, SIUMCR(r4)

#define DRAM_SIZE	4	// 4MB DRAMs normally shipped with FADS
//#define DRAM_SIZE 16
#define SDRAM_SIZE	4	// 4MB SDRAMs normally installed on FADS
#define FLASH_SIZE	2	// 2MB FLASH 

//Setup UPM A to access DRAMs
//Setup R5 with UPM Table location
	lis r5, UpmATable@h
	ori r5, r5, UpmATable@l
	
//Setup R6 with size of UPM table in words (64 = 0x0040)	
	lis r7, 0x0000
	ori r7, r7, 0x0040

//OR in the UPMA to R7 to find last MCR to execute because UPMA
	oris r7, r7, 0x0000
		
//Setup UPM write operation in MCR (0x0000_0000 because UPMA)
	lis r6, 0x0000
	ori r6, r6, 0x0000
	
//Upm Write loop
UpmAWriteLoop:
	lwz	r3, 0(r5)
	stw r3, MDR(r4)
	
	stw r6, MCR(r4)
	addi r5, r5, 0x0004
	addi r6, r6, 0x0001
	cmpw cr0, r6, r7
	blt UpmAWriteLoop
	
//Setup MAMR 
	lis r3, 0x9ca2
	ori r3, r3, 0x1114
	stw r3, MAMR(r4)

//Setup UPM B to access SDRAMs
//Setup R5 with UPM Table location
	lis r5, UpmBTable@h
	ori r5, r5, UpmBTable@l
	
//Setup R6 with size of UPM table in words (64 = 0x0040)	
	lis r7, 0x0000
	ori r7, r7, 0x0040

//OR in the UPMB to R7 to find last MCR to execute because UPMB
	oris r7, r7, 0x0080
		
//Setup UPM write operation in MCR (0x0080_0000 because UPMB)
	lis r6, 0x0080
	ori r6, r6, 0x0000
	
//Upm Write loop
UpmBWriteLoop:
	lwz	r3, 0(r5)
	stw r3, MDR(r4)
	
	stw r6, MCR(r4)
	addi r5, r5, 0x0004
	addi r6, r6, 0x0001
	cmpw cr0, r6, r7
	blt UpmBWriteLoop
	
//Setup MBMR
	lis r3, 0x8080
	ori r3, r3, 0x2114
	stw r3, MBMR(r4)

//Setup MPTPR	
	li	r3, 0x0400
	sth r3, MPTPR(r4)
	
//Setup base and option registers

//Flash settings
#if FLASH_SIZE==2
	lis r3, 0x0280
	ori r3, r3, 0x0001

	lis r5, 0xffe0
	ori r5, r5, 0x0d34
	
	stw r3, BR0(r4)
	stw r5, OR0(r4)

	lis r3, 0x0400
	ori r3, r3, 0x0001

	lis r5, 0xfc00
	ori r5, r5, 0x0790
	
	stw r3, BR5(r4)
	stw r5, OR5(r4)
#endif

#if DRAM_SIZE == 4
	lis r3, 0x0000
	ori r3, r3, 0x0081

	lis r5, 0xffc0
	ori r5, r5, 0x0800
	
	stw r3, BR2(r4)
	stw r5, OR2(r4)
	
	lis r3, 0x8000
	ori r3, r3, 0x0000
	
	lis r5, 0xffc0
	ori r5, r5, 0x0800
	
	stw r3, BR3(r4)
	stw r5, OR3(r4)
#endif

#if DRAM_SIZE == 16
	lis r3, 0x0000
	ori r3, r3, 0x0081

	lis r5, 0xff00
	ori r5, r5, 0x0800
	
	stw r3, BR2(r4)
	stw r5, OR2(r4)
	
	lis r3, 0x8000
	ori r3, r3, 0x0000
	
	lis r5, 0xffc0
	ori r5, r5, 0x0800
	
	stw r3, BR3(r4)
	stw r5, OR3(r4)
#endif
	
#if SDRAM_SIZE==4
	lis r3, 0x0300
	ori r3, r3, 0x00c1

	lis r5, 0xffc0
	ori r5, r5, 0x0a00
	
	stw r3, BR4(r4)
	stw r5, OR4(r4)
	
//Do SDRAM initialization routine
	lis r3, 0
	ori r3, r3, 0x0088
	stw r3, MAR(r4)
	
	lis r3, 0x8080
	ori r3, r3, 0x8105
	stw r3, MCR(r4)
	
	lis r3, 0x8080
	ori r3, r3, 0x8130
	stw r3, MCR(r4)

#endif

//BCSR settings
	lis r17, 0x0210
	ori r17, r17, 0x0001

	lis r18, 0xffff
	ori r18, r18, 0x8110
	
	stw r17, BR1(r4)
	stw r18, OR1(r4)

//Clear TimeBase and PIT interrupts
//Freeze TB and PIT in debug mode
	li r3, 0x00c2
	sth r3, TBSCR(r4)
	
	li r3, 0x0082
	sth r3, PISCR(r4)
	
//Setup the rest of the core registers	

//Normal mode, no show cycles
	lis r3, 0x0000
	ori r3, r3, 0x0007
	mtspr ICTRL, r3

//DER = 0x0, all exceptions to target
	lis r3, 0xfdc7
	ori r3, r3, 0x400f
	mtspr DER, r3

//Clear ICR
	mtspr ICR, r3
		
	blr

}

static void AllocMoreHeaps(void)
{
	/*
	 *	By default, we MSL's allocation (malloc/free) even with C++.
	 *	If you have declared a heap size in the Project Pref panel,
	 *	a defaull heap will be created the first time you call
	 *	malloc.  You can add more calls to init_alloc to create additional
	 *	heaps.
	 */
//	init_alloc(some address, some size);
}

asm void __init_user(void)
{
	fralloc
	/*
	 *	Allocate additional heaps.
	 */
//	bl		AllocMoreHeaps

	/*
	 *	initialization of exceptions and static initializers
	 */	
	bl		__init_cpp

	/*
	 *	Add your initializations here.
	 */
	frfree

	blr
}

static asm char *GetR2(void)
{
	/*
	 *	Get the contents of the r2 register
	 */
	nofralloc
	mr      r3,r2
	blr
}


extern void __init_cpp(void)
{
	char *R2;				/* r2 register contents								*/
	/*
	 *	Default uses one call to __register_fragment
	 *	To use linker generated symbols that aren't C variables,
	 *	you fake out the compiler and pretend that you are 
	 * 	only interested in the address.
	 */
	R2 = GetR2();
	fragmentID = __register_fragment(0,(char *)(-1),0,(char *)(-1),
							_fextabindex, _eextabindex ,R2);
	/*
	 *	call static initializers
	 */
	__sinit();
}


#pragma overload void abort(void);
void abort(void)
{
	_ExitProcess();
}


#pragma overload void exit(int status);
void exit(int status)
{
	#pragma unused(status)
	__destroy_global_chain();
	_ExitProcess();
}


/*
 *	_ExitProcess
 *
 *	PowerPC EABI Runtime termination
 */
asm void _ExitProcess(void)
{
	nofralloc
	
	tw		31,r3,r4					/* arbitrary break trap for halt */
}
