TwlIPL_commit-99/build/libraries/gcd/common/gcd.c
2023-12-16 15:41:34 -05:00

1216 lines
35 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*---------------------------------------------------------------------------*
Project: TwlBrom - GCD - libraries
File: gcd.c
Copyright 2007 Nintendo. All rights reserved.
These coded instructions, statements, and computer programs contain
proprietary information of Nintendo of America Inc. and/or Nintendo
Company Ltd., and are protected by Federal copyright law. They may
not be disclosed to third parties or copied or duplicated in any form,
in whole or in part, without the prior written consent of Nintendo.
$Log: $
$NoKeywords: $
*---------------------------------------------------------------------------*/
#include <firm/gcd.h>
#include <firm/mi.h>
// use this functions for DS mode only
//#define PRINT_DEBUG
#ifdef PRINT_DEBUG
#define DBG_PRINTF vlink_dos_printf
#define DBG_CHAR vlink_dos_put_console
#else
#define DBG_PRINTF( ... ) ((void)0)
#define DBG_CHAR( c ) ((void)0)
#endif
static BOOL GCDi_ReadRomPreCore( GCDSlot slot, u32 romp, void *ramp, s32 size );
static void GCDi_ReadGameModeRomCore( GCDSlot slot, u32 romp, void *ramp, s32 size, GCDRomCtrls *ctrls );
static void GCDi_WriteGameModeRomCore( GCDSlot slot, u32 romp, void *ramp, s32 size, GCDRomCtrls *ctrls );
static void GCD_DmaRecvRomAsync( GCDSlot slot, u32 dmaNo, void *dest );
static void GCD_DmaSendRomAsync( GCDSlot slot, u32 dmaNo, void *src );
u32 GCDi_HeaderBuf[2][ GCD_ROM_HEADER_SIZE/sizeof(u32) ];
u32 GCDi_SecureAreaBuf[2][ GCD_SECURE_AREA_SIZE/sizeof(u32) ];
u32 GCDi_Secure2AreaBuf[2][ GCD_SECURE_AREA_SIZE/sizeof(u32) ];
GCDSharedWork GCDi_SharedWork[2];
GCDSecureWork GCDi_SecureWork[2];
/*---------------------------------------------------------------------------*
Name: GCDi_Enable
Description: enable game card master control
Arguments: None
Returns: None
*---------------------------------------------------------------------------*/
void GCDi_Enable( GCDSlot slot )
{
REGType16v* cnt0 = GCDi_SelectRegAddr( slot, REG_MCCNT0_ADDR );
OSIntrMode enabled = OS_DisableInterrupts();
GCDi_WaitCtrl( slot );
*cnt0 |= REG_MI_MCCNT0_A_E_MASK | REG_MI_MCCNT0_A_I_MASK;
(void)OS_RestoreInterrupts(enabled);
}
/*---------------------------------------------------------------------------*
Name: GCDi_Disable
Description: disable game card master control
Arguments: None
Returns: None
*---------------------------------------------------------------------------*/
void GCDi_Disable( GCDSlot slot )
{
REGType16v* cnt0 = GCDi_SelectRegAddr( slot, REG_MCCNT0_ADDR );
OSIntrMode enabled = OS_DisableInterrupts();
GCDi_WaitCtrl( slot );
*cnt0 &= ~(REG_MI_MCCNT0_A_E_MASK | REG_MI_MCCNT0_A_I_MASK);
(void)OS_RestoreInterrupts(enabled);
}
/*---------------------------------------------------------------------------*
Name: GCDi_SelectRom
Description: select game card rom
Arguments: None
Returns: None
*---------------------------------------------------------------------------*/
void GCDi_SelectRom( GCDSlot slot )
{
REGType16v* cnt0 = GCDi_SelectRegAddr( slot, REG_MCCNT0_ADDR );
OSIntrMode enabled = OS_DisableInterrupts();
*cnt0 &= ~REG_MI_MCCNT0_A_SEL_MASK;
(void)OS_RestoreInterrupts(enabled);
}
/*---------------------------------------------------------------------------*
Name: GCDi_SelectSpi
Description: select game card spi
Arguments: None
Returns: None
*---------------------------------------------------------------------------*/
void GCDi_SelectSpi( GCDSlot slot )
{
REGType16v* cnt0 = GCDi_SelectRegAddr( slot, REG_MCCNT0_ADDR );
OSIntrMode enabled = OS_DisableInterrupts();
*cnt0 |= REG_MI_MCCNT0_A_SEL_MASK;
(void)OS_RestoreInterrupts(enabled);
}
/*---------------------------------------------------------------------------*
Name: GCDi_GenCtrl
Description: generate game card control
Arguments: op : command
Returns: None
*---------------------------------------------------------------------------*/
void GCDi_GenCtrl( GCDCtrlRegs* regs,
GCDRw rw,
GCDPageCount pcount,
GCDClockType ckt, u32 lt1, u32 lt2,
BOOL cpn, BOOL dpn, BOOL csc, BOOL dsc )
{
regs->latency = ((lt1 << REG_MI_MCCNT1_A_L1_SHIFT) & REG_MI_MCCNT1_A_L1_MASK)
| ((lt2 << REG_MI_MCCNT1_A_L2_SHIFT) & REG_MI_MCCNT1_A_L2_MASK);
regs->ctrl = REG_MI_MCCNT1_A_START_MASK | REG_MI_MCCNT1_A_RESB_MASK
| rw
| pcount
| ckt
| ((lt1 << REG_MI_MCCNT1_A_L1_SHIFT) & REG_MI_MCCNT1_A_L1_MASK)
| ((lt2 << REG_MI_MCCNT1_A_L2_SHIFT) & REG_MI_MCCNT1_A_L2_MASK)
| ((cpn || dpn) ? (u32)REG_MI_MCCNT1_A_SE_MASK : 0)
| (csc ? REG_MI_MCCNT1_A_CSC_MASK : 0)
| (dsc ? REG_MI_MCCNT1_A_DS_MASK : 0);
#if 1
regs->scramble = (cpn || dpn) ? (u32)REG_MI_MCCNT1_A_SE_MASK : 0
| csc ? REG_MI_MCCNT1_A_CSC_MASK : 0
| dsc ? REG_MI_MCCNT1_A_DS_MASK : 0;
#endif
}
/*---------------------------------------------------------------------------*
Name: GCDi_SetCtrl
Description: set game card control
Arguments: op : command
Returns: None
*---------------------------------------------------------------------------*/
void GCDi_SetCtrl( GCDSlot slot, GCDCtrlRegs* regs )
{
REGType32v* cnt1 = GCDi_SelectRegAddr( slot, REG_MCCNT1_ADDR );
*cnt1 = regs->ctrl | regs->latency | regs->scramble;
}
/*---------------------------------------------------------------------------*
Name: GCDi_SetOp
Description: set game card command
Arguments: op : command
Returns: None
*---------------------------------------------------------------------------*/
void GCDi_SetOp( GCDSlot slot, GCDCmd64* op )
{
GCDi_SelectRom( slot );
{
REGType8v* cmd = GCDi_SelectRegAddr( slot, REG_MCCMD0_ADDR );
cmd[0] = op->b[7];
cmd[1] = op->b[6];
cmd[2] = op->b[5];
cmd[3] = op->b[4];
cmd[4] = op->b[3];
cmd[5] = op->b[2];
cmd[6] = op->b[1];
cmd[7] = op->b[0];
}
}
/*---------------------------------------------------------------------------*
Name: GCD_SendOnlyCardOpCore
Description: send only rom command
sync version
Arguments: ctrls : rom control
Returns: None
*---------------------------------------------------------------------------*/
void GCD_SendOnlyCardOpCore( GCDSlot slot, GCDRomCtrls *ctrls )
{
GCDi_WaitCtrl( slot );
GCDi_SetOp( slot, &ctrls->gcdOp );
GCDi_SetCtrl( slot, ctrls->gcdRegs );
}
/*---------------------------------------------------------------------------*
Name: GCD_ReadRomID
Description: read rom ID
sync version
Arguments: None
Returns: rom ID
*---------------------------------------------------------------------------*/
u32 GCD_ReadRomID( GCDSlot slot )
{
return GCD_ReadGameModeID( slot );
}
/*---------------------------------------------------------------------------*
Name: GCD_ReadGameModeID
Description: read rom ID on game mode
sync version
Arguments: None
Returns: None
*---------------------------------------------------------------------------*/
u32 GCD_ReadGameModeID( GCDSlot slot )
{
GCDRomCtrls *ctrls = &GCDi_Work[slot].ctrls;
u32 romID = 0;
u16 id = (u16)OS_GetLockID();
if ( !GCD_IsExisting( slot ) )
{
return romID;
}
if ( slot == GCD_PRIMARY_SLOT )
{
OS_LockCard( id );
}
else
{
OS_LockExCard( id );
}
ctrls->gcdRegs = &ctrls->gIDRegs;
ctrls->gcdOp.dw = GCDOP_G_OP_RD_ROM_ID;
romID = GCDi_ReadRomIDCore( slot, ctrls );
if ( slot == GCD_PRIMARY_SLOT )
{
OS_UnlockCard( id );
}
else
{
OS_UnlockExCard( id );
}
OS_ReleaseLockID( id );
return romID;
}
/*---------------------------------------------------------------------------*
Name: GCDi_ReadRomIDCore
Description: read rom ID
sync version
Arguments: ctrls : rom control
Returns: None
*---------------------------------------------------------------------------*/
u32 GCDi_ReadRomIDCore( GCDSlot slot, GCDRomCtrls *ctrls )
{
REGType32v* data1 = GCDi_SelectRegAddr( slot, REG_MCD1_ADDR );
GCDi_WaitCtrl( slot );
GCDi_SetOp( slot, &ctrls->gcdOp );
GCDi_SetCtrl( slot, ctrls->gcdRegs );
GCDi_WaitData( slot );
return *data1;
}
/*---------------------------------------------------------------------------*
Name: GCD_ReadRom
Description: read rom data
sync version
Arguments: romp : rom offset
ramp : ram destination address
size : size (byte)
Returns: None
*---------------------------------------------------------------------------*/
void GCD_ReadRom( GCDSlot slot, u32 romp, void *ramp, s32 size )
{
GCDWork *gw = &GCDi_Work[slot];
u16 id;
if ( !GCD_IsExisting( slot ) )
{
return;
}
id = (u16)OS_GetLockID();
if ( slot == GCD_PRIMARY_SLOT )
{
OS_LockCard( id );
}
else
{
OS_LockExCard( id );
}
if ( GCDi_ReadRomPreCore( slot, romp, ramp, size ) )
{
GCD_ReadGameModeRom( slot, gw->romp, gw->ramp, gw->restSize );
}
if ( slot == GCD_PRIMARY_SLOT )
{
OS_UnlockCard( id );
}
else
{
OS_UnlockExCard( id );
}
OS_ReleaseLockID( id );
}
/*---------------------------------------------------------------------------*
Name: GCD_ReadRomAsync
Description: read rom data
async version
Arguments: romp : rom offset
ramp : ram destination address
size : size (byte)
Returns: None
*---------------------------------------------------------------------------*/
void GCD_ReadRomAsync( GCDSlot slot, u32 romp, void *ramp, s32 size )
{
GCDWork *gw = &GCDi_Work[slot];
if ( GCDi_ReadRomPreCore( slot, romp, ramp, size ) )
{
GCD_ReadGameModeRomAsync( slot, gw->romp, gw->ramp, gw->restSize );
}
}
/*---------------------------------------------------------------------------*
Name: GCDi_ReadRomPreCore
Description: read rom data
sync version
Arguments: romp : rom offset
ramp : ram destination address
size : size (byte)
Returns: None
*---------------------------------------------------------------------------*/
static BOOL GCDi_ReadRomPreCore( GCDSlot slot, u32 romp, void *ramp, s32 size )
{
BOOL game_area = GCDi_ReadRomCommonPreCore( slot, romp, ramp, size );
{
GCDWork *gw = &GCDi_Work[slot];
romp = gw->romp;
ramp = gw->ramp;
size = gw->restSize;
}
return game_area;
}
BOOL GCDi_ReadRomCommonPreCore( GCDSlot slot, u32 romp, void *ram, s32 size )
{
GCDRomHeader *rh = GCDi_GetRomHeaderAddr( slot );
u32 romEndp = romp + size;
u32 secure2 = (u32)rh->l.twlAreaOffset * GCD_TWL_AREA_ALIGN + GCD_SECURE2_AREA_OFFSET;
u32 game2 = secure2 + GCD_SECURE2_AREA_SIZE;
u8 *ramp = ram;
// header
if ( romp < GCD_ROM_HEADER_SIZE
&& size > 0 )
{
s32 otherSize = (s32)romEndp - GCD_ROM_HEADER_SIZE;
s32 hdrSize = size;
if ( otherSize > 0 )
{
hdrSize -= otherSize;
}
MI_CpuCopyFast( &GCDi_HeaderBuf[slot][romp/4], ramp, (u32)hdrSize );
romp += hdrSize;
ramp += hdrSize;
size -= hdrSize;
}
// pad
if ( romp >= GCD_ROM_HEADER_SIZE && romp < GCD_SECURE_AREA_OFFSET
&& size > 0 )
{
s32 otherSize = (s32)romEndp - (GCD_SECURE_AREA_OFFSET - GCD_ROM_HEADER_SIZE);
s32 padSize = size;
if ( otherSize > 0 )
{
padSize -= otherSize;
}
MI_CpuClearFast( ramp, (u32)padSize );
romp += padSize;
ramp += padSize;
size -= padSize;
}
//secure
if ( romp >= GCD_SECURE_AREA_OFFSET && romp < GCD_GAME_AREA_OFFSET
&& size > 0 )
{
s32 gameSize = (s32)romEndp - GCD_GAME_AREA_OFFSET;
s32 secureSize = size;
if ( gameSize > 0 )
{
secureSize -= gameSize;
}
MI_CpuCopyFast( &GCDi_SecureAreaBuf[slot][(romp - GCD_SECURE_AREA_OFFSET)/4], ramp, (u32)secureSize );
romp += secureSize;
ramp += secureSize;
size -= secureSize;
}
//secure2
if ( rh->l.twlAreaOffset
&& romp >= secure2 && romp < game2
&& size > 0 )
{
s32 game2Size = (s32)(romEndp - game2);
s32 secure2Size = size;
if ( game2Size > 0 )
{
secure2Size -= game2Size;
}
MI_CpuCopyFast( &GCDi_Secure2AreaBuf[slot][(romp - secure2)/4], ramp, (u32)secure2Size );
romp += secure2Size;
ramp += secure2Size;
size -= secure2Size;
}
GCD_WaitRomAsync( slot );
{
GCDWork *gw = &GCDi_Work[slot];
gw->romp = romp;
gw->ramp = ramp;
gw->restSize = size;
}
// game
if ( romp >= GCD_GAME_AREA_OFFSET
&& size > 0 )
{
return TRUE;
}
return FALSE;
}
/*---------------------------------------------------------------------------*
Name: GCD_ReadNormalModeRom
Description: read rom data on normal mode
sync version
Arguments: romp : rom offset
ramp : ram destination address
size : size (byte)
Returns: None
*---------------------------------------------------------------------------*/
void GCD_ReadNormalModeRom( GCDSlot slot, u32 romp, void *ramp, s32 size )
{
GCDRomCtrls *ctrls = &GCDi_Work[slot].ctrls;
s32 restSize = size;
s32 oneShotSize;
ctrls->gcdRegs = &ctrls->nReadRomRegs;
oneShotSize = GCDi_GetOneShotSizeFromCtrl( ctrls->gcdRegs->ctrl );
if ( GCDi_SharedWork[slot].nCardID & GCD_ROMID_1TROM_MASK )
{
// 3D<33><44><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>p<EFBFBD>ݒ<EFBFBD>
{
ctrls->gcdRegs->ctrl &= ~REG_MI_MCCNT1_A_PC_MASK;
ctrls->gcdRegs->ctrl |= GCD_PAGE_1;
}
}
while ( restSize > 0 ) // <20>u<EFBFBD><75><EFBFBD>b<EFBFBD>N<EFBFBD><4E><EFBFBD><EFBFBD><EFBFBD>ǂݍ<C782><DD8D><EFBFBD>
{
GCDi_ReadNormalModeRomCore( slot, romp, ramp, oneShotSize, ctrls );
romp += oneShotSize;
*(u8 **)&ramp += oneShotSize;
restSize -= oneShotSize;
}
GCDi_WaitDma( slot, ctrls->dmaNo );
}
/*---------------------------------------------------------------------------*
Name: GCDi_ReadNormalModeRomCore
Description: read rom data on game mode
async version
Arguments: romp : rom offset
ramp : ram destination address
size : size (byte)
Returns: None
*---------------------------------------------------------------------------*/
void GCDi_ReadNormalModeRomCore( GCDSlot slot, u32 romp, void *ramp, s32 size, GCDRomCtrls *ctrls )
{
ctrls->gcdOp.dw = GCDOP_N_OP_RD_PAGE
| ((u64 )(romp/GCD_ROM_PAGE_SIZE) << GCDOP_N_RD_PAGE_ADDR_SHIFT);
GCDi_ReadRomCore( slot, ramp, size, ctrls );
}
/*---------------------------------------------------------------------------*
Name: GCD_ReadGameModeRom
Description: read rom data on game mode
sync version
Arguments: romp : rom offset
ramp : ram destination address
size : size (byte)
Returns: None
*---------------------------------------------------------------------------*/
void GCD_ReadGameModeRom( GCDSlot slot, u32 romp, void *ramp, s32 size )
{
GCDRomCtrls *ctrls = &GCDi_Work[slot].ctrls;
s32 restSize = size;
s32 oneShotSize;
ctrls->gcdRegs = &ctrls->gReadRomRegs;
oneShotSize = GCDi_GetOneShotSizeFromCtrl( ctrls->gcdRegs->ctrl );
while ( restSize > 0 ) // <20>u<EFBFBD><75><EFBFBD>b<EFBFBD>N<EFBFBD><4E><EFBFBD><EFBFBD><EFBFBD>ǂݍ<C782><DD8D><EFBFBD>
{
GCDi_ReadGameModeRomCore( slot, romp, ramp, oneShotSize, ctrls );
romp += oneShotSize;
*(u8 **)&ramp += oneShotSize;
restSize -= oneShotSize;
}
GCDi_WaitDma( slot, ctrls->dmaNo );
}
/*---------------------------------------------------------------------------*
Name: GCDi_ReadGameModeRomCore
Description: read rom data on game mode
async version
Arguments: romp : rom offset
ramp : ram destination address
size : size (byte)
Returns: None
*---------------------------------------------------------------------------*/
static void GCDi_ReadGameModeRomCore( GCDSlot slot, u32 romp, void *ramp, s32 size, GCDRomCtrls *ctrls )
{
ctrls->gcdOp.dw = GCDOP_G_OP_RD_PAGE
| ((u64 )(romp/GCD_ROM_PAGE_SIZE) << GCDOP_G_RD_PAGE_ADDR_SHIFT);
GCDi_ReadRomCore( slot, ramp, size, ctrls );
}
/*---------------------------------------------------------------------------*
Name: GCDi_ReadRomCore
Description: read rom data on game mode
Arguments: romp : rom offset
ramp : ram destination address
size : size (byte)
Returns: None
*---------------------------------------------------------------------------*/
void GCDi_ReadRomCore( GCDSlot slot, void *ramp, s32 size, GCDRomCtrls *ctrls )
{
u32 dmaNo = ctrls->dmaNo;
REGType32v* cnt1 = GCDi_SelectRegAddr( slot, REG_MCCNT1_ADDR );
REGType32v* data1 = GCDi_SelectRegAddr( slot, REG_MCD1_ADDR );
if ( !GCD_IsExisting( slot ) )
{
return;
}
GCDi_WaitDma( slot, dmaNo );
GCDi_SetOp( slot, &ctrls->gcdOp ); // <20>R<EFBFBD>}<7D><><EFBFBD>h<EFBFBD>ݒ<EFBFBD>
if ( MI_EXDMA_CH_MIN <= dmaNo && dmaNo <= MI_EXDMA_CH_MAX )
{
GCD_DmaRecvRomAsync( slot, dmaNo, ramp );
GCDi_SetCtrl( slot, ctrls->gcdRegs ); // <20>R<EFBFBD><52><EFBFBD>g<EFBFBD><67><EFBFBD>[<5B><><EFBFBD>ݒ<EFBFBD> & DMA<4D>X<EFBFBD>^<5E>[<5B>g
}
else
{
void *ramEndp;
u32 ctrlTmp;
GCDi_SetCtrl( slot, ctrls->gcdRegs ); // <20>R<EFBFBD><52><EFBFBD>g<EFBFBD><67><EFBFBD>[<5B><><EFBFBD>ݒ<EFBFBD>
ramEndp = (u8 *)ramp + size; // <20>i<EFBFBD>[<5B>I<EFBFBD><49><EFBFBD>A<EFBFBD>h<EFBFBD><68><EFBFBD>X<EFBFBD>Z<EFBFBD>o
do { // CPU<50>ǂݍ<C782><DD8D><EFBFBD>
ctrlTmp = *cnt1;
if (ctrlTmp & REG_MI_MCCNT1_A_RDY_MASK) {
u32 dataTmp = *data1;
if (ramp < ramEndp)
{
*((vu32 *)ramp) = dataTmp; // <20>w<EFBFBD><77><EFBFBD>T<EFBFBD>C<EFBFBD>Y<EFBFBD>܂Ŋi<C58A>[<5B>i<EFBFBD><EFBFBD>f<EFBFBD>[<5B>^<5E>͓ǂݎ̂āj
(*(vu32 **)&ramp)++;
}
}
}
while (ctrlTmp & REG_MI_MCCNT1_A_START_MASK);
}
}
/*---------------------------------------------------------------------------*
Name: GCD_WriteGameModeRom
Description: write rom data on game mode
sync version
Arguments: romp : rom offset
ramp : ram destination address
size : size (byte)
Returns: None
*---------------------------------------------------------------------------*/
void GCD_WriteGameModeRom( GCDSlot slot, u32 romp, void *ramp, s32 size )
{
GCDRomCtrls *ctrls = &GCDi_Work[slot].ctrls;
s32 restSize = size;
s32 oneShotSize;
ctrls->gcdRegs = &ctrls->gWriteRomRegs;
oneShotSize = GCDi_GetOneShotSizeFromCtrl( ctrls->gcdRegs->ctrl );
while ( restSize > 0 ) // <20>u<EFBFBD><75><EFBFBD>b<EFBFBD>N<EFBFBD><4E><EFBFBD><EFBFBD><EFBFBD>ǂݍ<C782><DD8D><EFBFBD>
{
GCDi_WriteGameModeRomCore( slot, romp, ramp, oneShotSize, ctrls );
romp += oneShotSize;
*(u8 **)&ramp += oneShotSize;
restSize -= oneShotSize;
}
GCDi_WaitDma( slot, ctrls->dmaNo );
}
/*---------------------------------------------------------------------------*
Name: GCDi_WriteGameModeRomCore
Description: write rom data on game mode
async version
Arguments: romp : rom offset
ramp : ram destination address
size : size (byte)
Returns: None
*---------------------------------------------------------------------------*/
static void GCDi_WriteGameModeRomCore( GCDSlot slot, u32 romp, void *ramp, s32 size, GCDRomCtrls *ctrls )
{
ctrls->gcdOp.dw = GCDOP_G_OP_WR_PAGE
| ((u64 )(romp/GCD_ROM_PAGE_SIZE) << GCDOP_G_RD_PAGE_ADDR_SHIFT);
GCDi_WriteRomCore( slot, ramp, size, ctrls );
}
/*---------------------------------------------------------------------------*
Name: GCDi_WriteRomCore
Description: write rom data on game mode
Arguments: romp : rom offset
ramp : ram destination address
size : size (byte)
Returns: None
*---------------------------------------------------------------------------*/
void GCDi_WriteRomCore( GCDSlot slot, void *ramp, s32 size, GCDRomCtrls *ctrls )
{
u32 dmaNo = ctrls->dmaNo;
REGType32v* cnt1 = GCDi_SelectRegAddr( slot, REG_MCCNT1_ADDR );
REGType32v* data1 = GCDi_SelectRegAddr( slot, REG_MCD1_ADDR );
// OS_TPrintf( "\nwrite size = %#x\n\n", size );
GCDi_WaitDma( slot, dmaNo );
GCDi_SetOp( slot, &ctrls->gcdOp ); // <20>R<EFBFBD>}<7D><><EFBFBD>h<EFBFBD>ݒ<EFBFBD>
if ( MI_EXDMA_CH_MIN <= dmaNo && dmaNo <= MI_EXDMA_CH_MAX )
{
GCD_DmaSendRomAsync( slot, dmaNo, ramp );
GCDi_SetCtrl( slot, ctrls->gcdRegs ); // <20>R<EFBFBD><52><EFBFBD>g<EFBFBD><67><EFBFBD>[<5B><><EFBFBD>ݒ<EFBFBD> & DMA<4D>X<EFBFBD>^<5E>[<5B>g
}
else
{
void *ramEndp;
u32 ctrlTmp;
GCDi_SetCtrl( slot, ctrls->gcdRegs ); // <20>R<EFBFBD><52><EFBFBD>g<EFBFBD><67><EFBFBD>[<5B><><EFBFBD>ݒ<EFBFBD>
ramEndp = (u8 *)ramp + size; // <20>i<EFBFBD>[<5B>I<EFBFBD><49><EFBFBD>A<EFBFBD>h<EFBFBD><68><EFBFBD>X<EFBFBD>Z<EFBFBD>o
do { // CPU<50>ǂݍ<C782><DD8D><EFBFBD>
ctrlTmp = *cnt1;
if (ctrlTmp & REG_MI_MCCNT1_A_RDY_MASK) {
u32 dataTmp = 0;
if (ramp < ramEndp)
{
dataTmp = *((vu32 *)ramp);
(*(vu32 **)&ramp)++;
}
*data1 = dataTmp;
}
}
while (ctrlTmp & REG_MI_MCCNT1_A_START_MASK);
}
}
/*---------------------------------------------------------------------------*
Name: GCD_DmaRecvRomAsync
Description: receive data with DMA
async version
Arguments: dmaNo : DMA channel No.
dest : destination address
size : size (byte)
Returns: None
*---------------------------------------------------------------------------*/
static void GCD_DmaRecvRomAsync( GCDSlot slot, u32 dmaNo, void *dest )
{
const void* data1 = GCDi_SelectRegAddr( slot, REG_MCD1_ADDR );
u32 timing = MI_NDMA_TIMING_CARD_A;
u32 blockSize = MI_NDMA_BWORD_1;
u32 interval = 1;
u32 prescale = MI_NDMA_INTERVAL_PS_1;
if ( slot == GCD_SECONDARY_SLOT )
{
timing = MI_NDMA_TIMING_CARD_B;
}
MIi_ExDmaRecvAsyncCore(dmaNo, data1, dest, 4, 4,
blockSize, interval, prescale,
MI_NDMA_CONTINUOUS_ON, MI_NDMA_SRC_RELOAD_ENABLE, MI_NDMA_DEST_RELOAD_DISABLE,
timing);
}
/*---------------------------------------------------------------------------*
Name: GCD_DmaSendRomAsync
Description: receive data with DMA
async version
Arguments: dmaNo : DMA channel No.
dest : destination address
size : size (byte)
Returns: None
*---------------------------------------------------------------------------*/
static void GCD_DmaSendRomAsync( GCDSlot slot, u32 dmaNo, void *src )
{
const void* data1 = GCDi_SelectRegAddr( slot, REG_MCD1_ADDR );
u32 timing = MI_NDMA_TIMING_CARD_A;
u32 blockSize = MI_NDMA_BWORD_1;
u32 interval = 1;
u32 prescale = MI_NDMA_INTERVAL_PS_1;
if ( slot == GCD_SECONDARY_SLOT )
{
timing = MI_NDMA_TIMING_CARD_B;
}
MIi_ExDmaSendAsyncCore(dmaNo, src, (void*)REG_MCD1_ADDR, 4, 4,
blockSize, interval, prescale,
MI_NDMA_CONTINUOUS_ON, MI_NDMA_SRC_RELOAD_DISABLE, MI_NDMA_DEST_RELOAD_ENABLE,
timing);
}
/*---------------------------------------------------------------------------*
Name: GCDi_GetOneShotSizeFromCtrl
Description: get block size
Arguments: ctrl : rom control
Returns: None
*---------------------------------------------------------------------------*/
s32 GCDi_GetOneShotSizeFromCtrl( u32 ctrl )
{
s32 oneShotSize = 0;
u32 pages = (ctrl & REG_MI_MCCNT1_A_PC_MASK) >> REG_MI_MCCNT1_A_PC_SHIFT;
s32 pageSize = 512;
oneShotSize = pageSize << (pages - 1);
return oneShotSize;
}
/*---------------------------------------------------------------------------*
Name: GCD_ReadNormalModeRomAsync
Description: read rom data on normal mode
async version
Arguments: romp : rom offset
ramp : ram destination address
size : size (byte)
Returns: None
*---------------------------------------------------------------------------*/
void GCD_ReadNormalModeRomAsync( GCDSlot slot, u32 romp, void *ramp, s32 size )
{
GCDWork *gw = &GCDi_Work[slot];
GCDRomCtrls *ctrls = &gw->ctrls;
ctrls->gcdRegs = &ctrls->nReadRomRegs;
gw->funcp = GCDi_ReadNormalModeRomCore;
GCD_SetInterrupt( slot, romp, ramp, size, gw );
gw->funcp( slot, gw->romp, gw->ramp, gw->oneShotSize, ctrls );
}
/*---------------------------------------------------------------------------*
Name: GCD_ReadGameModeRomAsync
Description: read rom data on game mode
async version
Arguments: romp : rom offset
ramp : ram destination address
size : size (byte)
Returns: None
*---------------------------------------------------------------------------*/
void GCD_ReadGameModeRomAsync( GCDSlot slot, u32 romp, void *ramp, s32 size )
{
GCDWork *gw = &GCDi_Work[slot];
GCDRomCtrls *ctrls = &gw->ctrls;
ctrls->gcdRegs = &ctrls->gReadRomRegs;
gw->funcp = GCDi_ReadGameModeRomCore;
GCD_SetInterrupt( slot, romp, ramp, size, gw );
gw->funcp( slot, gw->romp, gw->ramp, gw->oneShotSize, ctrls );
}
/*---------------------------------------------------------------------------*
Name: GCD_WriteGameModeRomAsync
Description: write rom data on game mode
async version
Arguments: romp : rom offset
ramp : ram destination address
size : size (byte)
Returns: None
*---------------------------------------------------------------------------*/
void GCD_WriteGameModeRomAsync( GCDSlot slot, u32 romp, void *ramp, s32 size )
{
GCDWork *gw = &GCDi_Work[slot];
GCDRomCtrls *ctrls = &gw->ctrls;
ctrls->gcdRegs = &ctrls->gWriteRomRegs;
gw->funcp = GCDi_WriteGameModeRomCore;
GCD_SetInterrupt( slot, romp, ramp, size, gw );
gw->funcp( slot, gw->romp, gw->ramp, gw->oneShotSize, ctrls );
}
/*---------------------------------------------------------------------------*
Name: GCD_SetInterrupt
Description: set interrupt
Arguments: romp : rom offset
ramp : ram destination address
size : size (byte)
Returns: None
*---------------------------------------------------------------------------*/
void GCD_SetInterrupt( GCDSlot slot, u32 romp, void *ramp, s32 size, GCDWork *gw )
{
GCDRomCtrls *ctrls = &gw->ctrls;
u32 dmaNo = ctrls->dmaNo;
u32 mask = GCDi_SelectIrqMask( slot, OS_IE_CARD_DATA );
OSIrqFunction intr = GCDi_InterruptHandlerPRIME;
gw->romp = romp;
gw->ramp = ramp;
gw->restSize = size;
gw->oneShotSize = GCDi_GetOneShotSizeFromCtrl( ctrls->gcdRegs->ctrl );
if ( dmaNo < MI_EXDMA_CH_MIN || MI_EXDMA_CH_MAX < dmaNo )
{
ctrls->lastDmaNo = ctrls->dmaNo;
ctrls->dmaNo = GCD_DEFAULT_DMA_A_NO;
if ( slot == GCD_SECONDARY_SLOT )
{
ctrls->dmaNo = GCD_DEFAULT_DMA_B_NO;
}
}
GCDi_WaitDma( slot, dmaNo );
(void)OS_DisableInterrupts();
if ( slot )
{
intr = GCDi_InterruptHandlerSECOND;
}
OS_SetIrqFunction( mask, intr );
gw->isAsync = TRUE;
gw->intrDone = FALSE;
reg_OS_IF = mask;
reg_OS_IE |= mask;
(void)OS_EnableInterrupts();
(void)OS_EnableIrq();
}
/*---------------------------------------------------------------------------*
Name: GCDi_InterruptHandler
Description: interrupt handler
Arguments: None
Returns: None
*---------------------------------------------------------------------------*/
void GCDi_InterruptHandlerCommon( GCDSlot slot )
{
GCDWork *gw = &GCDi_Work[slot];
s32 oneShotSize = gw->oneShotSize;
// read block
gw->romp += oneShotSize;
gw->ramp += oneShotSize;
gw->restSize -= oneShotSize;
if (gw->restSize > 0) {
GCDRomCtrls *ctrls = &gw->ctrls;
gw->oneShotSize = GCDi_GetOneShotSizeFromCtrl( ctrls->gcdRegs->ctrl );
gw->funcp( slot, gw->romp, gw->ramp, oneShotSize, &gw->ctrls );
} else {
gw->intrDone = TRUE; // <20>J<EFBFBD>[<5B>h<EFBFBD><68><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̒ʒm
}
}
void GCDi_InterruptHandlerPRIME( void )
{
GCDi_InterruptHandlerCommon( GCD_PRIMARY_SLOT );
}
void GCDi_InterruptHandlerSECOND( void )
{
GCDi_InterruptHandlerCommon( GCD_SECONDARY_SLOT );
}
//================================================================================
// WAIT/STOP
//================================================================================
/*---------------------------------------------------------------------------*
Name: GCD_IsBusy
Description: check whether game card is busy or not
Arguments: None
Returns: TRUE if game card is busy, FALSE if not
*---------------------------------------------------------------------------*/
BOOL GCD_IsBusy( GCDSlot slot )
{
REGType32v* cnt1 = GCDi_SelectRegAddr( slot, REG_MCCNT1_ADDR );
return (BOOL)((*cnt1 & REG_MI_MCCNT1_A_START_MASK) >> REG_MI_MCCNT1_A_START_SHIFT);
}
/*---------------------------------------------------------------------------*
Name: GCD_IsDataReady
Description: check whether data is ready or not
Arguments: None
Returns: TRUE if game card is busy, FALSE if not
*---------------------------------------------------------------------------*/
BOOL GCD_IsDataReady( GCDSlot slot )
{
REGType32v* cnt1 = GCDi_SelectRegAddr( slot, REG_MCCNT1_ADDR );
return (BOOL)((*cnt1 & REG_MI_MCCNT1_A_RDY_MASK) >> REG_MI_MCCNT1_A_RDY_SHIFT);
}
/*---------------------------------------------------------------------------*
Name: GCD_Stop
Description: stop game card access
Arguments: None
Returns: None
*---------------------------------------------------------------------------*/
void GCD_Stop( GCDSlot slot )
{
REGType32v* cnt1 = GCDi_SelectRegAddr( slot, REG_MCCNT1_ADDR );
OSIntrMode enabled = OS_DisableInterrupts();
*cnt1 &= ~REG_MI_MCCNT1_A_START_MASK;
(void)OS_RestoreInterrupts(enabled);
}
/*---------------------------------------------------------------------------*
Name: GCDi_WaitCtrl
Description: wait while game card is busy
Arguments: None
Returns: None
*---------------------------------------------------------------------------*/
void GCDi_WaitCtrl( GCDSlot slot )
{
REGType32v* cnt1 = GCDi_SelectRegAddr( slot, REG_MCCNT1_ADDR );
while (*cnt1 & REG_MI_MCCNT1_A_START_MASK)
{
}
}
/*---------------------------------------------------------------------------*
Name: GCDi_WaitData
Description: wait until data is ready
Arguments: None
Returns: None
*---------------------------------------------------------------------------*/
void GCDi_WaitData( GCDSlot slot )
{
REGType32v* cnt1 = GCDi_SelectRegAddr( slot, REG_MCCNT1_ADDR );
while ( !(*cnt1 & REG_MI_MCCNT1_A_RDY_MASK) )
{
}
}
/*---------------------------------------------------------------------------*
Name: GCDi_WaitDma
Description: wait for stopping game card DMA
Arguments: dmaNo : DMA channel No.
Returns: None
*---------------------------------------------------------------------------*/
void GCDi_WaitDma( GCDSlot slot, u32 dmaNo )
{
GCDi_WaitCtrl( slot );
if ( MI_EXDMA_CH_MIN <= dmaNo && dmaNo <= MI_EXDMA_CH_MAX )
{
MIi_StopExDma( dmaNo );
}
}
/*---------------------------------------------------------------------------*
Name: GCDi_WaitInterrupt
Description: wait for game card interrupt
Arguments: None
Returns: None
*---------------------------------------------------------------------------*/
void GCDi_WaitInterrupt( GCDSlot slot )
{
GCDWork *gw = &GCDi_Work[slot];
if ( gw->isAsync )
{
while ( !gw->intrDone )
{
}
}
gw->intrDone = FALSE;
gw->isAsync = FALSE;
GCDi_WaitDma( slot, gw->ctrls.dmaNo );
}
/*---------------------------------------------------------------------------*
Name: GCD_WaitRomAsync
Description: wait for game card async access
Arguments: None
Returns: None
*---------------------------------------------------------------------------*/
void GCD_WaitRomAsync( GCDSlot slot )
{
GCDi_WaitInterrupt( slot );
{
GCDWork *gw = &GCDi_Work[slot];
GCDRomCtrls *ctrls = &gw->ctrls;
u32 mask = GCDi_SelectIrqMask( slot, OS_IE_CARD_DATA );
OSIntrMode enabled = OS_DisableInterrupts();
ctrls->dmaNo = ctrls->lastDmaNo;
#define IOP_DISABLE_OS_TIMER
#ifdef IOP_DISABLE_OS_TIMER
reg_OS_IE &= ~REG_OS_IE_T1_MASK;
#endif // IOP_DISABLE_OS_TIMER
reg_OS_IE &= ~mask; // disable card interrupt
(void)OS_RestoreInterrupts( enabled );
}
}