/*** actuationBlock($actuationFunction, $Letter) ***/
void $actuationFunction(void) {
        while(MTU20.TSR.BIT.TGF$Letter != 1)
                ;
        MTU20.TSR.BIT.TGF$Letter = 0;
        set_imask(15);
        actRd$Letter = actRd$Letter+1;
        if (actRd$Letter == 10)
                actRd$Letter = 0;
        if(actSt$Letter == 0) {
                actSt$Letter = 1;
        }
        else {
                actSt$Letter = 0;
        }

        if((actWr$Letter != actRd$Letter) && (actNs$Letter[actRd$Letter] <
                        ((4*divideByValue/2)*(65536 + intDel)))) {
                MTU20.TGR$Letter = actNs$Letter[actRd$Letter]/(4*divideByValue/2);
                MTU20.TSR.BIT.TGF$Letter = 0;
                MTU20.TIER.BIT.TGIE$Letter = 1;

                if(actSt$Letter == 0) {
                        MTU20.TIOR.BIT.IO$Letter = 2;
                } else {
                        MTU20.TIOR.BIT.IO$Letter = 5;
                }
        } else {
                MTU20.TIER.BIT.TGIE$Letter = 0;
                MTU20.TIOR.BIT.IO$Letter = 0;
        }
        set_imask(0);
}
Пример #2
0
void CPU_Sleep(SLEEP_LEVEL level, UINT64 wakeEvents)
{
    UINT16 iprUsart = 0;
    UINT16 iprSocket = 0;
    
    int return_value;
    
/* Detecting if Keypad is pushed.*/
#if 0
    return_value = g_GPIO_KEYPAD_Driver.KeyPad_Search();
    if(return_value != -1 ) trapa(32);
#endif
/* */

    
    if (0 != (wakeEvents & SYSTEM_EVENT_FLAG_COM_IN))
    {
        iprUsart = IPR16; 
        IPR16 |= 0xDDD0;
    }

    if (0 != (wakeEvents & SYSTEM_EVENT_FLAG_SOCKET))
    {
        iprSocket = IPR19;

        IPR19 |= 0x00D0;
    }
    
    
    switch(level)
    {
        case SLEEP_LEVEL__DEEP_SLEEP:
            STBCR = 8;
            break;
        default:
            STBCR = 0;
            break;
    }

    UINT8 mask = get_imask();

    set_imask(0xC);
    
    sleep();

    set_imask( mask );

    if (0 != (wakeEvents & SYSTEM_EVENT_FLAG_COM_IN))
    {
        IPR16 = iprUsart;
    }

    if (0 != (wakeEvents & SYSTEM_EVENT_FLAG_SOCKET))
    {
        IPR19 = iprSocket;
    }
    
}
Event* newEvent(void) {
    Event* result;
        set_imask(15);

    result = FREE_EVENT_LIST;
    FREE_EVENT_LIST = FREE_EVENT_LIST->nextEvent;

        set_imask(0);
    return result;
}
void SmartPtr_IRQ::Probe()
{
    UINT32 Cp = m_state;


    if(Cp != DISABLE_STATE)
    {
        set_imask(Cp);
        set_imask(DISABLE_STATE);
    }
}
Пример #5
0
void CPU_Sleep(SLEEP_LEVEL level, UINT64 wakeEvents)
{
    UINT16 iprUsart = 0;
    UINT16 iprSocket = 0;
    
    int return_value;
    
    /* Detecting if Keypad is pushed.*/

    return_value = g_SH7264_Keypad_Driver.Key_Press();
    
    if(return_value != -1 ) trapa(32);
    
    if (0 != (wakeEvents & SYSTEM_EVENT_FLAG_COM_IN))
    {
        iprUsart = IPR17; 
        IPR17 |= 0xDDDD;
    }

    if (0 != (wakeEvents & SYSTEM_EVENT_FLAG_SOCKET)){
        iprSocket = IPR01; 
        IPR01 |= 0x0D00;
    }    
    
    switch(level)
    {
        case SLEEP_LEVEL__DEEP_SLEEP:
            STBCR = 8;
            break;
        default:
            STBCR = 0;
            break;
    }

    UINT8 mask = get_imask();

    set_imask(0xC);
    
    sleep();

    set_imask( mask );

    if (0 != (wakeEvents & SYSTEM_EVENT_FLAG_COM_IN))
    {
        IPR17 = iprUsart;
    }

    if (0 != (wakeEvents & SYSTEM_EVENT_FLAG_SOCKET)){        
        IPR01 = iprSocket;
    }
    
}
Пример #6
0
/* -------------------------------------------------
 * @関数名				:	MotorDriver_Init
 * @概要				:	モータポートのタイマ設定,
 							IO(PC,PD)の出力設定を行う
 * @引数-motor_word		:	16bitで初期化する16個の
 							モータポートを指定する
		-tc_protect_word:	貫通電流対策をするモータ
							ポートを指定する
 * @戻り値				:	なし
 * ---------------------------------------------- */
void MotorDriver_Init(uint16_t motor_word, uint16_t tc_protect_word)
{
	int port, ch;
	
	for(port = 0; port < 2; port++)
	{
		for(ch = 0; ch < 8; ch++)
		{
			if(motor_word	   & (1<<(port*8+ch)))	motor_status[port].isEnable_PWM |= (3<<(ch*2));
			if(tc_protect_word & (1<<(port*8+ch)))	motor_status[port].isEnable_TCprotection |= (1<<ch);
		}
	}
		
	/* PORTC */
	PFC.PCCR.WORD	&= ~motor_status[0].isEnable_PWM;	// PORTCをIOポートにする
	PFC.PCIOR.WORD	|=  motor_status[0].isEnable_PWM;	// PORTCを出力ポートにする

	/* PORTD */
	PFC.PDCRL1.WORD &= ~motor_status[1].isEnable_PWM;	// PORTDをIOポートにする
	PFC.PDCRL2.WORD &= ~motor_status[1].isEnable_PWM;
	PFC.PDIORL.WORD |=  motor_status[1].isEnable_PWM;	// PORTDを出力ポートにする

	
	/* CMT0を使用 */
	MST.CR2.BIT._CMT	= 0;	// CMTのスタンバイ解除
	CMT.CMSTR.BIT.STR0	= 0;	// カウント停止
	CMT0.CMCSR.BIT.CMIE = 1;	// コンペアマッチ割り込み許可
	CMT0.CMCSR.BIT.CKS	= 0;	// 内部クロック/8 = 3.125MHzでカウント
	CMT0.CMCOR			= 25-1;	// 割り込みの周期を3.125MHzで25カウント:125kHz(割り込み周波数)に指定
	INTC.IPRG.BIT._CMT0	= 0x0F;	// 割り込み優先レベルを15にセット。
	CMT0.CMCSR.BIT.CMF	= 0;	// フラグクリア
	set_imask(0);				// 割り込み許可
	CMT.CMSTR.BIT.STR0	= 1;	// カウント開始
}
void SmartPtr_IRQ::Restore()
{
    UINT32 Cp = m_state;

    if(Cp != DISABLE_STATE)
    {
        set_imask(Cp);
    }
}
BOOL SmartPtr_IRQ::ForceDisabled(void* context)
{
    UINT32 Cp;

    Cp = get_imask();
    set_imask(DISABLE_STATE);

    return (Cp != DISABLE_STATE);
}
void SafeToProcessInterruptHandler(void) {

        while(MTU20.TSR2.BIT.TGFE != 1)
                ;

        MTU20.TSR2.BIT.TGFE = 0;

        set_imask(15);

        MTU20.TIER2.BIT.TGIEE = 0;

        lastTimerInterruptTime.secs = (NS_UINT32)-1;
        lastTimerInterruptTime.nsecs = (NS_UINT32)-1;

        set_imask(0);


        processEvents();
}
void SmartPtr_IRQ::Disable()
{
    UINT32 Cp;

    Cp = get_imask();

    set_imask(DISABLE_STATE);

    m_state = Cp;
}
Пример #11
0
void vPortYield( void )
{
long lInterruptMask;

	/* Ensure the yield trap runs at the same priority as the other interrupts
	that can cause a context switch. */
	lInterruptMask = get_imask();

	/* taskYIELD() can only be called from a task, not an interrupt, so the
	current interrupt mask can only be 0 or portKERNEL_INTERRUPT_PRIORITY and
	the mask can be set without risk of accidentally lowering the mask value. */	
	set_imask( portKERNEL_INTERRUPT_PRIORITY );
	
	trapa( portYIELD_TRAP_NO );
	
	/* Restore the interrupt mask to whatever it was previously (when the
	function was entered). */
	set_imask( ( int ) lInterruptMask );
}
Пример #12
0
void sci_setup(){

	//出力設定
	//sci0
	set_imask(5);
	
	//SCI1のボーレートはSCI0のボーレートは同じ、もしくはそれ以下
//	SCI0_INIT(76800);
	SCI1_INIT(115200);
	SCI2_INIT(115200);
}
Пример #13
0
void HW_Terminate( void )
{
	FS_Terminate( );
	syRtcFinish( );
	PER_Terminate( );
	kmUnloadDevice( );
	syStartGlobalDestructor( );
	MEM_Terminate( );
	syHwFinish( );
	set_imask( 15 );
}
void processEvents() {
    Event* event = NULL;
    Time processTime;
    Time platformTime;
    getRealTime(&platformTime);
    set_imask(15);
    event = peekEvent(NULL);
    while (event && higherPriority(event)) {
        safeToProcess(event, &processTime);
        if (compareTime(platformTime, processTime) >= 0) {
            queuePriority(event);
            removeAndPropagateSameTagEvents(event);
            setCurrentModelTag(event);
            set_imask(0);
            fireActor(event);
            getRealTime(&platformTime);
            set_imask(15);
            freeEvent(event);
            stackedDeadlineIndex--;
            event = NULL;
        }
        else {
            if (compareTime(processTime, lastTimerInterruptTime) == LESS) {
                lastTimerInterruptTime.secs = processTime.secs;
                lastTimerInterruptTime.nsecs = processTime.nsecs;
                setTimedInterrupt(&processTime);
            }
        }
        event = peekEvent(event);
    }
    /*
    if (stackedModelTagIndex >= 0) {
        currentMicrostep = executingModelTag[stackedModelTagIndex].microstep;
        currentModelTime = executingModelTag[stackedModelTagIndex].timestamp;
        stackedModelTagIndex--;
    } else {
        DBG(("cannot restore model tag\r\n"));
    }
    */
    set_imask(0);
}
void CG_3_T_Rex_noNetwork_v1_ContactController_ContactControllerMicro_ActuatorSetup2(void) {
/*$P*/
//void xxxxx(void) {
    /* Fire CG_3_T_Rex_noNetwork_v1_ContactController_ContactControllerMicro_ActuatorSetup2 */
    set_imask(15);
        actSA[actWrA] = currentModelTime.secs - Seconds;
    if (currentModelTime.nsecs < nanoSeconds) {
                actSA[actWrA]--;
                actNsA[actWrA] = currentModelTime.nsecs + 1000000000 - nanoSeconds;
    } else {
                actNsA[actWrA] = currentModelTime.nsecs - nanoSeconds;
    }
    set_imask(0);

    if((MTU20.TIOR.BIT.IOA == 0) && (actSA[actWrA] == 0) && (actNsA[actWrA] < ((4*divideByValue/2)*(65536 + intDel)))) {
        MTU20.TGRA = actNsA[actWrA]/(4*divideByValue/2);
        MTU20.TSR.BIT.TGFA = 0;
        MTU20.TIER.BIT.TGIEA = 1;
        if(actStA == 0)
        MTU20.TIOR.BIT.IOA = 2;
        else
        MTU20.TIOR.BIT.IOA = 5;
    }
        actWrA = actWrA+1;
        if(actWrA == 10)
                actWrA = 0;

        actSA[actWrA] = currentModelTime.secs - Seconds;
    if (currentModelTime.nsecs + actWidth < nanoSeconds) {
                actSA[actWrA]--;
                actNsA[actWrA] = currentModelTime.nsecs + actWidth + 1000000000 - nanoSeconds;
    } else {
                actNsA[actWrA] = currentModelTime.nsecs + actWidth - nanoSeconds;
    }
        actWrA = actWrA+1;
        if(actWrA == 10)
                actWrA = 0;

    /* generate code for clearing Event Head buffer. */
    Event_Head_CG_3_T_Rex_noNetwork_v1_ContactController_ContactControllerMicro_ActuatorSetup2_input[0] = NULL;
}
void addEvent(Event* newEvent) {
    Event* compareDeadline;
        set_imask(15);

    compareDeadline = DEADLINE_QUEUE_HEAD;
    if (compareDeadline == NULL) {
        DEADLINE_QUEUE_HEAD = newEvent;
        DEADLINE_QUEUE_TAIL = newEvent;
        newEvent->prevEvent = NULL;
        newEvent->nextEvent = NULL;
    } else {
        if (compareEvent(newEvent, DEADLINE_QUEUE_HEAD) <= 0) {
            newEvent->nextEvent = DEADLINE_QUEUE_HEAD;
            DEADLINE_QUEUE_HEAD->prevEvent = newEvent;
            newEvent->prevEvent = NULL;
            DEADLINE_QUEUE_HEAD = newEvent;
        } else {
                        compareDeadline = DEADLINE_QUEUE_TAIL;
            while (compareEvent(newEvent, compareDeadline) < 0) {
                                compareDeadline = compareDeadline->prevEvent;
                if (compareDeadline == NULL) {
                    DBG(("compareDeadline == NULL!\r\n"));
                                }
            }
            newEvent->prevEvent = compareDeadline;
            newEvent->nextEvent = compareDeadline->nextEvent;
            compareDeadline->nextEvent = newEvent;
            if (compareDeadline != DEADLINE_QUEUE_TAIL) {
                newEvent->nextEvent->prevEvent = newEvent;
            } else {
                DEADLINE_QUEUE_TAIL = newEvent;
            }
        }
    }

        set_imask(0);
}
Пример #17
0
void usbModuleDisable(void)
{
	wait_ms(100);
	led_off();
	/* ==== Interrupt mask level change ==== */
	set_imask(15);				//(0x000000F0);

	/* USBコントローラディセーブル */
	INTC.IPR10.BIT._USB = 0;	/* Set USB interrupt level */
	USB.SYSCFG.WORD = 0x0481;	/* DPRUP off */
	wait_ms(30);
	USB.SYSCFG.WORD = 0x0401;	/* HSE off */
	wait_ms(30);
	USB.SYSCFG.WORD = 0x0400;	/* USB off */
	wait_ms(30);
	USB.SYSCFG.WORD = 0x0;		/* SCKE off */
	usb_reset_module();			/* USBモジュール リセット */

	wait_ms(1200);
	INTC.IBNR.WORD = 0x0000;	/* レジスタバングディセーブル */
	cache_disable();
}
void SH7216_INTERNAL_FLASH_Driver::Action_ExitPEMode(volatile CHIP_WORD BaseAddress)
{
    volatile unsigned char *flash_addr;

    // Go back to normal 'ROM/FLD' Read mode

    /* Check the FRDY bit in FSTATR0 */
    if( FSTATR0 & 0x80 )    // FRDY = 1?
    {
        /* Check if any errors exist */
        /* Check bits ILGLERR, PRGERR, and ERSERR (bits 6,5,4) in FSTATR0 */
        if( (FSTATR0 & 0xE0) == 0x00 )
        {
            // All good. Nothing left to check
        }
        else
        {
            
            if( (FSTATR0 & 0x40) )  // ILGLERR == 1?
            {
                if(FASTAT != 0x10)
                {
                       FASTAT = 0x10;
                }
            }
             
            /* Issue a status register clear command to clear all error bits */
            if( BaseAddress <= (CHIP_WORD )0x000FFFFF)
            {
                /* ROM */
                flash_addr = (unsigned char *)ROM_PE_ADDR;
                *flash_addr = 0x50;
            }
            else // ( current_mode == FLD_PE_MODE )
            {
                /* FLD */
                flash_addr = (unsigned char *)FLD_ADDRESS;
                *flash_addr = 0x50;
            }
        }
    }
    else
    {
        //  Wait for FRDY to be set?
    }

    /* Leave Program/Erase Mode */
    FENTRYR = 0xAA00;                   // Clear FENTRY0 & FENTRYD to 0

    /* When returning from Program/Erase Mode to Rom/FLD Read mode, you must do a dummy
       read of the 'FENTRYR' register after writing to it in order to guarantee the value
       gets transferred from the register buffer to the actual FCU internal register.
       Because 'FENTRYR' was defined as 'volatile', it will not get optimized out.*/
    FENTRYR;    // Dummy read after value written
    nop();      // This NOP is inserted in order to keep the SH compiler from re-ordering the 'FENTRYR;' instruction

    /* Restore the imask value (ROM PE Mode only) */
    if(BaseAddress <= (CHIP_WORD )0x000FFFFF)
    {
        set_imask(imask_value); // Restore the previous imask
    }

}
BOOL SH7216_INTERNAL_FLASH_Driver::Action_EnterPEMode(volatile CHIP_WORD BaseAddress)
{
    volatile unsigned char *flash_addr;
    BOOL result = TRUE;
    
    /* FENTRYR must be 0x0000 before bit FENTRY0 or FENTRYD can be set to 1 */
    if( FENTRYR != 0x0000)
    {
        FENTRYR = 0xAA00;
        FENTRYR;    // Dummy Read is needed to enter Read Mode
        nop();      // To keep compiler optimization form re-ordering
    }

    if( BaseAddress <= (CHIP_WORD)0x000FFFFF )
    {
        /* ROM */
        /* Disable Interrupts because the interrupt vector table will not be accessible */
        imask_value = get_imask();
        set_imask(0xF);

        FENTRYR = 0xAA01;   // Set FENTRY0 bit(Bit 0) and FKEY (B8-15 = 0xAA)
        flash_addr = (unsigned char *)ROM_PE_ADDR;
    }
    else 
    {
        /* FLD */
        FENTRYR = 0xAA80;   // Set FENTRYD bit(Bit 7) and FKEY (B8-15 = 0xAA)
        flash_addr = (unsigned char *)FLD_ADDRESS;

        // First clear the status of the FCU before doing FLD programming.
        // This is to clear out any previous errors that may have occured.
        // For example, if you attempt to read the Data Flash area 
        // before you make it readable using FlashFLDAreaAccess().
        /* Check if ILGERR (bit 6) is set */
        if( FSTATR0 & 0x40 )
        {
            if(FASTAT != 0x10)
            {
                FASTAT = 0x10;
            }
        }
        *flash_addr = 0x50;
    }

    /* Send the 'Normal mode transition' (0xFF) command 
       by writing to address 0x80800000 (or 0x80100000) */
    *flash_addr = 0xFF;

    /* Check 'ILGLERR' (bit 6) in 'Flash Status Register 0' (FSTATR0) */
    if( FSTATR0 & 0x40 )
    {
        /* Restore the imask value (ROM PE Mode only) */
        if( BaseAddress <= (CHIP_WORD )0x000FFFFF )
        {
            set_imask(imask_value); // Restore the previous imask
        }

        FENTRYR = 0xAA00;
        FENTRYR;    // Dummy Read is needed to enter Read Mode
        nop();      // To keep compiler optimization form re-ordering
        result = FALSE; // ERROR
    }

    return result;

}
Пример #20
0
Sint32 HW_Initialise( KMBPPMODE p_BPP, SYE_CBL *p_pCableType,
	PNATIVE_MEMORY_FREESTAT p_pMemoryFreeStat )
{
	KMDISPLAYMODE DisplayMode;

	switch( syCblCheck( ) )
	{
		case SYE_CBL_NTSC:
		{
			DisplayMode = KM_DSPMODE_NTSCNI640x480;

			break;
		}
		case SYE_CBL_PAL:
		{
			if( p_pCableType )
			{
				( *p_pCableType ) = SYE_CBL_PAL;
			}

			DisplayMode = KM_DSPMODE_PALNI640x480EXT;

			break;
		}
		case SYE_CBL_VGA:
		{
			DisplayMode = KM_DSPMODE_VGA;

			break;
		}
		default:
		{
			HW_Reboot( );
		}
	}

	set_imask( 15 );

	/* Initialise the CPU, G1 bus, interrupt controller, cache, and timer */
	syHwInit( );
	MEM_Initialise( p_pMemoryFreeStat );
	syStartGlobalConstructor( );
	kmInitDevice( KM_DREAMCAST );

	/* No antialiasing, dither if 16-BPP is enabled */
	kmSetDisplayMode( DisplayMode, p_BPP, KM_DITHER, KM_AAMODE );
	kmSetWaitVsyncCount( 1 );
	
	/* Initialise the interrupt controller and libraries required for after the
	 * graphics library is initialised */
	syHwInit2( );

	PER_Initialise( );

	/* Start the real-time clock */
	syRtcInit( );

	set_imask( 0 );

	if( FS_Initialise( ) != FS_OK )
	{
		LOG_Debug( "Failed to initialise the file system" );

		return HW_FATALERROR;
	}

	if( syCblCheck( ) == SYE_CBL_PAL )
	{
		kmSetPALEXTCallback( PALExtCallback, NULL );
		kmSetDisplayMode( DisplayMode, p_BPP, KM_DITHER, KM_AAMODE );
	}

	return HW_OK;
}
Пример #21
0
// 125kHzで割り込み
void CMT0_CMT_INT(void)
{
	static int pwmcounter;
	static int prescaler;
	
	int port, ch;
	
	CMT0Flag_Clear();

	for(port = 0; port < 2; port++)
	{
		for(ch = 0; ch < 8; ch++)
		{
			if(motor_status[port].isEnable_TCprotection & (1<<ch))
			{
				if(motor_status[port].deadtime_cnt[ch])
				{
					motor_status[port].deadtime_cnt[ch]--;
				}
				else
				{
					motor_status[port].dir_word |= DUTY_TO_DIR(motor_status[port].duty[ch])<<(ch*2);
					motor_status[port].duty[ch] = ABS_VAL(motor_status[port].duty[ch]);
				}
			}
			else	motor_status[port].duty[ch] = ABS_VAL(motor_status[port].duty[ch]);
		}
	}

	if(!pwmcounter)
	{
		PC.DR.WORD   = (PC.DR.WORD   & (~motor_status[0].isEnable_PWM)) |
					   (motor_status[0].dir_word & motor_status[0].isEnable_PWM);
		PD.DR.WORD.L = (PD.DR.WORD.L & (~motor_status[1].isEnable_PWM)) | 
					   (motor_status[1].dir_word & motor_status[1].isEnable_PWM);
	}
	else
	{
		if(motor_status[0].duty[0] == pwmcounter)	PC.DR.BYTE.L  &= 0xFC;
		if(motor_status[0].duty[1] == pwmcounter)	PC.DR.BYTE.L  &= 0xF3;
		if(motor_status[0].duty[2] == pwmcounter)	PC.DR.BYTE.L  &= 0xCF;
		if(motor_status[0].duty[3] == pwmcounter)	PC.DR.BYTE.L  &= 0x3F;
		if(motor_status[0].duty[4] == pwmcounter)	PC.DR.BYTE.H  &= 0xFC;
		if(motor_status[0].duty[5] == pwmcounter)	PC.DR.BYTE.H  &= 0xF3;
		if(motor_status[0].duty[6] == pwmcounter)	PC.DR.BYTE.H  &= 0xCF;
		if(motor_status[0].duty[7] == pwmcounter)	PC.DR.BYTE.H  &= 0x3F;
		if(motor_status[1].duty[0] == pwmcounter)	PD.DR.BYTE.LL &= 0xFC;
		if(motor_status[1].duty[1] == pwmcounter)	PD.DR.BYTE.LL &= 0xF3;
		if(motor_status[1].duty[2] == pwmcounter)	PD.DR.BYTE.LL &= 0xCF;
		if(motor_status[1].duty[3] == pwmcounter)	PD.DR.BYTE.LL &= 0x3F;
		if(motor_status[1].duty[4] == pwmcounter)	PD.DR.BYTE.LH &= 0xFC;
		if(motor_status[1].duty[5] == pwmcounter)	PD.DR.BYTE.LH &= 0xF3;
		if(motor_status[1].duty[6] == pwmcounter)	PD.DR.BYTE.LH &= 0xCF;
		if(motor_status[1].duty[7] == pwmcounter)	PD.DR.BYTE.LH &= 0x3F;
	}
	
	/* 1msに1回割り込まれる */
	if(!prescaler)
	{
		systemTimer_ms++;
		if(timingDelay_ms)	timingDelay_ms--;
	}
	
	if(++pwmcounter	== 100)	pwmcounter = 0;
	if(++prescaler	== 125)	prescaler  = 0;
	
	set_imask(0);
}
Пример #22
0
int main( void )
{
	int DisplayMode = 0;
	int Running = 1;
	const PDS_PERIPHERAL	*pControllerA;
	const PDS_PERIPHERALINFO	*pControllerAInfo;
	KMSYSTEMCONFIGSTRUCT	KamuiSystemConfig;
	PKMSURFACEDESC			FramebufferSurfaces[ 2 ];
	KMSURFACEDESC			FrontBuffer;
	KMSURFACEDESC			BackBuffer;
	KMSURFACEDESC			TextureSurface;
	KMVERTEXBUFFDESC		VertexBufferDesc;
	PKMDWORD				pVertexBuffer;
	SYCHAIN					UserVSyncChainID;

	/* Initialise hardware */
	set_imask( 15 );
	syHwInit( );
	syMallocInit( HEAP_AREA, HEAP_SIZE );
	syStartGlobalConstructor( );
	kmInitDevice( KM_DREAMCAST );

	switch( syCblCheck( ) )
	{
	case SYE_CBL_NTSC:
		DisplayMode = KM_DSPMODE_NTSCNI640x480;
		break;
	case SYE_CBL_PAL:
		DisplayMode = KM_DSPMODE_PALNI640x480EXT;
		break;
	case SYE_CBL_VGA:
		DisplayMode = KM_DSPMODE_VGA;
		break;
	default:
		syBtExit( );
	}
	kmSetDisplayMode( DisplayMode, KM_DSPBPP_RGB565, TRUE, FALSE );
	kmSetWaitVsyncCount( 1 );
	syHwInit2( );
	pdInitPeripheral( PDD_PLOGIC_ACTIVE, g_MapleRecvBuffer,
		g_MapleSendBuffer );
	syRtcInit( );
	set_imask( 0 );

	/* Set up MallocPtr and FreePtr to allocate memory aligned to a 32-byte
	 * boundary */
	Initialise32Malloc( );

	/* Testing output */
	DebugOut( "Anniversary" );

	/* Control what happens when V-Sync is triggered */
	UserVSyncChainID = syChainAddHandler( SYD_CHAIN_EVENT_IML6_VBLANK,
		VSyncCallback, VSYNC_PRIORITY, NULL );

	kmSetEORCallback( EORCallback, NULL );

	/* Set up Kamui 2 */
	KamuiSystemConfig.dwSize = sizeof( KamuiSystemConfig );

	/* Rendering flags */
	KamuiSystemConfig.flags = KM_CONFIGFLAG_ENABLE_CLEAR_FRAMEBUFFER |
		KM_CONFIGFLAG_NOWAITVSYNC | KM_CONFIGFLAG_ENABLE_2V_LATENCY;

	/* Double-buffer setup */
	FramebufferSurfaces[ 0 ] = &FrontBuffer;
	FramebufferSurfaces[ 1 ] = &BackBuffer;

	KamuiSystemConfig.ppSurfaceDescArray = FramebufferSurfaces;
	KamuiSystemConfig.fb.nNumOfFrameBuffer = 2;
	KamuiSystemConfig.fb.nStripBufferHeight = 32;

	/* Texture memory configuration */
	KamuiSystemConfig.nTextureMemorySize = TEXTURE_MEMORY_SIZE;
	KamuiSystemConfig.nNumOfTextureStruct = MAX_TEXTURES;
	KamuiSystemConfig.nNumOfSmallVQStruct = MAX_SMALLVQ;
	KamuiSystemConfig.pTextureWork = g_pTextureWorkArea;

	/* Vertex buffer allocation */
	pVertexBuffer = ( PKMDWORD )Align32Malloc( VERTEX_BUFFER_SIZE );
	KamuiSystemConfig.pVertexBuffer =
		( PKMDWORD )SH4_P2NonCachedMemory( pVertexBuffer );
	
	KamuiSystemConfig.pBufferDesc = &VertexBufferDesc;
	KamuiSystemConfig.nVertexBufferSize = VERTEX_BUFFER_SIZE;
	/* 2V latency only requires one vertex bank, 3V needs it double-buffered */
	KamuiSystemConfig.nNumOfVertexBank = 1;

	/* Only one rendering pass is used */
	KamuiSystemConfig.nPassDepth = 1;
	/* Autosort translucent polygons for rendering */
	KamuiSystemConfig.Pass[ 0 ].dwRegionArrayFlag = KM_PASSINFO_AUTOSORT;

	/* 2V allows one buffer to be directly transferred, 0 (Opaque polygons)
	 * are the most common, so send them directly */
	KamuiSystemConfig.Pass[ 0 ].nDirectTransferList = KM_OPAQUE_POLYGON;

	/* As the opaque polygons are already being sent directly, set their usage
	 * to zero
	 * All of these percentages must add up to 100.0f */
	KamuiSystemConfig.Pass[ 0 ].fBufferSize[ 0 ] = 0.0f; /* Opaque polygon*/
	KamuiSystemConfig.Pass[ 0 ].fBufferSize[ 1 ] = 0.0f; /* Opaque modifier */
	KamuiSystemConfig.Pass[ 0 ].fBufferSize[ 2 ] = 50.0f; /* Translucent */
	KamuiSystemConfig.Pass[ 0 ].fBufferSize[ 3 ] = 0.0f; /* Translucent
															modifier */
	KamuiSystemConfig.Pass[ 0 ].fBufferSize[ 4 ] = 50.0f; /* Punchthrough */

	/* Finally, set the Kamui 2 configuration */
	kmSetSystemConfiguration( &KamuiSystemConfig );

	/* Create a strip head for type 01 */
	memset( &g_StripHead01, 0, sizeof( g_StripHead01 ) );
	kmGenerateStripHead01( &g_StripHead01, &g_DefaultContext );

	/* Make an initial call to the EOR function to set the background plane */
	EORCallback( NULL );

	while( Running )
	{
		/* Get the latest data from controller port A and quit if the Start
		 * button is pressed */
		pControllerA = pdGetPeripheral( PDD_PORT_A0 );

		if( pControllerA->press & PDD_DGT_ST )
		{
			Running = 0;
		}

		/* Pump the renderer */
		kmBeginScene( &KamuiSystemConfig );
		kmBeginPass( &VertexBufferDesc );
		kmEndPass( &VertexBufferDesc );
		kmRender( KM_RENDER_FLIP );
		kmEndScene( &KamuiSystemConfig );

		/* Update input */
		pdExecPeripheralServer( );
	}

	/* Uninstall the V-Sync function */
	syChainDeleteHandler( UserVSyncChainID );

	/* Clean up the hardware */
	syRtcFinish( );
	pdExitPeripheral( );
	kmUnloadDevice( );
	syStartGlobalDestructor( );
	syMallocFinish( );
	syHwFinish( );
	set_imask( 15 );

	/* Reboot into the firmware */
	syBtExit( );
	
	/* This will never be reached */
	return 0;
}