1641 lines
53 KiB
C
1641 lines
53 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdint.h>
|
|
#include <malloc.h>
|
|
#include <libdragon.h>
|
|
#include <n64sys.h>
|
|
#include "everdrive.h"
|
|
#include "sys.h"
|
|
|
|
#include "types.h"
|
|
#include "utils.h"
|
|
#include "sram.h"
|
|
|
|
|
|
|
|
|
|
#define STBI_HEADER_FILE_ONLY
|
|
#include "stb_image.c"
|
|
|
|
extern short int gCheats; /* 0 = off, 1 = select, 2 = all */
|
|
extern short int force_tv;
|
|
extern short int boot_country;
|
|
|
|
struct gscEntry {
|
|
char *description;
|
|
char *gscodes;
|
|
u16 count;
|
|
u16 state;
|
|
u16 mask;
|
|
u16 value;
|
|
};
|
|
typedef struct gscEntry gscEntry_t;
|
|
|
|
extern gscEntry_t gGSCodes[];
|
|
|
|
|
|
|
|
static u8 __attribute__((aligned(16))) dmaBuf[128*1024];
|
|
static volatile struct _PI_regs_s * const _PI_regs = (struct _PI_regs_s *)0xa4600000;
|
|
|
|
int is_valid_rom(unsigned char *buffer)
|
|
{
|
|
/* Test if rom is a native .z64 image with header 0x80371240. [ABCD] */
|
|
if((buffer[0]==0x80)&&(buffer[1]==0x37)&&(buffer[2]==0x12)&&(buffer[3]==0x40))
|
|
return 0;
|
|
/* Test if rom is a byteswapped .v64 image with header 0x37804012. [BADC] */
|
|
else if((buffer[0]==0x37)&&(buffer[1]==0x80)&&(buffer[2]==0x40)&&(buffer[3]==0x12))
|
|
return 1;
|
|
/* Test if rom is a wordswapped .n64 image with header 0x40123780. [DCBA] */
|
|
else if((buffer[0]==0x40)&&(buffer[1]==0x12)&&(buffer[2]==0x37)&&(buffer[3]==0x80))
|
|
return 2;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
void swap_header(unsigned char* header, int loadlength)
|
|
{
|
|
unsigned char temp;
|
|
int i;
|
|
|
|
/* Btyeswap if .v64 image. */
|
|
if( header[0]==0x37)
|
|
{
|
|
// *imagetype = V64IMAGE;
|
|
for (i = 0; i < loadlength; i+=2)
|
|
{
|
|
temp= header[i];
|
|
header[i]= header[i+1];
|
|
header[i+1]=temp;
|
|
}
|
|
}
|
|
/* Wordswap if .n64 image. */
|
|
else if( header[0]==0x40)
|
|
{
|
|
// *imagetype = N64IMAGE;
|
|
for (i = 0; i < loadlength; i+=4)
|
|
{
|
|
temp= header[i];
|
|
header[i]= header[i+3];
|
|
header[i+3]=temp;
|
|
temp= header[i+1];
|
|
header[i+1]= header[i+2];
|
|
header[i+2]=temp;
|
|
}
|
|
}
|
|
// else
|
|
// *imagetype = Z64IMAGE;
|
|
}
|
|
|
|
|
|
|
|
|
|
u8 getCicType(u8 bios_cic) {
|
|
|
|
u8 cic_buff[2048];
|
|
volatile u8 cic_chip;
|
|
volatile u32 val; // = *(u32 *) 0xB0000170;
|
|
if (bios_cic) {
|
|
evd_setCfgBit(ED_CFG_SDRAM_ON, 0);
|
|
sleep(10);
|
|
val = *(u32 *) 0xB0000170;
|
|
dma_read_s(cic_buff, 0xB0000040, 1024);
|
|
cic_chip = get_cic(cic_buff);
|
|
evd_setCfgBit(ED_CFG_SDRAM_ON, 1);
|
|
sleep(10);
|
|
|
|
} else {
|
|
val = *(u32 *) 0xB0000170;
|
|
dma_read_s(cic_buff, 0xB0000040, 1024);
|
|
cic_chip = get_cic(cic_buff);
|
|
|
|
}
|
|
return cic_chip;
|
|
}
|
|
|
|
|
|
|
|
int get_cic(unsigned char *buffer)
|
|
{
|
|
unsigned int crc;
|
|
// figure out the CIC
|
|
crc = CRC_Calculate(0, buffer, 1000);
|
|
switch(crc)
|
|
{
|
|
case 0x303faac9:
|
|
case 0xf0da3d50:
|
|
return 1;
|
|
case 0xf3106101:
|
|
return 2;
|
|
case 0xe7cd9d51:
|
|
return 3;
|
|
case 0x7ae65c9:
|
|
return 5;
|
|
case 0x86015f8f:
|
|
return 6;
|
|
}
|
|
return 2;
|
|
}
|
|
|
|
int get_cic_save(char *cartid, int *cic, int *save)
|
|
{
|
|
// variables
|
|
int NUM_CARTS = 137;
|
|
int i;
|
|
|
|
//data arrays
|
|
//char *names[] = {"gnuboy64lite", "FRAMTestRom", "SRAMTestRom", "Worms Armageddon", "Super Smash Bros.", "Banjo-Tooie", "Blast Corps", "Bomberman Hero", "Body Harvest", "Banjo-Kazooie", "Bomberman 64", "Bomberman 64: Second Attack", "Command & Conquer", "Chopper Attack", "NBA Courtside 2 featuring Kobe Bryant", "Penny Racers", "Chameleon Twist", "Cruis'n USA", "Cruis'n World", "Legend of Zelda: Majora's Mask, The", "Donkey Kong 64", "Donkey Kong 64", "Donald Duck: Goin' Quackers", "Loony Toons: Duck Dodgers", "Diddy Kong Racing", "PGA European Tour", "Star Wars Episode 1 Racer", "AeroFighters Assault", "Bass Hunter 64", "Conker's Bad Fur Day", "F-1 World Grand Prix", "Star Fox 64", "F-Zero X", "GT64 Championship Edition", "GoldenEye 007", "Glover", "Bomberman 64", "Indy Racing 2000", "Indiana Jones and the Infernal Machine", "Jet Force Gemini", "Jet Force Gemini", "Earthworm Jim 3D", "Snowboard Kids 2", "Kirby 64: The Crystal Shards", "Fighters Destiny", "Major League Baseball featuring Ken Griffey Jr.", "Killer Instinct Gold", "Ken Griffey Jr's Slugfest", "Mario Kart 64", "Mario Party", "Lode Runner 3D", "Megaman 64", "Mario Tennis", "Mario Golf", "Mission: Impossible", "Mickey's Speedway USA", "Monopoly", "Paper Mario", "Multi-Racing Championship", "Big Mountain 2000", "Mario Party 3", "Mario Party 2", "Excitebike 64", "Dr. Mario 64", "Star Wars Episode 1: Battle for Naboo", "Kobe Bryant in NBA Courtside", "Excitebike 64", "Ogre Battle 64: Person of Lordly Caliber", "Pokémon Stadium 2", "Pokémon Stadium 2", "Perfect Dark", "Pokémon Snap", "Hey you, Pikachu!", "Pokémon Snap", "Pokémon Puzzle League", "Pokémon Stadium", "Pokémon Stadium", "Pilotwings 64", "Top Gear Overdrive", "Resident Evil 2", "New Tetris, The", "Star Wars: Rogue Squadron", "Ridge Racer 64", "Star Soldier: Vanishing Earth", "AeroFighters Assault", "Starshot Space Circus", "Super Mario 64", "Starcraft 64", "Rocket: Robot on Wheels", "Space Station Silicon Valley", "Star Wars: Shadows of the Empire", "Tigger's Honey Hunt", "1080º Snowboarding", "Tom & Jerry in Fists of Furry", "Mischief Makers", "All-Star Tennis '99", "Tetrisphere", "V-Rally Edition '99", "V-Rally Edition '99", "WCW/NWO Revenge", "WWF: No Mercy", "Waialae Country Club: True Golf Classics", "Wave Race 64", "Worms Armageddon", "WWF: Wrestlemania 2000", "Cruis'n Exotica", "Yoshi's Story", "Harvest Moon 64", "Legend of Zelda: Ocarina of Time, The", "Legend of Zelda: Majora's Mask, The", "Airboarder 64", "Bakuretsu Muteki Bangaioh", "Choro-Q 64 II", "Custom Robo", "Custom Robo V2", "Densha de Go! 64", "Doraemon: Mittsu no Seireiseki", "Dezaemon 3D", "Transformers Beast Wars", "Transformers Beast Wars Metals", "64 Trump Collection", "Bass Rush", "ECW Hardcore Revolution", "40 Winks", "Aero Gauge", "Aidyn Chronicles The First Mage", "Derby Stallion 64", "Doraemon 2 - Hikari no Shinden", "Doraemon 3 - Nobi Dai No Machi SOS", "F-1 World Grand Prix II", "Fushigi no Dungeon - Furai no Shiren 2", "Heiwa Pachinko World 64", "Neon Genesis Evangelion", "Racing Simulation", "Tsumi to Batsu", "Sonic Wings Assault", "Virtual Pro Wrestling", "Virtual Pro Wrestling 2", "Wild Choppers"};
|
|
char *cartIDs[] = {"DZ", "B6", "ZY", "ZZ", "AD", "AL", "B7", "BC", "BD", "BH", "BK", "BM", "BV", "CC", "CH", "CK", "CR", "CT", "CU", "CW", "DL", "DO", "DP", "DQ", "DU", "DY", "EA", "EP", "ER", "FH", "FU", "FW", "FX", "FZ", "GC", "GE", "GV", "HA", "IC", "IJ", "JD", "JF", "JM", "K2", "K4", "KA", "KG", "KI", "KJ", "KT", "LB", "LR", "M6", "M8", "MF", "MI", "ML", "MO", "MQ", "MR", "MU", "MV", "MW", "MX", "N6", "NA", "NB", "NX", "OB", "P2", "P3", "PD", "PF", "PG", "PH", "PN", "PO", "PS", "PW", "RC", "RE", "RI", "RS", "RZ", "S6", "SA", "SC", "SM", "SQ", "SU", "SV", "SW", "T9", "TE", "TJ", "TM", "TN", "TP", "VL", "VY", "W2", "W4", "WL", "WR", "WU", "WX", "XO", "YS", "YW", "ZL", "ZS", "AB", "BN", "CG", "CX", "CZ", "D6", "DR", "DZ", "OH", "TB", "TC", "VB", "WI", "4W", "AG", "AY", "DA", "D2", "3D", "F2", "SI", "HP", "EV", "MG", "GU", "SA", "VP", "A2", "WC"};
|
|
|
|
//int saveTypes[] = {5, 1, 6, 5, 5, 5, 5, 5, 5, 4, 5, 4, 5, 5, 5, 6, 4, 6, 6, 5, 5, 5, 5, 6, 5, 5, 6, 5, 5, 1, 5, 5, 5, 5, 5, 5, 4, 4, 5, 5, 5, 5, 1, 5, 4, 5, 5, 5, 4, 6, 1, 5, 5, 5, 4, 5, 5, 6, 5, 6, 5, 5, 6, 6, 1, 4, 4, 6, 4, 5, 4, 4, 4, 4, 5, 5, 1, 1, 5, 6, 5, 5, 5, 5, 4, 5, 5, 5, 4, 1, 5, 5, 5, 5, 5, 5, 1, 4, 5, 5, 5, 1, 5, 6, 1, 1, 4, 5, 5, 5, 5, 6, 1, 5, 1, 5, 5, 5, 1, 1, 5, 5, 1, 1, 6, 6, 6, 4, 5, 6, 5, 5, 5, 1, 1, 5};
|
|
// Banjo-Tooie B7 -> set to sram 'cause crk converts ek16->sram
|
|
int saveTypes[] = {2, 1, 5, 1, 3, 1, 1, 3, 3, 3, 3, 3, 3, 5, 3, 5, 3, 3, 3, 4, 5, 4, 4, 3, 3, 3, 3, 4, 3, 3, 4, 3, 3, 1, 3, 3, 3, 3, 3, 3, 5, 5, 3, 3, 3, 3, 1, 3, 5, 3, 3, 3, 5, 4, 1, 3, 3, 3, 5, 3, 3, 4, 3, 4, 3, 3, 4, 4, 1, 5, 5, 4, 5, 3, 5, 5, 5, 5, 3, 3, 1, 1, 3, 4, 3, 3, 3, 3, 5, 3, 3, 3, 5, 1, 3, 3, 3, 3, 3, 3, 1, 5, 3, 3, 3, 1, 3, 4, 1, 1, 5, 3, 3, 3, 3, 4, 1, 3, 1, 3, 3, 3, 1, 1, 3, 3, 1, 1, 4, 4, 4, 5, 3, 4, 3, 3, 3, 1, 1, 3};
|
|
|
|
//bt cic to 2 pos6 was 5
|
|
int cicTypes[] = {2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 6, 5, 5, 5, 2, 2, 3, 2, 2, 2, 2, 5, 2, 1, 6, 2, 2, 2, 2, 2, 2, 5, 5, 2, 2, 3, 2, 3, 2, 3, 2, 2, 2, 2, 2, 2, 2, 5, 2, 3, 2, 2, 2, 2, 3, 2, 2, 3, 3, 2, 3, 3, 5, 3, 2, 3, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 2, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2};
|
|
|
|
// search for cartid
|
|
for (i=0; i<NUM_CARTS; i++)
|
|
if (strcmp(cartid, cartIDs[i]) == 0)
|
|
break;
|
|
|
|
if (i == NUM_CARTS)
|
|
{
|
|
// cart not in list
|
|
*cic = 2;
|
|
*save = 0;
|
|
return 0; // not found
|
|
}
|
|
|
|
// cart found
|
|
*cic = cicTypes[i];
|
|
*save = saveTypes[i];
|
|
return 1; // found
|
|
}
|
|
|
|
|
|
const char* saveTypeToExtension(int type, int etype){
|
|
|
|
static char* str = "SAV";
|
|
|
|
if(etype==0){
|
|
switch(type)
|
|
{
|
|
case 0: str = "OFF"; break;
|
|
case 1: str = "SRM"; break;
|
|
case 2: str = "128"; break;
|
|
case 3: str = "E4K"; break;
|
|
case 4: str = "E16"; break;
|
|
case 5: str = "FLA"; break;
|
|
default: str = "SAV";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch(type)
|
|
{
|
|
case 0: str = "OFF"; break;
|
|
case 1: str = "SRA"; break;
|
|
case 2: str = "SRA"; break;
|
|
case 3: str = "EEP"; break;
|
|
case 4: str = "EEP"; break;
|
|
case 5: str = "FLA"; break;
|
|
default: str = "SAV";
|
|
}
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
int saveTypeToSize(int type){
|
|
|
|
switch(type)
|
|
{
|
|
case 0: return 0; break;
|
|
case 1: return SAVE_SIZE_SRAM; break;
|
|
case 2: return SAVE_SIZE_SRAM128; break;
|
|
case 3: return SAVE_SIZE_EEP4k; break;
|
|
case 4: return SAVE_SIZE_EEP16k; break;
|
|
case 5: return SAVE_SIZE_FLASH; break;
|
|
default: return 0;
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
#define SAVE_TYPE_OFF 0
|
|
#define SAVE_TYPE_SRAM 1
|
|
#define SAVE_TYPE_SRAM128 2
|
|
#define SAVE_TYPE_EEP4k 3
|
|
#define SAVE_TYPE_EEP16k 4
|
|
#define SAVE_TYPE_FLASH 5
|
|
|
|
*/
|
|
|
|
|
|
//switch to the correct dump function
|
|
int getSaveFromCart(int stype, uint8_t *buffer){
|
|
|
|
int ret=0;
|
|
|
|
switch(stype)
|
|
{
|
|
case 0: return 0;
|
|
case 1: ret = getSRAM32(buffer); break;
|
|
case 2: ret = getSRAM128(buffer); break;
|
|
case 3: ret = getEeprom4k(buffer); break;
|
|
case 4: ret = getEeprom16k(buffer); break;
|
|
case 5: ret = getFlashRAM(buffer); break;
|
|
default: return 0;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
//switch to the correct upload function
|
|
int pushSaveToCart(int stype, uint8_t *buffer){
|
|
|
|
|
|
int ret=0;
|
|
|
|
switch(stype)
|
|
{
|
|
case 0: return 0;
|
|
case 1: ret = setSRAM32(buffer); break;
|
|
case 2: ret = setSRAM128(buffer); break;
|
|
case 3: ret = setEeprom4k(buffer); break;
|
|
case 4: ret = setEeprom16k(buffer); break;
|
|
case 5: ret = setFlashRAM(buffer); break;
|
|
default: return 0;
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
int getSRAM( uint8_t *buffer, int size){
|
|
|
|
|
|
|
|
while (dma_busy()) ;
|
|
IO_WRITE(PI_BSD_DOM2_LAT_REG, 0x05);
|
|
IO_WRITE(PI_BSD_DOM2_PWD_REG, 0x0C);
|
|
IO_WRITE(PI_BSD_DOM2_PGS_REG, 0x0D);
|
|
IO_WRITE(PI_BSD_DOM2_RLS_REG, 0x02);
|
|
|
|
while (dma_busy()) ;
|
|
|
|
|
|
PI_Init();
|
|
|
|
sleep(1000);
|
|
|
|
while (dma_busy()) ;
|
|
//dma_read_sram(writeback, 0, 32);
|
|
PI_DMAFromSRAM(buffer, 0, size) ;
|
|
|
|
|
|
while (dma_busy()) ;
|
|
IO_WRITE(PI_BSD_DOM2_LAT_REG, 0x40);
|
|
IO_WRITE(PI_BSD_DOM2_PWD_REG, 0x12);
|
|
IO_WRITE(PI_BSD_DOM2_PGS_REG, 0x07);
|
|
IO_WRITE(PI_BSD_DOM2_RLS_REG, 0x03);
|
|
|
|
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
int getSRAM32( uint8_t *buffer){
|
|
|
|
return getSRAM(buffer, SAVE_SIZE_SRAM);
|
|
}
|
|
|
|
int getSRAM128( uint8_t *buffer){
|
|
|
|
return getSRAM(buffer, SAVE_SIZE_SRAM128);
|
|
}
|
|
|
|
|
|
//working hurray :D
|
|
int getEeprom4k( uint8_t *buffer){
|
|
|
|
if(eeprom_present()){
|
|
int blocks=SAVE_SIZE_EEP4k/8;
|
|
for( int b = 0; b < blocks; b++ )
|
|
{
|
|
eeprom_read( b, &buffer[b * 8] );
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int getEeprom16k( uint8_t *buffer){
|
|
|
|
|
|
int blocks=SAVE_SIZE_EEP16k/8;
|
|
for( int b = 0; b < blocks; b++ )
|
|
{
|
|
eeprom_read( b, &buffer[b * 8] );
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
|
|
int getFlashRAM( uint8_t *buffer){
|
|
|
|
|
|
evd_setSaveType(SAVE_TYPE_SRAM128); //2
|
|
sleep(10);
|
|
|
|
int s = getSRAM(buffer, SAVE_SIZE_SRAM128);
|
|
data_cache_hit_writeback_invalidate(buffer,SAVE_SIZE_SRAM128);
|
|
|
|
sleep(10);
|
|
evd_setSaveType(SAVE_TYPE_FLASH); //5
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
sram upload
|
|
*/
|
|
int setSRAM( uint8_t *buffer,int size){
|
|
|
|
//half working
|
|
PI_DMAWait();
|
|
//Timing
|
|
PI_Init_SRAM();
|
|
|
|
//Readmode
|
|
PI_Init();
|
|
|
|
data_cache_hit_writeback_invalidate(buffer,size);
|
|
while (dma_busy());
|
|
PI_DMAToSRAM(buffer, 0, size);
|
|
data_cache_hit_writeback_invalidate(buffer,size);
|
|
|
|
//Wait
|
|
PI_DMAWait();
|
|
//Restore evd Timing
|
|
setSDTiming();
|
|
|
|
return 1;
|
|
}
|
|
|
|
int setSRAM32( uint8_t *buffer){
|
|
|
|
return setSRAM(buffer, SAVE_SIZE_SRAM);
|
|
}
|
|
|
|
int setSRAM128( uint8_t *buffer){
|
|
|
|
return setSRAM(buffer, SAVE_SIZE_SRAM128);
|
|
}
|
|
|
|
|
|
//working hurray :D
|
|
int setEeprom4k( uint8_t *buffer){
|
|
|
|
if(eeprom_present()){
|
|
int blocks=SAVE_SIZE_EEP4k/8;
|
|
for( int b = 0; b < blocks; b++ )
|
|
{
|
|
eeprom_write( b, &buffer[b * 8] );
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int setEeprom16k(uint8_t *buffer){
|
|
|
|
|
|
|
|
int blocks=SAVE_SIZE_EEP16k/8;
|
|
for( int b = 0; b < blocks; b++ )
|
|
{
|
|
eeprom_write( b, &buffer[b * 8] );
|
|
}
|
|
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
//isn't working nor finished
|
|
int setFlashRAM(uint8_t *buffer){
|
|
|
|
evd_setSaveType(SAVE_TYPE_SRAM128); //2
|
|
sleep(10);
|
|
|
|
int s = setSRAM(buffer, SAVE_SIZE_SRAM128);
|
|
|
|
evd_setSaveType(SAVE_TYPE_FLASH); //5
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setSDTiming(void){
|
|
|
|
|
|
/*
|
|
PI_BSD_DOM1_LAT_REG (0x04600014) write word 0x000000FF
|
|
PI_BSD_DOM1_PWD_REG (0x04600018) write word 0x000000FF
|
|
PI_BSD_DOM1_PGS_REG (0x0460001C) write word 0x0000000F
|
|
PI_BSD_DOM1_RLS_REG (0x04600020) write word 0x00000003
|
|
*
|
|
PI_BSD_DOM1_LAT_REG (0x04600014) write word 0x00000040
|
|
PI_BSD_DOM1_PWD_REG (0x04600018) write word 0x00803712
|
|
PI_BSD_DOM1_PGS_REG (0x0460001C) write word 0x00008037
|
|
PI_BSD_DOM1_RLS_REG (0x04600020) write word 0x00000803
|
|
*/
|
|
|
|
|
|
|
|
// PI_DMAWait();
|
|
IO_WRITE(PI_BSD_DOM1_LAT_REG, 0x40);
|
|
IO_WRITE(PI_BSD_DOM1_PWD_REG, 0x12);
|
|
IO_WRITE(PI_BSD_DOM1_PGS_REG, 0x07);
|
|
IO_WRITE(PI_BSD_DOM1_RLS_REG, 0x03);
|
|
|
|
IO_WRITE(PI_BSD_DOM2_LAT_REG, 0x40);
|
|
IO_WRITE(PI_BSD_DOM2_PWD_REG, 0x12);
|
|
IO_WRITE(PI_BSD_DOM2_PGS_REG, 0x07);
|
|
IO_WRITE(PI_BSD_DOM2_RLS_REG, 0x03);
|
|
}
|
|
|
|
|
|
void _data_cache_invalidate_all(void) {
|
|
asm(
|
|
"li $8,0x80000000\n"
|
|
"li $9,0x80000000\n"
|
|
"addu $9,$9,0x1FF0\n"
|
|
"cacheloop:\n"
|
|
"cache 1,0($8)\n"
|
|
"cache 1,16($8)\n"
|
|
"cache 1,32($8)\n"
|
|
"cache 1,48($8)\n"
|
|
"cache 1,64($8)\n"
|
|
"cache 1,80($8)\n"
|
|
"cache 1,96($8)\n"
|
|
"addu $8,$8,112\n"
|
|
"bne $8,$9,cacheloop\n"
|
|
"cache 1,0($8)\n"
|
|
: // no outputs
|
|
: // no inputs
|
|
: "$8", "$9" // trashed registers
|
|
);
|
|
}
|
|
|
|
void restoreTiming(void){
|
|
|
|
//n64 timing restore :>
|
|
IO_WRITE(PI_BSD_DOM1_LAT_REG, 0x40);
|
|
IO_WRITE(PI_BSD_DOM1_PWD_REG, 0x12);
|
|
IO_WRITE(PI_BSD_DOM1_PGS_REG, 0x07);
|
|
IO_WRITE(PI_BSD_DOM1_RLS_REG, 0x03);
|
|
|
|
IO_WRITE(PI_BSD_DOM2_LAT_REG, 0x40);
|
|
IO_WRITE(PI_BSD_DOM2_PWD_REG, 0x12);
|
|
IO_WRITE(PI_BSD_DOM2_PGS_REG, 0x07);
|
|
IO_WRITE(PI_BSD_DOM2_RLS_REG, 0x03);
|
|
}
|
|
|
|
/*
|
|
* Load an image from the rom filesystem, returning a pointer to the
|
|
* sprite that hold the image.
|
|
*/
|
|
sprite_t *loadImageDFS(char *fname)
|
|
{
|
|
int size, x, y, n, fd;
|
|
u8 *tbuf;
|
|
u8 *ibuf;
|
|
sprite_t *sbuf;
|
|
|
|
fd = dfs_open(fname);
|
|
if (fd < 0)
|
|
return 0; // couldn't open image
|
|
|
|
size = dfs_size(fd);
|
|
tbuf = malloc(size);
|
|
if (!tbuf)
|
|
{
|
|
dfs_close(fd);
|
|
return 0; // out of memory
|
|
}
|
|
|
|
dfs_read(tbuf, 1, size, fd);
|
|
dfs_close(fd);
|
|
|
|
ibuf = stbi_load_from_memory(tbuf, size, &x, &y, &n, 4);
|
|
free(tbuf);
|
|
if (!ibuf)
|
|
return 0; // couldn't decode image
|
|
|
|
sbuf = (sprite_t*)malloc(sizeof(sprite_t) + x * y * 2);
|
|
if (!sbuf)
|
|
{
|
|
stbi_image_free(ibuf);
|
|
return 0; // out of memory
|
|
}
|
|
sbuf->width = x;
|
|
sbuf->height = y;
|
|
sbuf->bitdepth = 2;
|
|
sbuf->format = 0;
|
|
sbuf->hslices = x / 32;
|
|
sbuf->vslices = y / 16;
|
|
|
|
color_t *src = (color_t*)ibuf;
|
|
u16 *dst = (u16*)((u32)sbuf + sizeof(sprite_t));
|
|
|
|
for (int j=0; j<y; j++)
|
|
for (int i=0; i<x; i++)
|
|
dst[i + j*x] = graphics_convert_color(src[i + j*x]) & 0x0000FFFF;
|
|
/* Invalidate data associated with sprite in cache */
|
|
data_cache_hit_writeback_invalidate( sbuf->data, sbuf->width * sbuf->height * sbuf->bitdepth );
|
|
//data_cache_writeback_invalidate( sbuf->data, sbuf->width * sbuf->height * sbuf->bitdepth );
|
|
// data_cache_hit_writeback_invalidate(buffer,size);
|
|
|
|
stbi_image_free(ibuf);
|
|
return sbuf;
|
|
}
|
|
|
|
|
|
sprite_t *loadImage32(u8 *png, int size)
|
|
{
|
|
int x, y, n, fd;
|
|
u8 *tbuf;
|
|
u32 *ibuf;
|
|
sprite_t *sbuf;
|
|
|
|
tbuf = malloc(size);
|
|
memcpy(tbuf,png,size);
|
|
|
|
ibuf = stbi_load_from_memory(tbuf, size, &x, &y, &n, 4);
|
|
free(tbuf);
|
|
if (!ibuf)
|
|
return 0; // couldn't decode image
|
|
|
|
sbuf = (sprite_t*)malloc(sizeof(sprite_t) + x * y * 4);
|
|
if (!sbuf)
|
|
{
|
|
stbi_image_free(ibuf);
|
|
return 0; // out of memory
|
|
}
|
|
sbuf->width = x;
|
|
sbuf->height = y;
|
|
sbuf->bitdepth = 4;
|
|
sbuf->format = 0;
|
|
sbuf->hslices = x / 32;
|
|
sbuf->vslices = y / 32;
|
|
|
|
// color_t *src = (color_t*)ibuf;
|
|
u32 *dst = (u32*)((u32)sbuf + sizeof(sprite_t));
|
|
|
|
for (int j=0; j<y; j++)
|
|
for (int i=0; i<x; i++)
|
|
dst[i + j*x] = ibuf[i + j*x];
|
|
/* Invalidate data associated with sprite in cache */
|
|
data_cache_hit_writeback_invalidate( sbuf->data, sbuf->width * sbuf->height * sbuf->bitdepth );
|
|
//data_cache_writeback_invalidate( sbuf->data, sbuf->width * sbuf->height * sbuf->bitdepth );
|
|
// data_cache_hit_writeback_invalidate(buffer,size);
|
|
|
|
stbi_image_free(ibuf);
|
|
return sbuf;
|
|
}
|
|
|
|
|
|
sprite_t *loadImage32DFS(char *fname)
|
|
{
|
|
int size, x, y, n, fd;
|
|
u8 *tbuf;
|
|
u32 *ibuf;
|
|
sprite_t *sbuf;
|
|
|
|
fd = dfs_open(fname);
|
|
if (fd < 0)
|
|
return 0; // couldn't open image
|
|
|
|
size = dfs_size(fd);
|
|
tbuf = malloc(size);
|
|
if (!tbuf)
|
|
{
|
|
dfs_close(fd);
|
|
return 0; // out of memory
|
|
}
|
|
|
|
dfs_read(tbuf, 1, size, fd);
|
|
dfs_close(fd);
|
|
|
|
ibuf = stbi_load_from_memory(tbuf, size, &x, &y, &n, 4);
|
|
free(tbuf);
|
|
if (!ibuf)
|
|
return 0; // couldn't decode image
|
|
|
|
sbuf = (sprite_t*)malloc(sizeof(sprite_t) + x * y * 4);
|
|
if (!sbuf)
|
|
{
|
|
stbi_image_free(ibuf);
|
|
return 0; // out of memory
|
|
}
|
|
sbuf->width = x;
|
|
sbuf->height = y;
|
|
sbuf->bitdepth = 4;
|
|
sbuf->format = 0;
|
|
sbuf->hslices = x / 32;
|
|
sbuf->vslices = y / 32;
|
|
|
|
// color_t *src = (color_t*)ibuf;
|
|
u32 *dst = (u32*)((u32)sbuf + sizeof(sprite_t));
|
|
|
|
for (int j=0; j<y; j++)
|
|
for (int i=0; i<x; i++)
|
|
dst[i + j*x] = ibuf[i + j*x];
|
|
/* Invalidate data associated with sprite in cache */
|
|
data_cache_hit_writeback_invalidate( sbuf->data, sbuf->width * sbuf->height * sbuf->bitdepth );
|
|
//data_cache_writeback_invalidate( sbuf->data, sbuf->width * sbuf->height * sbuf->bitdepth );
|
|
// data_cache_hit_writeback_invalidate(buffer,size);
|
|
|
|
stbi_image_free(ibuf);
|
|
return sbuf;
|
|
}
|
|
|
|
/*
|
|
* Draw an image to the screen using the sprite passed.
|
|
*/
|
|
void drawImage(display_context_t dcon, sprite_t *sprite)
|
|
{
|
|
int x, y = 0;
|
|
|
|
rdp_sync(SYNC_PIPE);
|
|
rdp_set_default_clipping();
|
|
rdp_enable_texture_copy();
|
|
rdp_attach_display(dcon);
|
|
// Draw image
|
|
for (int j=0; j<sprite->vslices; j++)
|
|
{
|
|
x = 0;
|
|
for (int i=0; i<sprite->hslices; i++)
|
|
{
|
|
rdp_sync(SYNC_PIPE);
|
|
rdp_load_texture_stride(0, 0, MIRROR_DISABLED, sprite, j*sprite->hslices + i);
|
|
rdp_draw_sprite(0, x, y);
|
|
x += 32;
|
|
}
|
|
y += 16;
|
|
}
|
|
rdp_detach_display();
|
|
}
|
|
|
|
|
|
#define CIC_6101 1
|
|
#define CIC_6102 2
|
|
#define CIC_6103 3
|
|
#define CIC_6104 4
|
|
#define CIC_6105 5
|
|
#define CIC_6106 6
|
|
|
|
|
|
void globalTest(void){
|
|
|
|
gCheats=1;
|
|
|
|
}
|
|
|
|
|
|
void simulate_boot(u32 cic_chip, u8 gBootCic)
|
|
{
|
|
|
|
if (cic_chip == CIC_6104)
|
|
cic_chip = CIC_6102;
|
|
|
|
u32 ix, sz, cart, country;
|
|
vu32 *src, *dst;
|
|
u32 info = *(vu32 *)0xB000003C;
|
|
vu64 *gGPR = (vu64 *)0xA03E0000;
|
|
//vu64 *gGPR = (vu64 *)0xA0080000; //n
|
|
vu32 *codes = (vu32 *)0xA0000180;
|
|
u64 bootAddr = 0xFFFFFFFFA4000040LL;
|
|
char *cp, *vp, *tp;
|
|
char temp[8];
|
|
int i, type, val;
|
|
int curr_cheat = 0;
|
|
|
|
cart = info >> 16;
|
|
country = (info >> 8) & 0xFF;
|
|
|
|
if(boot_country!=0){
|
|
switch(boot_country){
|
|
case 1: country = 0x45; break; //ntsc region
|
|
case 2: country = 0x50; break; //pal region
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
// clear XBUS/Flush/Freeze
|
|
((vu32 *)0xA4100000)[3] = 0x15;
|
|
|
|
|
|
sz = (gBootCic != CIC_6105) ? *(vu32 *)0xA0000318 : *(vu32 *)0xA00003F0;
|
|
if (cic_chip == CIC_6105)
|
|
*(vu32 *)0xA00003F0 = sz;
|
|
else
|
|
*(vu32 *)0xA0000318 = sz;
|
|
|
|
// clear some OS globals for cleaner boot
|
|
*(vu32 *)0xA000030C = 0; // cold boot
|
|
memset((void *)0xA000031C, 0, 64); // clear app nmi buffer
|
|
|
|
|
|
|
|
if (gCheats)
|
|
{
|
|
|
|
u16 xv, yv, zv;
|
|
u32 xx;
|
|
vu32 *sp, *dp;
|
|
// get rom os boot segment - note, memcpy won't work for copying rom
|
|
sp = (vu32 *)0xB0001000;
|
|
dp = (vu32 *)0xA02A0000;
|
|
for (ix=0; ix<0x100000; ix++)
|
|
*dp++ = *sp++;
|
|
// default boot address with cheats
|
|
sp = (vu32 *)0xB0000008;
|
|
bootAddr = 0xFFFFFFFF00000000LL | *sp;
|
|
|
|
// move general int handler
|
|
sp = (vu32 *)0xA0000180;
|
|
dp = (vu32 *)0xA0000120;
|
|
for (ix=0; ix<0x60; ix+=4)
|
|
*dp++ = *sp++;
|
|
|
|
// insert new general int handler prologue
|
|
*codes++ = 0x401a6800; // mfc0 k0,c0_cause
|
|
*codes++ = 0x241b005c; // li k1,23*4
|
|
*codes++ = 0x335a007c; // andi k0,k0,0x7c
|
|
*codes++ = 0x175b0012; // bne k0,k1,0x1d8
|
|
*codes++ = 0x00000000; // nop
|
|
*codes++ = 0x40809000; // mtc0 zero,c0_watchlo
|
|
*codes++ = 0x401b7000; // mfc0 k1,c0_epc
|
|
*codes++ = 0x8f7a0000; // lw k0,0(k1)
|
|
*codes++ = 0x3c1b03e0; // lui k1,0x3e0
|
|
*codes++ = 0x035bd024; // and k0,k0,k1
|
|
*codes++ = 0x001ad142; // srl k0,k0,0x5
|
|
*codes++ = 0x3c1ba000; // lui k1,0xa000
|
|
*codes++ = 0x8f7b01cc; // lw k1,0x01cc(k1)
|
|
*codes++ = 0x035bd025; // or k0,k0,k1
|
|
*codes++ = 0x3c1ba000; // lui k1,0xa000
|
|
*codes++ = 0xaf7a01cc; // sw k0,0x01cc(k1)
|
|
*codes++ = 0x3c1b8000; // lui k1,0x8000
|
|
*codes++ = 0xbf7001cc; // cache 0x10,0x01cc(k1)
|
|
*codes++ = 0x3c1aa000; // lui k0,0xa000
|
|
*codes++ = 0x37400120; // ori zero,k0,0x120
|
|
*codes++ = 0x42000018; // eret
|
|
*codes++ = 0x00000000; // nop
|
|
|
|
// process cheats
|
|
while (gGSCodes[curr_cheat].count != 0xFFFF)
|
|
{
|
|
if (!gGSCodes[curr_cheat].state || !gGSCodes[curr_cheat].count)
|
|
{
|
|
// cheat not enabled or no codes, skip
|
|
curr_cheat++;
|
|
continue;
|
|
}
|
|
|
|
for (i=0; i<gGSCodes[curr_cheat].count; i++)
|
|
{
|
|
cp = &gGSCodes[curr_cheat].gscodes[i*16 + 0];
|
|
vp = &gGSCodes[curr_cheat].gscodes[i*16 + 9];
|
|
|
|
temp[0] = cp[0];
|
|
temp[1] = cp[1];
|
|
temp[2] = 0;
|
|
type = strtol(temp, (char **)NULL, 16);
|
|
|
|
switch(type)
|
|
{
|
|
case 0x80:
|
|
// write 8-bit value to (cached) ram continuously
|
|
// 80XXYYYY 00ZZ
|
|
temp[0] = cp[2];
|
|
temp[1] = cp[3];
|
|
temp[2] = 0;
|
|
xv = strtol(temp, (char **)NULL, 16);
|
|
temp[0] = cp[4];
|
|
temp[1] = cp[5];
|
|
temp[2] = cp[6];
|
|
temp[3] = cp[7];
|
|
temp[4] = 0;
|
|
yv = strtol(temp, (char **)NULL, 16);
|
|
if (yv & 0x8000) xv++; // adjust for sign extension of yv
|
|
if (gGSCodes[curr_cheat].mask)
|
|
{
|
|
zv = gGSCodes[curr_cheat].value & gGSCodes[curr_cheat].mask;
|
|
}
|
|
else
|
|
{
|
|
temp[0] = vp[2];
|
|
temp[1] = vp[3];
|
|
temp[2] = 0;
|
|
zv = strtol(temp, (char **)NULL, 16);
|
|
}
|
|
*codes++ = 0x3c1a8000 | xv; // lui k0,80xx
|
|
*codes++ = 0x241b0000 | zv; // li k1,00zz
|
|
*codes++ = 0xa35b0000 | yv; // sb k1,yyyy(k0)
|
|
|
|
|
|
break;
|
|
case 0x81:
|
|
// write 16-bit value to (cached) ram continuously
|
|
// 81XXYYYY 00ZZ
|
|
temp[0] = cp[2];
|
|
temp[1] = cp[3];
|
|
temp[2] = 0;
|
|
xv = strtol(temp, (char **)NULL, 16);
|
|
temp[0] = cp[4];
|
|
temp[1] = cp[5];
|
|
temp[2] = cp[6];
|
|
temp[3] = cp[7];
|
|
temp[4] = 0;
|
|
yv = strtol(temp, (char **)NULL, 16);
|
|
if (yv & 0x8000) xv++; // adjust for sign extension of yv
|
|
if (gGSCodes[curr_cheat].mask)
|
|
{
|
|
zv = gGSCodes[curr_cheat].value & gGSCodes[curr_cheat].mask;
|
|
}
|
|
else
|
|
{
|
|
temp[0] = vp[0];
|
|
temp[1] = vp[1];
|
|
temp[2] = vp[2];
|
|
temp[3] = vp[3];
|
|
temp[4] = 0;
|
|
zv = strtol(temp, (char **)NULL, 16);
|
|
}
|
|
*codes++ = 0x3c1a8000 | xv; // lui k0,80xx
|
|
*codes++ = 0x241b0000 | zv; // li k1,zzzz
|
|
*codes++ = 0xa75b0000 | yv; // sh k1,yyyy(k0)
|
|
break;
|
|
case 0x88:
|
|
// write 8-bit value to (cached) ram on GS button pressed - unimplemented
|
|
// 88XXYYYY 00ZZ
|
|
break;
|
|
case 0x89:
|
|
// write 16-bit value to (cached) ram on GS button pressed - unimplemented
|
|
// 89XXYYYY ZZZZ
|
|
break;
|
|
case 0xA0:
|
|
// write 8-bit value to (uncached) ram continuously
|
|
// A0XXYYYY 00ZZ
|
|
temp[0] = cp[2];
|
|
temp[1] = cp[3];
|
|
temp[2] = 0;
|
|
xv = strtol(temp, (char **)NULL, 16);
|
|
temp[0] = cp[4];
|
|
temp[1] = cp[5];
|
|
temp[2] = cp[6];
|
|
temp[3] = cp[7];
|
|
temp[4] = 0;
|
|
yv = strtol(temp, (char **)NULL, 16);
|
|
if (yv & 0x8000) xv++; // adjust for sign extension of yv
|
|
if (gGSCodes[curr_cheat].mask)
|
|
{
|
|
zv = gGSCodes[curr_cheat].value & gGSCodes[curr_cheat].mask;
|
|
}
|
|
else
|
|
{
|
|
temp[0] = vp[2];
|
|
temp[1] = vp[3];
|
|
temp[2] = 0;
|
|
zv = strtol(temp, (char **)NULL, 16);
|
|
}
|
|
*codes++ = 0x3c1aa000 | xv; // lui k0,A0xx
|
|
*codes++ = 0x241b0000 | zv; // li k1,00zz
|
|
*codes++ = 0xa35b0000 | yv; // sb k1,yyyy(k0)
|
|
break;
|
|
case 0xA1:
|
|
// write 16-bit value to (uncached) ram continuously
|
|
// A1XXYYYY 00ZZ
|
|
temp[0] = cp[2];
|
|
temp[1] = cp[3];
|
|
temp[2] = 0;
|
|
xv = strtol(temp, (char **)NULL, 16);
|
|
temp[0] = cp[4];
|
|
temp[1] = cp[5];
|
|
temp[2] = cp[6];
|
|
temp[3] = cp[7];
|
|
temp[4] = 0;
|
|
yv = strtol(temp, (char **)NULL, 16);
|
|
if (yv & 0x8000) xv++; // adjust for sign extension of yv
|
|
if (gGSCodes[curr_cheat].mask)
|
|
{
|
|
zv = gGSCodes[curr_cheat].value & gGSCodes[curr_cheat].mask;
|
|
}
|
|
else
|
|
{
|
|
temp[0] = vp[0];
|
|
temp[1] = vp[1];
|
|
temp[2] = vp[2];
|
|
temp[3] = vp[3];
|
|
temp[4] = 0;
|
|
zv = strtol(temp, (char **)NULL, 16);
|
|
}
|
|
*codes++ = 0x3c1aa000 | xv; // lui k0,A0xx
|
|
*codes++ = 0x241b0000 | zv; // li k1,zzzz
|
|
*codes++ = 0xa75b0000 | yv; // sh k1,yyyy(k0)
|
|
break;
|
|
case 0xCC:
|
|
// deactivate expansion ram using 3rd method
|
|
// CC000000 0000
|
|
if (cic_chip == CIC_6105)
|
|
*(vu32 *)0xA00003F0 = 0x00400000;
|
|
else
|
|
*(vu32 *)0xA0000318 = 0x00400000;
|
|
break;
|
|
case 0xD0:
|
|
// do next gs code if ram location is equal to 8-bit value
|
|
// D0XXYYYY 00ZZ
|
|
temp[0] = cp[2];
|
|
temp[1] = cp[3];
|
|
temp[2] = 0;
|
|
xv = strtol(temp, (char **)NULL, 16);
|
|
temp[0] = cp[4];
|
|
temp[1] = cp[5];
|
|
temp[2] = cp[6];
|
|
temp[3] = cp[7];
|
|
temp[4] = 0;
|
|
yv = strtol(temp, (char **)NULL, 16);
|
|
if (yv & 0x8000) xv++; // adjust for sign extension of yv
|
|
temp[0] = vp[2];
|
|
temp[1] = vp[3];
|
|
temp[2] = 0;
|
|
zv = strtol(temp, (char **)NULL, 16);
|
|
*codes++ = 0x3c1a8000 | xv; // lui k0,0x80xx
|
|
*codes++ = 0x835a0000 | yv; // lb k0,yyyy(k0)
|
|
*codes++ = 0x241b0000 | zv; // li k1,00zz
|
|
*codes++ = 0x175b0004; // bne k0,k1,4
|
|
*codes++ = 0x00000000; // nop
|
|
break;
|
|
case 0xD1:
|
|
// do next gs code if ram location is equal to 16-bit value
|
|
// D1XXYYYY 00ZZ
|
|
temp[0] = cp[2];
|
|
temp[1] = cp[3];
|
|
temp[2] = 0;
|
|
xv = strtol(temp, (char **)NULL, 16);
|
|
temp[0] = cp[4];
|
|
temp[1] = cp[5];
|
|
temp[2] = cp[6];
|
|
temp[3] = cp[7];
|
|
temp[4] = 0;
|
|
yv = strtol(temp, (char **)NULL, 16);
|
|
if (yv & 0x8000) xv++; // adjust for sign extension of yv
|
|
temp[0] = vp[0];
|
|
temp[1] = vp[1];
|
|
temp[2] = vp[2];
|
|
temp[3] = vp[3];
|
|
temp[4] = 0;
|
|
zv = strtol(temp, (char **)NULL, 16);
|
|
*codes++ = 0x3c1a8000 | xv; // lui k0,0x80xx
|
|
*codes++ = 0x875a0000 | yv; // lh k0,yyyy(k0)
|
|
*codes++ = 0x241b0000 | zv; // li k1,zzzz
|
|
*codes++ = 0x175b0004; // bne k0,k1,4
|
|
*codes++ = 0x00000000; // nop
|
|
break;
|
|
case 0xD2:
|
|
// do next gs code if ram location is not equal to 8-bit value
|
|
// D2XXYYYY 00ZZ
|
|
temp[0] = cp[2];
|
|
temp[1] = cp[3];
|
|
temp[2] = 0;
|
|
xv = strtol(temp, (char **)NULL, 16);
|
|
temp[0] = cp[4];
|
|
temp[1] = cp[5];
|
|
temp[2] = cp[6];
|
|
temp[3] = cp[7];
|
|
temp[4] = 0;
|
|
yv = strtol(temp, (char **)NULL, 16);
|
|
if (yv & 0x8000) xv++; // adjust for sign extension of yv
|
|
temp[0] = vp[2];
|
|
temp[1] = vp[3];
|
|
temp[2] = 0;
|
|
zv = strtol(temp, (char **)NULL, 16);
|
|
*codes++ = 0x3c1a8000 | xv; // lui k0,0x80xx
|
|
*codes++ = 0x835a0000 | yv; // lb k0,yyyy(k0)
|
|
*codes++ = 0x241b0000 | zv; // li k1,00zz
|
|
*codes++ = 0x135b0004; // beq k0,k1,4
|
|
*codes++ = 0x00000000; // nop
|
|
break;
|
|
case 0xD3:
|
|
// do next gs code if ram location is not equal to 16-bit value
|
|
// D3XXYYYY 00ZZ
|
|
temp[0] = cp[2];
|
|
temp[1] = cp[3];
|
|
temp[2] = 0;
|
|
xv = strtol(temp, (char **)NULL, 16);
|
|
temp[0] = cp[4];
|
|
temp[1] = cp[5];
|
|
temp[2] = cp[6];
|
|
temp[3] = cp[7];
|
|
temp[4] = 0;
|
|
yv = strtol(temp, (char **)NULL, 16);
|
|
if (yv & 0x8000) xv++; // adjust for sign extension of yv
|
|
temp[0] = vp[0];
|
|
temp[1] = vp[1];
|
|
temp[2] = vp[2];
|
|
temp[3] = vp[3];
|
|
temp[4] = 0;
|
|
zv = strtol(temp, (char **)NULL, 16);
|
|
*codes++ = 0x3c1a8000 | xv; // lui k0,0x80xx
|
|
*codes++ = 0x875a0000 | yv; // lh k0,yyyy(k0)
|
|
*codes++ = 0x241b0000 | zv; // li k1,zzzz
|
|
*codes++ = 0x135b0004; // beq k0,k1,4
|
|
*codes++ = 0x00000000; // nop
|
|
break;
|
|
case 0xDD:
|
|
// deactivate expansion ram using 2nd method
|
|
// DD000000 0000
|
|
if (cic_chip == CIC_6105)
|
|
*(vu32 *)0xA00003F0 = 0x00400000;
|
|
else
|
|
*(vu32 *)0xA0000318 = 0x00400000;
|
|
break;
|
|
case 0xDE:
|
|
// set game boot address
|
|
// DEXXXXXX 0000 => boot address = 800XXXXX, msn ignored
|
|
temp[0] = cp[2];
|
|
temp[1] = cp[3];
|
|
temp[2] = cp[4];
|
|
temp[3] = cp[5];
|
|
temp[4] = cp[6];
|
|
temp[5] = cp[7];
|
|
temp[6] = 0;
|
|
val = strtol(temp, (char **)NULL, 16);
|
|
bootAddr = 0xFFFFFFFF80000000LL | (val & 0xFFFFF);
|
|
break;
|
|
case 0xEE:
|
|
// deactivate expansion ram using 1st method
|
|
// EE000000 0000
|
|
if (cic_chip == CIC_6105)
|
|
*(vu32 *)0xA00003F0 = 0x00400000;
|
|
else
|
|
*(vu32 *)0xA0000318 = 0x00400000;
|
|
break;
|
|
case 0xF0:
|
|
// write 8-bit value to ram before boot
|
|
// F0XXXXXX 00YY
|
|
temp[0] = cp[2];
|
|
temp[1] = cp[3];
|
|
temp[2] = cp[4];
|
|
temp[3] = cp[5];
|
|
temp[4] = cp[6];
|
|
temp[5] = cp[7];
|
|
temp[6] = 0;
|
|
val = strtol(temp, (char **)NULL, 16);
|
|
val -= (bootAddr & 0xFFFFFF);
|
|
tp = (char *)(0xFFFFFFFFA02A0000LL + val);
|
|
if (gGSCodes[curr_cheat].mask)
|
|
{
|
|
val = gGSCodes[curr_cheat].value & gGSCodes[curr_cheat].mask;
|
|
}
|
|
else
|
|
{
|
|
temp[0] = vp[2];
|
|
temp[1] = vp[3];
|
|
temp[2] = 0;
|
|
val = strtol(temp, (char **)NULL, 16);
|
|
}
|
|
*tp = val & 0x00FF;
|
|
break;
|
|
case 0xF1:
|
|
// write 16-bit value to ram before boot
|
|
// F1XXXXXX YYYY
|
|
temp[0] = cp[2];
|
|
temp[1] = cp[3];
|
|
temp[2] = cp[4];
|
|
temp[3] = cp[5];
|
|
temp[4] = cp[6];
|
|
temp[5] = cp[7];
|
|
temp[6] = 0;
|
|
val = strtol(temp, (char **)NULL, 16);
|
|
val -= (bootAddr & 0xFFFFFF);
|
|
tp = (char *)(0xFFFFFFFFA02A0000LL + val);
|
|
if (gGSCodes[curr_cheat].mask)
|
|
{
|
|
val = gGSCodes[curr_cheat].value & gGSCodes[curr_cheat].mask;
|
|
}
|
|
else
|
|
{
|
|
temp[0] = vp[0];
|
|
temp[1] = vp[1];
|
|
temp[2] = vp[2];
|
|
temp[3] = vp[3];
|
|
temp[4] = 0;
|
|
val = strtol(temp, (char **)NULL, 16);
|
|
}
|
|
*tp++ = (val >> 8) & 0x00FF;
|
|
*tp = val & 0x00FF;
|
|
break;
|
|
case 0xFF:
|
|
// set code base
|
|
// FFXXXXXX 0000
|
|
temp[0] = cp[2];
|
|
temp[1] = cp[3];
|
|
temp[2] = cp[4];
|
|
temp[3] = cp[5];
|
|
temp[4] = cp[6];
|
|
temp[5] = cp[7];
|
|
temp[6] = 0;
|
|
val = strtol(temp, (char **)NULL, 16);
|
|
//codes = (vu32 *)(0xA0000000 | (val & 0xFFFFFF));
|
|
break;
|
|
}
|
|
}
|
|
curr_cheat++;
|
|
}
|
|
|
|
// generate jump to moved general int handler
|
|
*codes++ = 0x3c1a8000; // lui k0,0x8000
|
|
*codes++ = 0x375a0120; // ori k0,k0,0x120
|
|
*codes++ = 0x03400008; // jr k0
|
|
*codes++ = 0x00000000; // nop
|
|
|
|
// flush general int handler memory
|
|
data_cache_hit_writeback_invalidate((void *)0x80000120, 0x2E0);
|
|
inst_cache_hit_invalidate((void *)0x80000120, 0x2E0);
|
|
|
|
// flush os boot segment
|
|
data_cache_hit_writeback_invalidate((void *)0x802A0000, 0x100000);
|
|
|
|
// flush os boot segment memory
|
|
data_cache_hit_writeback_invalidate((void *)bootAddr, 0x100000);
|
|
inst_cache_hit_invalidate((void *)bootAddr, 0x100000);
|
|
}
|
|
|
|
// Copy low 0x1000 bytes to DMEM
|
|
//copy bootcode to RSP DMEM starting at 0xA4000040; <- bootaddr
|
|
src = (vu32 *)0xB0000000; //i think 0xB0000040; is the right value
|
|
dst = (vu32 *)0xA4000000; //0xA4000040;
|
|
for (ix=0; ix<(0x1000>>2); ix++)
|
|
dst[ix] = src[ix];
|
|
|
|
|
|
// Need to copy crap to IMEM for CIC-6105 boot.
|
|
dst = (vu32 *)0xA4001000;
|
|
|
|
// register values due to pif boot for CiC chip and country code, and IMEM crap
|
|
gGPR[0]=0x0000000000000000LL;
|
|
gGPR[6]=0xFFFFFFFFA4001F0CLL;
|
|
gGPR[7]=0xFFFFFFFFA4001F08LL;
|
|
gGPR[8]=0x00000000000000C0LL;
|
|
gGPR[9]=0x0000000000000000LL;
|
|
gGPR[10]=0x0000000000000040LL;
|
|
gGPR[11]=bootAddr; // 0xFFFFFFFFA4000040LL;
|
|
gGPR[16]=0x0000000000000000LL;
|
|
gGPR[17]=0x0000000000000000LL;
|
|
gGPR[18]=0x0000000000000000LL;
|
|
gGPR[19]=0x0000000000000000LL;
|
|
gGPR[21]=0x0000000000000000LL;
|
|
gGPR[26]=0x0000000000000000LL;
|
|
gGPR[27]=0x0000000000000000LL;
|
|
gGPR[28]=0x0000000000000000LL;
|
|
gGPR[29]=0xFFFFFFFFA4001FF0LL;
|
|
gGPR[30]=0x0000000000000000LL;
|
|
|
|
switch (country)
|
|
{
|
|
case 0x44: //Germany
|
|
case 0x46: //french
|
|
case 0x49: //Italian
|
|
case 0x50: //Europe
|
|
case 0x53: //Spanish
|
|
case 0x55: //Australia
|
|
case 0x58: // ????
|
|
case 0x59: // X (PAL)
|
|
{
|
|
|
|
if(force_tv!=0)
|
|
*(u32 *) 0x80000300 = force_tv; //pal
|
|
else
|
|
*(u32 *) 0x80000300 = 2;
|
|
|
|
switch (cic_chip)
|
|
{
|
|
case CIC_6102:
|
|
gGPR[5]=0xFFFFFFFFC0F1D859LL;
|
|
gGPR[14]=0x000000002DE108EALL;
|
|
gGPR[24]=0x0000000000000000LL;
|
|
break;
|
|
case CIC_6103:
|
|
gGPR[5]=0xFFFFFFFFD4646273LL;
|
|
gGPR[14]=0x000000001AF99984LL;
|
|
gGPR[24]=0x0000000000000000LL;
|
|
break;
|
|
case CIC_6105:
|
|
dst[0x04>>2] = 0xBDA807FC;
|
|
gGPR[5]=0xFFFFFFFFDECAAAD1LL;
|
|
gGPR[14]=0x000000000CF85C13LL;
|
|
gGPR[24]=0x0000000000000002LL;
|
|
break;
|
|
case CIC_6106:
|
|
gGPR[5]=0xFFFFFFFFB04DC903LL;
|
|
gGPR[14]=0x000000001AF99984LL;
|
|
gGPR[24]=0x0000000000000002LL;
|
|
break;
|
|
}
|
|
|
|
gGPR[20]=0x0000000000000000LL;
|
|
gGPR[23]=0x0000000000000006LL;
|
|
gGPR[31]=0xFFFFFFFFA4001554LL;
|
|
break;
|
|
}
|
|
case 0x37: // 7 (Beta)
|
|
case 0x41: // ????
|
|
case 0x45: //USA
|
|
case 0x4A: //Japan
|
|
|
|
if(force_tv!=0)
|
|
*(u32 *) 0x80000300 = force_tv; //pal
|
|
else
|
|
*(u32 *) 0x80000300 = 1; //ntsc
|
|
|
|
default:
|
|
{
|
|
switch (cic_chip)
|
|
{
|
|
case CIC_6102:
|
|
gGPR[5]=0xFFFFFFFFC95973D5LL;
|
|
gGPR[14]=0x000000002449A366LL;
|
|
break;
|
|
case CIC_6103:
|
|
gGPR[5]=0xFFFFFFFF95315A28LL;
|
|
gGPR[14]=0x000000005BACA1DFLL;
|
|
break;
|
|
case CIC_6105:
|
|
dst[0x04>>2] = 0x8DA807FC;
|
|
gGPR[5]=0x000000005493FB9ALL;
|
|
gGPR[14]=0xFFFFFFFFC2C20384LL;
|
|
break;
|
|
case CIC_6106:
|
|
gGPR[5]=0xFFFFFFFFE067221FLL;
|
|
gGPR[14]=0x000000005CD2B70FLL;
|
|
break;
|
|
}
|
|
|
|
gGPR[20]=0x0000000000000001LL;
|
|
gGPR[23]=0x0000000000000000LL;
|
|
gGPR[24]=0x0000000000000003LL;
|
|
gGPR[31]=0xFFFFFFFFA4001550LL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
switch (cic_chip)
|
|
{
|
|
case CIC_6101:
|
|
gGPR[22]=0x000000000000003FLL;
|
|
break;
|
|
case CIC_6102:
|
|
gGPR[1]=0x0000000000000001LL;
|
|
gGPR[2]=0x000000000EBDA536LL;
|
|
gGPR[3]=0x000000000EBDA536LL;
|
|
gGPR[4]=0x000000000000A536LL;
|
|
gGPR[12]=0xFFFFFFFFED10D0B3LL;
|
|
gGPR[13]=0x000000001402A4CCLL;
|
|
gGPR[15]=0x000000003103E121LL;
|
|
gGPR[22]=0x000000000000003FLL;
|
|
gGPR[25]=0xFFFFFFFF9DEBB54FLL;
|
|
break;
|
|
case CIC_6103:
|
|
gGPR[1]=0x0000000000000001LL;
|
|
gGPR[2]=0x0000000049A5EE96LL;
|
|
gGPR[3]=0x0000000049A5EE96LL;
|
|
gGPR[4]=0x000000000000EE96LL;
|
|
gGPR[12]=0xFFFFFFFFCE9DFBF7LL;
|
|
gGPR[13]=0xFFFFFFFFCE9DFBF7LL;
|
|
gGPR[15]=0x0000000018B63D28LL;
|
|
gGPR[22]=0x0000000000000078LL;
|
|
gGPR[25]=0xFFFFFFFF825B21C9LL;
|
|
break;
|
|
case CIC_6105:
|
|
dst[0x00>>2] = 0x3C0DBFC0;
|
|
dst[0x08>>2] = 0x25AD07C0;
|
|
dst[0x0C>>2] = 0x31080080;
|
|
dst[0x10>>2] = 0x5500FFFC;
|
|
dst[0x14>>2] = 0x3C0DBFC0;
|
|
dst[0x18>>2] = 0x8DA80024;
|
|
dst[0x1C>>2] = 0x3C0BB000;
|
|
gGPR[1]=0x0000000000000000LL;
|
|
gGPR[2]=0xFFFFFFFFF58B0FBFLL;
|
|
gGPR[3]=0xFFFFFFFFF58B0FBFLL;
|
|
gGPR[4]=0x0000000000000FBFLL;
|
|
gGPR[12]=0xFFFFFFFF9651F81ELL;
|
|
gGPR[13]=0x000000002D42AAC5LL;
|
|
gGPR[15]=0x0000000056584D60LL;
|
|
gGPR[22]=0x0000000000000091LL;
|
|
gGPR[25]=0xFFFFFFFFCDCE565FLL;
|
|
break;
|
|
case CIC_6106:
|
|
gGPR[1]=0x0000000000000000LL;
|
|
gGPR[2]=0xFFFFFFFFA95930A4LL;
|
|
gGPR[3]=0xFFFFFFFFA95930A4LL;
|
|
gGPR[4]=0x00000000000030A4LL;
|
|
gGPR[12]=0xFFFFFFFFBCB59510LL;
|
|
gGPR[13]=0xFFFFFFFFBCB59510LL;
|
|
gGPR[15]=0x000000007A3C07F4LL;
|
|
gGPR[22]=0x0000000000000085LL;
|
|
gGPR[25]=0x00000000465E3F72LL;
|
|
break;
|
|
}
|
|
|
|
|
|
// set HW registers
|
|
IO_WRITE(PI_STATUS_REG, 0x03);
|
|
switch (cart)
|
|
{
|
|
case 0x4258: // 'BX' - Battle Tanx
|
|
|
|
IO_WRITE(PI_BSD_DOM1_LAT_REG, 0x80);
|
|
IO_WRITE(PI_BSD_DOM1_RLS_REG, 0x37);
|
|
IO_WRITE(PI_BSD_DOM1_PWD_REG, 0x12);
|
|
IO_WRITE(PI_BSD_DOM1_PGS_REG, 0x40);
|
|
|
|
break;
|
|
|
|
case 0x4237: // 'B7' - Banjo Tooie
|
|
|
|
IO_WRITE(PI_BSD_DOM1_LAT_REG, 0x80);
|
|
IO_WRITE(PI_BSD_DOM1_RLS_REG, 0x37);
|
|
IO_WRITE(PI_BSD_DOM1_PWD_REG, 0x12);
|
|
IO_WRITE(PI_BSD_DOM1_PGS_REG, 0x40);
|
|
|
|
break;
|
|
|
|
|
|
case 0x5A4C: // 'ZL' - Zelda OOT
|
|
|
|
/*
|
|
IO_WRITE(PI_BSD_DOM2_LAT_REG, 0x00000005);
|
|
IO_WRITE(PI_BSD_DOM2_PWD_REG, 0x0000000C);
|
|
IO_WRITE(PI_BSD_DOM2_PGS_REG, 0x0000000D);
|
|
IO_WRITE(PI_BSD_DOM2_RLS_REG, 0x00000002);
|
|
*/
|
|
|
|
/* unstable
|
|
IO_WRITE(PI_BSD_DOM1_LAT_REG, 0x00000040);
|
|
IO_WRITE(PI_BSD_DOM1_RLS_REG, 0x00803712);
|
|
IO_WRITE(PI_BSD_DOM1_PWD_REG, 0x00008037);
|
|
IO_WRITE(PI_BSD_DOM1_PGS_REG, 0x00000803);
|
|
*/
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
load immediate:
|
|
|
|
li register_destination, value
|
|
#load immediate value into destination register
|
|
|
|
---
|
|
|
|
Registers in coprocessor 0 cannot be used directly by MIPS instructions. Instead, there are two
|
|
instructions that work much like load and store instructions. The mfc0 (move from coprocessor 0) instruction
|
|
loads data from a coprocessor 0 register into a CPU register. The mtc0 likewise stores data in a cp0 register.
|
|
|
|
Note
|
|
|
|
The mtc0 instruction, like the store instruction has the destination last. This is especially important to note,
|
|
since the syntax for cp0 registers looks the same as the syntax for CPU registers. For example, the following copies
|
|
the contents of CPU register 13 to cp0 register 12.
|
|
mtc0 $13, $12
|
|
|
|
|
|
mthi 010001 MoveTo hi = $s
|
|
|
|
|
|
LUI -- Load upper immediate
|
|
|
|
Description:
|
|
The immediate value is shifted left 16 bits and stored in the register. The lower 16 bits are zeroes.
|
|
Operation:
|
|
$t = (imm << 16); advance_pc (4);
|
|
Syntax:
|
|
lui $t, imm
|
|
Encoding:
|
|
0011 11-- ---t tttt iiii iiii iiii iiii
|
|
|
|
* */
|
|
|
|
// now set MIPS registers - set CP0, and then GPRs, then jump thru gpr11 (which is usually 0xA400040)
|
|
if (!gCheats)
|
|
|
|
asm(".set noat\n\t"
|
|
".set noreorder\n\t"
|
|
"li $8,0x34000000\n\t"
|
|
"mtc0 $8,$12\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"li $9,0x0006E463\n\t"
|
|
"mtc0 $9,$16\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"li $8,0x00005000\n\t"
|
|
"mtc0 $8,$9\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"li $9,0x0000005C\n\t"
|
|
"mtc0 $9,$13\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"li $8,0x007FFFF0\n\t"
|
|
"mtc0 $8,$4\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"li $9,0xFFFFFFFF\n\t"
|
|
"mtc0 $9,$14\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"mtc0 $9,$8\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"mtc0 $9,$30\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"lui $8,0\n\t"
|
|
"mthi $8\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"mtlo $8\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"ctc1 $8,$31\n\t"
|
|
"nop\n\t"
|
|
"lui $31,0xA03E\n\t"
|
|
//"lui $31,0xA008\n\t"
|
|
"ld $1,0x08($31)\n\t"
|
|
"ld $2,0x10($31)\n\t"
|
|
"ld $3,0x18($31)\n\t"
|
|
"ld $4,0x20($31)\n\t"
|
|
"ld $5,0x28($31)\n\t"
|
|
"ld $6,0x30($31)\n\t"
|
|
"ld $7,0x38($31)\n\t"
|
|
"ld $8,0x40($31)\n\t"
|
|
"ld $9,0x48($31)\n\t"
|
|
"ld $10,0x50($31)\n\t"
|
|
"ld $11,0x58($31)\n\t"
|
|
"ld $12,0x60($31)\n\t"
|
|
"ld $13,0x68($31)\n\t"
|
|
"ld $14,0x70($31)\n\t"
|
|
"ld $15,0x78($31)\n\t"
|
|
"ld $16,0x80($31)\n\t"
|
|
"ld $17,0x88($31)\n\t"
|
|
"ld $18,0x90($31)\n\t"
|
|
"ld $19,0x98($31)\n\t"
|
|
"ld $20,0xA0($31)\n\t"
|
|
"ld $21,0xA8($31)\n\t"
|
|
"ld $22,0xB0($31)\n\t"
|
|
"ld $23,0xB8($31)\n\t"
|
|
"ld $24,0xC0($31)\n\t"
|
|
"ld $25,0xC8($31)\n\t"
|
|
"ld $26,0xD0($31)\n\t"
|
|
"ld $27,0xD8($31)\n\t"
|
|
"ld $28,0xE0($31)\n\t"
|
|
"ld $29,0xE8($31)\n\t"
|
|
"ld $30,0xF0($31)\n\t"
|
|
"ld $31,0xF8($31)\n\t"
|
|
"jr $11\n\t"
|
|
"nop"
|
|
::: "$8" );
|
|
|
|
|
|
|
|
|
|
else
|
|
asm(".set noreorder\n\t"
|
|
"li $8,0x34000000\n\t"
|
|
"mtc0 $8,$12\n\t"
|
|
"nop\n\t"
|
|
"li $9,0x0006E463\n\t"
|
|
"mtc0 $9,$16\n\t"
|
|
"nop\n\t"
|
|
"li $8,0x00005000\n\t"
|
|
"mtc0 $8,$9\n\t"
|
|
"nop\n\t"
|
|
"li $9,0x0000005C\n\t"
|
|
"mtc0 $9,$13\n\t"
|
|
"nop\n\t"
|
|
"li $8,0x007FFFF0\n\t"
|
|
"mtc0 $8,$4\n\t"
|
|
"nop\n\t"
|
|
"li $9,0xFFFFFFFF\n\t"
|
|
"mtc0 $9,$14\n\t"
|
|
"nop\n\t"
|
|
"mtc0 $9,$30\n\t"
|
|
"nop\n\t"
|
|
"lui $8,0\n\t"
|
|
"mthi $8\n\t"
|
|
"nop\n\t"
|
|
"mtlo $8\n\t"
|
|
"nop\n\t"
|
|
"ctc1 $8,$31\n\t"
|
|
"nop\n\t"
|
|
"li $9,0x00000183\n\t"
|
|
"mtc0 $9,$18\n\t"
|
|
"nop\n\t"
|
|
"mtc0 $zero,$19\n\t"
|
|
"nop\n\t"
|
|
"lui $8,0xA03C\n\t"
|
|
"la $9,2f\n\t"
|
|
"la $10,9f\n\t"
|
|
".set noat\n"
|
|
"1:\n\t"
|
|
"lw $2,($9)\n\t"
|
|
"sw $2,($8)\n\t"
|
|
"addiu $8,$8,4\n\t"
|
|
"addiu $9,$9,4\n\t"
|
|
"bne $9,$10,1b\n\t"
|
|
"nop\n\t"
|
|
"lui $8,0xA03C\n\t"
|
|
"jr $8\n\t"
|
|
"nop\n"
|
|
"2:\n\t"
|
|
"lui $9,0xB000\n\t"
|
|
"lw $9,8($9)\n\t"
|
|
"lui $8,0x2000\n\t"
|
|
"or $8,$8,$9\n\t"
|
|
"lui $9,0xA02A\n\t"
|
|
"lui $10,0xA03A\n\t"
|
|
"3:\n\t"
|
|
"lw $2,($9)\n\t"
|
|
"sw $2,($8)\n\t"
|
|
"addiu $8,$8,4\n\t"
|
|
"addiu $9,$9,4\n\t"
|
|
"bne $9,$10,3b\n\t"
|
|
"nop\n\t"
|
|
"lui $31,0xA03E\n\t"
|
|
"ld $1,0x08($31)\n\t"
|
|
"ld $2,0x10($31)\n\t"
|
|
"ld $3,0x18($31)\n\t"
|
|
"ld $4,0x20($31)\n\t"
|
|
"ld $5,0x28($31)\n\t"
|
|
"ld $6,0x30($31)\n\t"
|
|
"ld $7,0x38($31)\n\t"
|
|
"ld $8,0x40($31)\n\t"
|
|
"ld $9,0x48($31)\n\t"
|
|
"ld $10,0x50($31)\n\t"
|
|
"ld $11,0x58($31)\n\t"
|
|
"ld $12,0x60($31)\n\t"
|
|
"ld $13,0x68($31)\n\t"
|
|
"ld $14,0x70($31)\n\t"
|
|
"ld $15,0x78($31)\n\t"
|
|
"ld $16,0x80($31)\n\t"
|
|
"ld $17,0x88($31)\n\t"
|
|
"ld $18,0x90($31)\n\t"
|
|
"ld $19,0x98($31)\n\t"
|
|
"ld $20,0xA0($31)\n\t"
|
|
"ld $21,0xA8($31)\n\t"
|
|
"ld $22,0xB0($31)\n\t"
|
|
"ld $23,0xB8($31)\n\t"
|
|
"ld $24,0xC0($31)\n\t"
|
|
"ld $25,0xC8($31)\n\t"
|
|
"ld $26,0xD0($31)\n\t"
|
|
"ld $27,0xD8($31)\n\t"
|
|
"ld $28,0xE0($31)\n\t"
|
|
"ld $29,0xE8($31)\n\t"
|
|
"ld $30,0xF0($31)\n\t"
|
|
"ld $31,0xF8($31)\n\t"
|
|
"jr $11\n\t"
|
|
"nop\n"
|
|
"9:\n"
|
|
::: "$8" );
|
|
}
|