mirror of
https://github.com/emu-russia/pureikyubu.git
synced 2025-04-02 10:42:15 -04:00
480 lines
9.8 KiB
Text
480 lines
9.8 KiB
Text
typedef struct // 64 bytes
|
|
{
|
|
+0 - EXI callback
|
|
+4 - TC callback
|
|
+8 - EXT callback
|
|
+12
|
|
+16 - immediate length (used only for read imm)
|
|
+20 - immediate buffer (used only for read imm)
|
|
+24 - last locked device number
|
|
+28
|
|
+32
|
|
|
|
+36 - number of unlock callbacks
|
|
|
|
+40 dev \
|
|
+44 cb |
|
|
|
|
|
+48 dev | unlocked callbacks FIFO :
|
|
+52 cb | first goes device number,
|
|
| then callback address
|
|
+56 dev |
|
|
+60 cb /
|
|
} EXICHAN;
|
|
|
|
EXICHAN Ecb[3]; // 64 * 3 = 0xc0 bytes
|
|
|
|
// check for device, connected with specified chan
|
|
BOOL __EXIProbe(s32 chan)
|
|
{
|
|
BOOL level;
|
|
u32 status;
|
|
|
|
if(chan == 2) return 1;
|
|
|
|
level = OSDisableInterrupts();
|
|
|
|
r6 = 0xcc006800 + chan * 20; // EXI
|
|
status = EXI.status;
|
|
|
|
if(((u32)Ecb[chan][12] & 8) == 0)
|
|
{
|
|
if(status & 0x800)
|
|
{
|
|
EXI.status = (status & 0x07f5) | 0x0800;
|
|
(u32)Ecb[chan][32] = 0
|
|
0x800030c0 + chan * 4 = 0
|
|
}
|
|
|
|
if(status & bit19)
|
|
{
|
|
[0x800000f8] ..
|
|
.
|
|
.
|
|
OSGetTime()
|
|
div2i()
|
|
div2i()
|
|
|
|
[0x800030c0 + chan * 4] = 1
|
|
|
|
OSRestoreInterrupts(level);
|
|
return 0;
|
|
}
|
|
|
|
[0x80000020] = 0
|
|
[0x800030c0 + chan * 4] = 0
|
|
|
|
OSRestoreInterrupts(level);
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
if((status & bit19) == 0)
|
|
{
|
|
if(status & bit20)
|
|
{
|
|
[0x80000020] = 0
|
|
[0x800030c0 + chan * 4] = 0
|
|
|
|
OSRestoreInterrupts(level);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
OSRestoreInterrupts(level);
|
|
return 1;
|
|
}
|
|
|
|
BOOL EXIProbe(s32 chan)
|
|
{
|
|
char id[...];
|
|
|
|
if(__EXIProbe(chan))
|
|
{
|
|
if(Ecb[chan][32] == NULL)
|
|
{
|
|
if(EXIGetID(chan, 0, id)) return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// maybe incorrect
|
|
void SetExiInterruptMask(s32 chan, u32 *exi)
|
|
{
|
|
switch(chan)
|
|
{
|
|
case 0:
|
|
if(((*exi != 0) && (*exi[12] & 0x10)) || (Ecb[2][0] == 0))
|
|
{
|
|
__OSMaskInterrupts(0x00410000);
|
|
}
|
|
else
|
|
{
|
|
__OSUnmaskInterrupts(0x00410000);
|
|
}
|
|
break;
|
|
|
|
case 1:
|
|
if((*exi == 0) || (*exi[12] & 0x10))
|
|
{
|
|
__OSMaskInterrupts(0x00080000);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
__OSUnmaskInterrupts(0x00080000);
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
if(__OSGetInterruptHandler(25) && (*exi[12] & 0x10))
|
|
{
|
|
__OSMaskInterrupts(0x00400000);
|
|
}
|
|
else
|
|
{
|
|
__OSMaskInterrupts(0x00400000);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
void EXIInit()
|
|
{
|
|
// mask all EXI interrupts
|
|
__OSMaskInterrupts(0x007f8000);
|
|
|
|
[0xcc006800] = 0
|
|
[0xcc006814] = 0
|
|
[0xcc006828] = 0
|
|
|
|
[0xcc006800] = 0x2000
|
|
|
|
__OSSetInterruptHandler(9, EXIIntrruptHandler); // EXI0 EXI
|
|
__OSSetInterruptHandler(10, TCIntrruptHandler); // EXI0 TC
|
|
__OSSetInterruptHandler(11, EXTIntrruptHandler); // EXI0 EXT
|
|
__OSSetInterruptHandler(12, EXIIntrruptHandler); // EXI1 EXI
|
|
__OSSetInterruptHandler(14, EXTIntrruptHandler); // EXI1 EXT
|
|
__OSSetInterruptHandler(15, EXIIntrruptHandler); // EXI2 EXI
|
|
__OSSetInterruptHandler(16, TCIntrruptHandler); // EXI2 TC
|
|
|
|
if(OSGetConsoleType() & OS_CONSOLE_DEVELOPMENT)
|
|
{
|
|
(u32)[0x800030c0] = 0;
|
|
(u32)[0x800030c4] = 0;
|
|
|
|
(u32)Ecb[0].[32] = 0;
|
|
(u32)Ecb[1].[32] = 0;
|
|
|
|
__EXIProbe(0);
|
|
__EXIProbe(1);
|
|
}
|
|
}
|
|
|
|
int EXIDma(s32 chan, u32 *buf, s32 len, int type, void (*callback)())
|
|
{
|
|
BOOL level;
|
|
|
|
level = OSDisableInterrupts();
|
|
|
|
if(!(Ecb[chan][12] & 4) || (Ecb[chan][12] & 3))
|
|
{
|
|
OSRestoreInterrupts(level);
|
|
return 0;
|
|
}
|
|
|
|
if(Ecb[chan][4] = callback)
|
|
{
|
|
// unmask EXI TC interrupt
|
|
EXIClearInterrupts(chan, 0, 1, 0);
|
|
__OSUnmaskInterrupts(0x00200000 >> (chan * 3));
|
|
}
|
|
|
|
Ecb[chan][12] |= 1
|
|
|
|
r4 = 0xcc006800 + chan * 20; // EXI
|
|
EXI.dmabuf = buf & 0x03ffffe0;
|
|
EXI.dmalen = len;
|
|
EXI.control = (type << 2) | 3;
|
|
|
|
OSRestoreInterrupts(level)
|
|
return 1;
|
|
}
|
|
|
|
BOOL EXILock(s32 chan, s32 dev, void (*unlockedCallback)())
|
|
{
|
|
BOOL level = OSDisableInterrupts();
|
|
|
|
if(Ecb[chan][12] & 0x10)
|
|
{
|
|
// reinstall unlock callback
|
|
if(unlockedCallback)
|
|
{
|
|
for(i=0; i<Ecb[chan][36]; i++)
|
|
{
|
|
// already installed
|
|
if(Ecb[chan][40 + 8 * i] == dev)
|
|
{
|
|
OSRestoreInterrupts(level);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
Ecb[chan][44 + 8 * i] = unlockedCallback;
|
|
Ecb[chan][40 + 8 * i] = dev;
|
|
Ecb[chan][36]++;
|
|
}
|
|
|
|
OSRestoreInterrupts(level);
|
|
return 0;
|
|
}
|
|
|
|
SetExiInterruptMask(chan, &Ecb[chan]);
|
|
Ecb[chan][12] |= 0x10;
|
|
Ecb[chan][24] = dev;
|
|
|
|
OSRestoreInterrupts(level);
|
|
return 1;
|
|
}
|
|
|
|
BOOL EXIUnlock(s32 chan)
|
|
{
|
|
BOOL level = OSDisableInterrupts();
|
|
|
|
if(!(Ecb[chan][12] & 0x10))
|
|
{
|
|
OSRestoreInterrupts(level);
|
|
return 0;
|
|
}
|
|
|
|
Ecb[chan][12] &= ~0x10;
|
|
SetExiInterruptMask(chan, &Ecb[chan]);
|
|
|
|
// unlocked callbcak
|
|
if(Ecb[chan][36] > 0)
|
|
{
|
|
void (*callback)() = Ecb[chan][44];
|
|
|
|
if(--Ecb[chan][36])
|
|
{
|
|
memmove(&Ecb[chan][40], &Ecb[chan][48], Ecb[chan][36] * 8);
|
|
}
|
|
|
|
callback(chan, 0);
|
|
}
|
|
|
|
OSRestoreInterrupts(level);
|
|
return 1;
|
|
}
|
|
|
|
BOOL EXISelect(s32 chan, s32 dev, s32 freq)
|
|
{
|
|
BOOL level = OSDisableInterrupts();
|
|
|
|
// already selected ?
|
|
if(Ecb[chan][12] & 4)
|
|
{
|
|
OSRestoreInterrupts(level);
|
|
return 0;
|
|
}
|
|
|
|
if(chan != 2)
|
|
{
|
|
if(dev == 0)
|
|
{
|
|
if(!(Ecb[chan][12] & 8))
|
|
{
|
|
if(__EXIProbe(chan) == 0)
|
|
{
|
|
OSRestoreInterrupts(level);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// check locked flag
|
|
if(Ecb[chan][12] & 0x10)
|
|
{
|
|
OSRestoreInterrupts(level);
|
|
return 0;
|
|
}
|
|
|
|
// check for last locked device
|
|
if(Ecb[chan][24] != dev)
|
|
{
|
|
OSRestoreInterrupts(level);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// set selected flag
|
|
Ecb[chan][12] |= 4;
|
|
|
|
r5 = 0xcc006800 + chan * 20; // EXI
|
|
EXI.status = (EXI.status & 0x0405) | (0x80 << dev) | (freq << 4);
|
|
|
|
if(Ecb[chan][12] & 8)
|
|
{
|
|
switch(chan)
|
|
{
|
|
case 0:
|
|
__OSMaskInterrupts(0x00100000); // EXI0 EXT
|
|
break;
|
|
|
|
case 1:
|
|
__OSMaskInterrupts(0x00020000); // EXI1 EXT
|
|
break;
|
|
}
|
|
}
|
|
|
|
OSRestoreInterrupts(level);
|
|
return 1;
|
|
}
|
|
|
|
BOOL EXIDeselect(s32 chan)
|
|
{
|
|
BOOL level = OSDisableInterrupts();
|
|
u32 status;
|
|
|
|
// already deselected ?
|
|
if(!(Ecb[chan][12] & 4))
|
|
{
|
|
OSDisableInterrupts(level);
|
|
return 0;
|
|
}
|
|
|
|
// clear selected flag
|
|
Ecb[chan][12] &= ~4;
|
|
|
|
r3 = 0xcc006800 + chan * 20; // EXI
|
|
status = EXI.status;
|
|
EXI.status = status & 0x0405;
|
|
|
|
if(Ecb[chan][12] & 8)
|
|
{
|
|
switch(chan)
|
|
{
|
|
case 0:
|
|
__OSUnmaskInterrupts(0x00100000); // EXI0 EXT
|
|
break;
|
|
|
|
case 1:
|
|
__OSUnmaskInterrupts(0x00020000); // EXI1 EXT
|
|
break;
|
|
}
|
|
}
|
|
|
|
OSRestoreInterrupts(level);
|
|
|
|
if(chan != 2)
|
|
{
|
|
if(status & bit24)
|
|
{
|
|
if(__EXIProbe(chan) == 0) return 0;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
void EXIClearInterrupts(s32 chan, BOOL exi, BOOL tc, BOOL ext)
|
|
{
|
|
u32 status;
|
|
|
|
r7 = 0xcc006800 + chan * 20; // EXI
|
|
|
|
status = EXI.status & 0x07f5;
|
|
|
|
if(exi) status |= 2;
|
|
if(tc ) status |= 8;
|
|
if(ext) status |= 0x800;
|
|
|
|
EXI.status = status;
|
|
}
|
|
|
|
|
|
/// UNCOMPLETE STUFFFF !!!!!!!!!!!!!
|
|
|
|
|
|
u32 EXISync(s32 chan)
|
|
{
|
|
BOOL level;
|
|
|
|
r31 = &Ecb[chan]
|
|
r29 = 0xcc006800 + chan * 20;
|
|
|
|
do
|
|
{
|
|
if((Ecb[chan][12] & 1) == 0)
|
|
{
|
|
level = OSDisableInterrupts();
|
|
|
|
if((Ecb[chan][12] & 4) == 0)
|
|
{
|
|
OSRestoreInterrupts(level);
|
|
break;
|
|
}
|
|
|
|
if(if(Ecb[chan][12] & 3)
|
|
{
|
|
|
|
}
|
|
|
|
}
|
|
} while(Ecb[chan][12] & 4);
|
|
|
|
return 0;
|
|
}
|
|
|
|
00000640 <EXISync>:
|
|
|
|
|
|
BOOL EXIImm(s32 chan, u32 *buf, s32 len, BOOL type, void (*callback)())
|
|
{
|
|
BOOL level = OSDisableInterrupts();
|
|
s32 size;
|
|
|
|
r28 = chan
|
|
r29 = buf
|
|
r30 = len
|
|
r31 = type
|
|
r19 = callback
|
|
|
|
r27 = &Ecb[chan];
|
|
|
|
if(Ecb[chan][12] & 3)
|
|
{
|
|
OSRestoreInterrupts(level);
|
|
return 0;
|
|
}
|
|
|
|
if(Ecb[chan][4] = callback)
|
|
{
|
|
EXIClearInterrupts(chan, 0, 1, 0);
|
|
__OSUnmaskInterrupts(0x00200000 >> (chan * 3));
|
|
}
|
|
|
|
Ecb[chan][12] |= 2;
|
|
|
|
if(type)
|
|
{
|
|
}
|
|
else
|
|
{
|
|
Ecb[chan][20] = buf;
|
|
Ecb[chan][16] = (type) ? (0) : (len);
|
|
|
|
r3 = 0xcc006800 + chan * 20; // EXI
|
|
EXI.control = ((len - 1) << 4) | (type << 2) | 1;
|
|
|
|
OSRestoreInterrupts(level);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
<EXIImm>:
|