GameCube EXI Bus Specification

From gc-linux

Jump to: navigation, search

by Costis, 21 January 2004

In total, there are 15 EXI hardware registers. The EXI hardware register base is located at 0xCC006800 in virtual memory. There are 3 different EXI channels, each which can hold 3 different devices. Each channel has 5 hardware registers of its own, so with three channels, the total number is 15.

Contents

EXI Status Register Bit Description

(0xCC006800 + channel * 20)

18 19 20 21 22 23 24 25 26 27 28 29 30 31
D T  ?  ? S S S F F F C  ? E  ?
D Device Connected Bit (R)

Set to 0 if a device is not connected on the specific channel.

Set to 1 if a device is connected on the specific channel.

T EXT Interrupt Enable Bit (R\W)

Set this to 1 to enable the EXT interrupt.

Set this to 0 to disable the EXT interrupt.

SSS EXI Device Selection Bits (R\W)

Only one of these three bits can be set to signify which device number has been selected on a specific channel. Use this code to set a selected EXI device in the EXI Control Register:

*(unsigned long*)(EXI_BASE + channel * 20) |= (0x80 << device);
FFF EXI Channel Frequency Selection Bits (R\W)

These bits set the EXI channel frequency for a selected device. Valid values are from 0 to 5. Use this code to set a selected EXI device frequency in the EXI Control Register:

*(unsigned long*)(EXI_BASE + channel * 20) |= (freq << 4);
C TC Interrupt Enable Bit (R\W)

Set this to 1 to enable the TC interrupt.

Set this to 0 to disable the TC interrupt.

E EXI Interrupt Enable Bit (R\W)

Set this to 1 to enable the EXI interrupt.

Set this to 0 to disable the EXI interrupt.

EXI DMA Buffer Register Bit Description

(0xCC006804 + channel * 20)

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
0 0 0 0 0 0 x x x x x x x x x x x x x x x x x x x x x 0 0 0 0 0


000000xxxxxxxxxxxxxxxxxxxxx00000 Set this register to the DMA transfer buffer address in RAM for an EXI DMA operation.

Note : Only 21 bits of this address are valid (top 6 and low 5 should be set to 0). This means that the DMA transfer buffer address should be aligned to 32-bits. Use the following code to easily set the DMA transfer buffer address:

 *(unsigned long*)(EXI_BASE + EXI_DMABUF_OFFSET + channel * 20) = abuffer & 0x3FFFFE0;

EXI DMA Size Register Bit Description

(0xCC006808 + channel * 20)

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
0 0 0 0 0 0 x x x x x x x x x x x x x x x x x x x x x 0 0 0 0 0


000000xxxxxxxxxxxxxxxxxxxxx00000 Set this register to the DMA transfer size (bytes) for an EXI DMA operation.

Note : Just like the DMA Buffer Register, the DMA Transfer Register has 21 valid size bits (top 6 and low 5 bits should be set to 0). Therefore, the DMA transfer size must be a multiple of 32 bytes. Use the following code to set the DMA transfer size:

*(unsigned long*)(EXI_BASE + EXI_DMALEN_OFFSET + channel * 20) = asize & 0x3FFFFE0;

EXI DMA\IMM Control Register Bit Description

(0xCC00680C + channel * 20)

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
x x x x x x x x x x x x x x x x x x x x x x x x x x x x T T S E
xxxxxxxxxxxxxxxxxxxxxxxxxxxx IMM Operation Transfer Length (Set this only for IMM write operations.)

Note: The maximum size for this should be 4 bytes (1 - 4 are valid).

TT Transfer Type (0 - Read, 1 - Write)
S Transfer Selection (0 - IMM, 1 - DMA)
E Enable Bit (0 - Disable Transfer, 1 - Enable Transfer)

When an EXI DMA\IMM operation has been completed, the EXI Enable Bit will be reset to 0.

EXI IMM Data Register Bit Description

(0xCC006810 + channel * 20)

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x
xxxxxxxxxxxxxxxxxxxxxxxxxxxx IMM Operation Data (Set this only for IMM write operations and read it for IMM read operations).

Initializing the EXI Bus

Here is some code that will initialize the EXI bus:

void EXIInit (void)
{
    // Wait until any previously active EXI operations have been completed on all of the EXI channels.
    while (EXI_DMACNT0 & EXI_CONTROL_ENABLE);
    while (EXI_DMACNT1 & EXI_CONTROL_ENABLE);
    while (EXI_DMACNT2 & EXI_CONTROL_ENABLE);

    // Clear the EXI Status Register for all of the EXI channels.
    EXI_STATUS0 = 0;
    EXI_STATUS1 = 0;
    EXI_STATUS2 = 0;
}

Selecting a Specific EXI Device on an EXI Channel

Here is some code to select an EXI device on any EXI channel:

// Channel must be from 0 to 2.
// Device must be from 0 to 2.
// Frequency must be from 0 to 5 (normally use 0).
void EXISelect (unsigned long channel, unsigned long device, unsigned long frequency)
{
    // Mask out the previously set device and frequency bits and set the new ones.
    *(unsigned long*)(&EXI_STATUS0 + channel * 20) = (*(unsigned long*)(&EXI_STATUS0 + channel * 20) & 0x405) |
                                                    (0x80 << device) | (frequency << 4);
}

Deselecting EXI Devices on an EXI Channel

Here is some code to deselect all EXI devices on any EXI channel:

// Channel must be from 0 to 2.
void EXIDeselect (unsigned long channel)
{
    // Mask out the previously set device and frequency bits.
    *(unsigned long*)(&EXI_STATUS0 + channel * 20) &= 0x405;
}

Performing an IMM Operation on a EXI Device

Here is some code to perform an IMM operation on an EXI device:

#define EXI_CONTROL_TYPE_READ        0
#define EXI_CONTROL_TYPE_WRITE       1
#define EXI_CONTROL_IMM              0
#define EXI_CONTROL_DMA              2
#define EXI_CONTROL_ENABLE           1


// Channel must be from 0 to 2.
// Size must be from 1 to 4.
// Type must be either EXI_CONTROL_TYPE_READ or EXI_CONTROL_TYPE_WRITE.
void EXIImm (unsigned long channel, unsigned char *abuffer, unsigned long size, unsigned long type)
{
    int i;
    unsigned long IMMdat;

    if (type == EXI_CONTROL_TYPE_READ)
    {
        // EXI IMM Read Operation

*(unsigned long*)(&EXI_DMACNT0 + channel * 20) = EXI_CONTROL_ENABLE | EXI_CONTROL_IMM |

                                                                  (type << 2) | ((size - 1) << 4);

	// Wait until the EXI IMM operation has been completed.
	while (*(volatile unsigned long*)(&EXI_DMACNT0 + channel * 20) & EXI_CONTROL_ENABLE);

        // Copy the EXI IMM data read to the buffer passed.
        IMMdat = *(unsigned long*)(&EXI_IMMDAT0 + channel * 20);
        for (i = 0; i < size; i++)
            abuffer[i] = IMMdat >> ((3 - i) << 3);

        return;
    } else {
        // Copy the data from the buffer passed to the EXI IMM Data Register.
        IMMdat = 0;
        for (i = 0; i < size; i++)
            IMMdat |= abuffer[i] << ((3 - i) << 3);
        *(unsigned long*)(&EXI_IMMDAT0 + channel * 20) = IMMdat;

        // EXI IMM Write Operation
	*(unsigned long*)(&EXI_DMACNT0 + channel * 20) = EXI_CONTROL_ENABLE | EXI_CONTROL_IMM | 
                                                        (type << 2) | ((size - 1) << 4);
	// Wait until the EXI IMM operation has been completed.
	while (*(volatile unsigned long*)(&EXI_DMACNT0 + channel * 20) & EXI_CONTROL_ENABLE);

        return;
    }
}

Performing a DMA Operation on a EXI Device

Here is some code to perform an DMA operation on an EXI device:

Use the defines previously shown above for the IMM operations.

// Channel must be from 0 to 2.
// Buffer must be aligned to a 32-bit offset.
// Size must be a multiple of 32 bytes.
// Type must be either EXI_CONTROL_TYPE_READ or EXI_CONTROL_TYPE_WRITE.
void EXIDma (unsigned long channel, unsigned char *abuffer, unsigned long size,  unsigned long type)
{
    // EXI DMA Operation
    *(unsigned long*)(&EXI_DMABUF0 + channel * 20) = (unsigned long)abuffer & 0x3FFFFE0;
    *(unsigned long*)(&EXI_DMALEN0 + channel * 20) = size & 0x3FFFFE0;
    *(unsigned long*)(&EXI_DMACNT0 + channel * 20) = EXI_CONTROL_ENABLE | EXI_CONTROL_DMA | (type << 2);
    // Wait until the EXI DMA operation has been completed.
    while (*(volatile unsigned long*)(&EXI_DMACNT0 + channel * 20) & EXI_CONTROL_ENABLE);
    return;
}

Retrieving the ID of an EXI Device

To retrieve the ID of an EXI Device, an EXI IMM write operation must be used to send the ID command (0x0000) and an EXI IMM read operation should follow it to read the actual 4 byte ID. Here is some code to retrieve the ID of an EXI device:

unsigned long EXIRetrieveID (unsigned long channel, unsigned long device)
{
    unsigned long tID;

    // Select the specified EXI channel and device.
    EXISelect (channel, device, 0);

    // Send the EXI ID command (0x0000)
    tID = 0;
    EXIImm (channel, &tID, 2, EXI_CONTROL_TYPE_WRITE);

    // Read the actual ID data (4 bytes)
    EXIImm (channel, &tID, 4, EXI_CONTROL_TYPE_READ);

    return tID;
}

EXI Channel and Device List

The folllowing table shows the GameCube devices which use the EXI bus and their channel and device numbers:

Description Channel Device
Memory Card (Slot A) 0 0
Memory Card (Slot B) 1 0
Serial Port 1 0 2
Serial Port 2 2 0
Real-Time Clock (RTC) 0 1
SRAM 0 1
Mask ROM 0 1

Note : The Real-Time Clock (RTC), SRAM, and Mask ROM are actually one device mapped to different address offsets. The SRAM should only be accessed by the IPL and contains non-volatile system data. The Mask ROM contains the IPL itself (encrypted) and the system font data.

Personal tools