// erase018.c

#include "..\UserBootModeXmodem\flash.h"

// #define H83069F			// defined on compiler command line
//#define INUSERBOOTMODE	// defined on compiler command line

#include <machine.h>

typedef unsigned short (*pt2Function)(unsigned char );		// function pointer for calling the RAM based erase routine

#pragma section PTRTABLE
const pt2Function ptrtable[] = {
	Erase018FlashBlock
};
#pragma section

//
// The Hitachi MCS C/C++ SH compiler passes parameters in ER0 and ER1 with the return value in R0
// The Hitachi MCS C/C++ H8 compiler passes parameters in R4 and R5 with the return value in R0
// see the relevant documentation for further details
//
void func (unsigned long ul1, unsigned long ul2)
{
	// dummy function used to get the passed values into
	// registers ER0 and ER1 (H8)
	// registers R4 and R5 (SH)
}

// to use inline assembler with the MCS C/C++ compiler the compiler output must be
// set to assembler source, this can cause problems when dubugging
#pragma inline_asm( no_operation )
static void no_operation ( void )
{
	NOP
}

unsigned short Erase018FlashBlock( unsigned char FlashBlock )
{
	//
	// Function to erase the specified 0.18um flash erase block
	//
	// Note:
	// This function along with the functions 'func' and 'no_operation' must all be
	// executed from on-chip RAM.
	// This means that these functions must be linked to internal RAM to ensure that any
	// references to absolute addresses refer to addresses in the internal RAM.  Control
	// must not return to flash based code until this function has completed.
	//
	// While executing from internal RAM this function must not access any code or data
	// located in flash.  This includes constant data and also library routines.  For example,
	// when building for the H8/300H with the Hitachi/MCS v4.0a compiler toolchain the library
	// functions '$sp_regsv$3' and '$spregld2$3' are  used by these functions.  Therefore,
	// these library routines must also be located in the internal RAM.
	//
	// One of the simplest ways to achieve this is to build the functions in this file as a 
	// completely separate project which is linked to internal RAM.  This RAM based code
	// should then be stored in the flash by the project that is to use the functions.  This
	// project should then copy the RAM based code into RAM at runtime and execute it from there.
	//
	// There are a number of methods of taking the RAM based code, moving it to flash for storage
	// and then moving it to RAM for execution.  Some of these methods are described in apps notes
	// numbers 64, 113 and 130.
	//
	// If a separate project is not used for the functions in this file then any library calls and
	// constant data accesses are likely to access the flash memory unless an alternative approach
	// is adopted.
	//
	// parameters:
	// -----------
	// FlashBlock	-	flash erase block to be erased, the caller should ensure that the value is valid
	//
	// returns:
	// --------
	// result of erase request
	// 0x0000		-	block erased ok
	// 0x01xx		-	download error
	// 0x02xx		-	initialisation error
	// 0x08xx		-	erasing error
	// where xx is the value indicating the exact nature of the error as specified in the ROM
	// section of the hardware manual
	//

	volatile unsigned char *dfpr;		// pointer used to access the contents of the FTDAR addresswhich contains
										// the pass or fail information when downloading the erase routine to internal RAM
	unsigned char fpfr;					// flash pass/fail result parameter
										// variable to store the result of initialisation and erase routines
	unsigned long fpefeq, fubra, febs;	// variables used for passing CPU frequency, user branch destination address
										// and flash erase block number
	unsigned char (*fp) ( void );		// function pointer for calling the intialisation and programming routines
	unsigned short status;				// variable for calculating the return value for this function

	#ifndef H83069F
	// if SH-2(e) set the vector base register to zero
	set_vbr( (void **) 0 );
	#endif

	// initialise dfpr to point to first byte in download destination area
	// specified by FDAR
	dfpr = (unsigned char *) FTDAR_ADDRESS;

	// set address where flash prog and erase routines will be loaded
	// approx 2kB of RAM from this address will be unavailable to the user program
	// while flash erasing is being performed
	FLASH_FTDAR = FTDAR_START_ADDRESS;

	// select flash erasing program to be downloaded
	FLASH_FPCS.BIT.PPVS = 0;	// do NOT download flash programming program RAM
	FLASH_FECS.BIT.EPVB = 1;	// download flash erasing program to RAM

	// initialise contents of dfpr
	// the contents of this pointer will contain the status of the request to download the
	// erasing program to RAM
	*dfpr = 0xff;

	// start download of flash programming program
	// disable software protection
	FLASH_FKEY = 0xa5;
	FLASH_FCCS.BIT.SCO = 1;
	no_operation();
	no_operation();
	no_operation();
	no_operation();
	// enable software protection
	FLASH_FKEY = 0;

	// check that the download has completed successfully
	// if *dfpr == 
	// 0x00 		-	indicates download was successful
	// 0xff 		-	indicates that there was something wrong with the FTDAR value idicated by
	//					the TDER (bit 7) error bit in FTDAR
	// bit 0 set	-	downloading of on-chip program failed (SF==1)
	// bit 1 set 	-	FKEY setting is abnormal (FK==1)
	// bit 2 set 	-	Download error as multi-selection or non-supported program selected (SS==1)
	if( *dfpr != 0 )
	{
		// the download has failed for some reason
		status = (unsigned short) *dfpr;
		status |= (unsigned short) FLASH_PROG_ERASE_DOWNLOAD_ERROR;
		
		return status;
	}

	// set the operating frequency
	// FPEFEQ value must be loaded into ER0 (H8) / R4 (SH)
	// FUBRA value must be loaded into ER1 (H8) / R5 (SH)
	// return value is in R0(L)
	// dummy 'func' function used to ensure correct function call interface
	fpefeq = CPU_CLOCK_FREQ;
	fubra = USER_BRANCH_DEST_ADDRESS;		// user branch processing not required
	func( fpefeq, fubra );
	// load the address of the erase intialisation routine into the function pointer
	fp = (void *) INIT_ERASE_ADDRESS;
	fpfr = fp();	// the returned value is in fpfr ( R0(L) )

	// check that the initialisation was performed without errors
	// if fpfr ==
	// 0x00			-	indicates initialisation was successful
	// bit 0 set	-	initialisation failed (SF==1)
	// bit 1 set	-	operating frequency invalid (FQ==1)
	// bit 2 set 	-	user branch address invalid (BR==1)
	if( fpfr != 0 )
	{
		// there has been an error
		status = (unsigned short) fpfr;
		status |= (unsigned short) FLASH_INIT_ERROR;
		
		return status;
	}

	// in either user mode or user boot mode only the user mat can be erased so	
	// if in user boot mode then the MAT should be switched from the user boot mat
	// to the user mat
	#ifdef INUSERBOOTMODE
	// set FMATS to any value other than H'AA
	FLASH_FMATS = 0;
	no_operation();
	no_operation();
	no_operation();
	no_operation();
	#endif
	
	// disable software protection
	FLASH_FKEY = 0x5a;

	// set the flash block to be erased
	// FEBS parameter must be loaded into (E)R0 (H8) / R4 (SH)
	// return value is in R0(L)
	// dummy 'func' function used to ensure correct function call interface
	febs = (unsigned long) FlashBlock;
	func( febs, 0 );
	fp = (void *) ERASE_ROUTINE_ADDRESS;
	fpfr = fp();

	// if in user boot mode then switch MAT back to the user boot MAT
	#ifdef INUSERBOOTMODE
	// set FMATS to H'AA
	FLASH_FMATS = 0xAA;
	no_operation();
	no_operation();
	no_operation();
	no_operation();
	#endif

	// enable software protection
	FLASH_FKEY = 0;
	
	// check if block erased ok
	if( fpfr != 0 )
	{
		// there has been an erasing error
		status = (unsigned short) fpfr;
		status |= (unsigned short) FLASH_ERASING_ERROR;
		
		return status;
	}
	else
	{
		return (unsigned short) FLASH_NO_ERROR;
	}
}