N64 程式設計/編譯
外觀
< N64 程式設計

N64 絕不是資源受限的,因此用 C 語言為其編寫軟體是完全合理的。不過,您必須牢記一件事:為 N64 編碼需要深入瞭解 C 語言和 MIPS R4K 彙編。但是,彙編只需要在初始化 N64(或處理異常)的小例程中使用。您還需要熟悉 GNU 工具鏈(主要是 binutils 和 gcc)。
選擇一個您想要編譯二進位制檔案的目錄,將其設定為 $PREFIX,並確保它存在。例如,
export PREFIX=/opt/n64
mkdir -p $PREFIX
接下來,將 $GCC 設定為您將使用的編譯器。例如,
export GCC=gcc
下載 binutils 原始碼(我們將使用 2.35.1 版本),並解壓縮它。
建立一個樹外構建目錄,並進入其中
mkdir -p build-binutils
cd build-binutils
然後執行以下命令
../binutils-2.35.1/configure \
--target=mips64-elf --prefix=$PREFIX \
--program-prefix=mips64- --with-cpu=vr4300 \
--with-sysroot --disable-nls --disable-werror
make CC=$GCC
make install
希望一切順利,現在您將擁有一個針對 MIPS 的 binutils 軟體包。回到您的工作目錄,現在該構建 GCC 了。
GCC 需要使用您上面編譯的一些二進位制檔案,因此請執行以下操作
export PATH=$PREFIX/bin:$PATH
這將使 GCC 能夠找到它們。
與 binutils 一樣,下載 gcc 原始碼(我們將使用 10.2.0 版本)並解壓縮它。
建立一個樹外構建目錄,並進入其中
mkdir -p build-gcc
cd build-gcc
然後執行以下命令
../gcc-10.2.0/configure \
--target=mips64-elf --prefix=$PREFIX \
--program-prefix=mips64- --with-arch=vr4300 \
-with-languages=c,c++ --disable-threads \
--disable-nls --without-headers
make all-gcc CC=$GCC
make all-target-libgcc CC=$GCC
make install-gcc
make install-target-libgcc
mips64 工具鏈現在應該安裝在您選擇的 $PREFIX/bin 中。
雖然為 N64 編寫 C 程式碼與任何其他平臺沒有區別(除了您沒有可用的庫),但您有時可能需要寫入記憶體對映暫存器。以下示例(使用 DMA)演示了這一點
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **
** N64 DMA **
** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
typedef struct
{
/* Pointers to data */
void *ramp;
void *romp;
/* Filesizes (8-byte aligned) */
u32 size_ramrom; /* RAM -> ROM */
u32 size_romram; /* RAM <- ROM */
/* Status register */
u32 status;
} DMA_REG;
/* DMA status flags */
enum
{
DMA_BUSY = 0x00000001,
DMA_ERROR = 0x00000008
};
/* DMA registers ptr */
static volatile DMA_REG * dmaregs = (DMA_REG*)0xA4600000;
/* Copy data from ROM to RAM */
int dma_write_ram ( void *ram_ptr, void *rom_ptr, u32 length )
{
/* Check that DMA is not busy already */
while( dmaregs->status & DMA_BUSY );
/* Write addresses */
dmaregs->ramp = (u32)ram_ptr & 0x00FFFFFF; /* ram pointer */
dmaregs->romp = (u32)rom_ptr & 0x1FFFFFFF; /* rom pointer */
/* Write size */
dmaregs->size_romram = length - 1;
/* Wait for transfer to finish */
while( dmaregs->status & DMA_BUSY );
/* Return size written */
return length & 0xFFFFFFF8;
}
您可能還必須經常使用內聯彙編。以下函式在記憶體區域設定斷點
enum
{
BREAKPOINT_READ = 1,
BREAKPOINT_WRITE = 2
};
/* Set breakpoint */
void bp_set ( u32 addr, u8 flags )
{
addr &= 0x3FFFF8; /* assuming lower 4MB, also doubleword */
flags &= 0x03; /* only lower two bits */
addr |= flags;
asm("mtc0 %0, $18\n" /* WatchLo */
"mtc0 $zero, $19\n" /* WatchHi */
::"r"(addr));
}