The Ichidan Collection part #1
What is ucode?
---[By Ichidan:18-12-98]---
What is ucode?
ucode is microcode (u means micro or meu). The Micro code is instructions which tell the RSP (Reality Signal Processor) what to do. They are in the same format as normal instructions like:
lui $T0,$a440
ori $T0,$10
etc
however, they tend to use the CO-Processors a lot more.
Remember, Graphics Display Lists (GFX *glistp; etc) are NOT the same as Micro Code. The difference being that micro code is just ASM code which is designed to be executed by the Signal Processor (SP) instead of by the natural CPU. It might be faster or slower I have No Idea.
The OSTask struct looks like this:
~~(extracted from ultra.zip "sptask.h")~~
typedef struct {
u32 type; // 0x0
u32 flags; // 0x4
u64 *ucode_boot; // 0x8
u32 ucode_boot_size; // 0xC
u64 *ucode; // 0x10
u32 ucode_size; // 0x14
u64 *ucode_data; // 0x18
u32 ucode_data_size; // 0x1C
u64 *dram_stack; // 0x20
u32 dram_stack_size; // 0x24
u64 *output_buff; // 0x28
u64 *output_buff_size; // 0x2C
u64 *data_ptr; // 0x30
u32 data_size; // 0x34
u64 *yield_data_ptr; // 0x38
u32 yield_data_size; // 0x3C
} OSTask_t; // All varibles above are 4 bytes wide totaling a 64 byte structure.
typedef union {
OSTask_t t;
long long int force_structure_alignment;
} OSTask;
The values which should be supplied to the OSTask structure are:
.ucode_boot = "RSPBOOT.Obj" <--- found in this file (n64devkit)
.ucode_boot_size = 208; // Just the RspBootTextEnd-RspBootTextStart.
.ucode = "GSPFASt3d.Obj" <--- found in this file (n64devkit) gspFast3DTextStart
.ucode_size = 4096;
.ucode_data = "GSPFast3d.Obj" <--- found in this file (n64devkit) gspFast3DDataStart
.ucode_data_size = 2048;
.data_ptr = glistp; <--- Points to the start of the graphics display list. (You make this up).
.data_size = glistpfinal-glistp; // Just the size of the Graphics display list.
***SP Task Registers***
The SP Task Registers are their to control N64 ucode lists.
Mainly for 3d Operations.
<Graphics Display Lists>
These are instructions in a TOTALLY different language to N64
Traditional Fixed Instructions like LUI,ADDIU etc (32-bits wide).
The Graphics Display Lists & Audio Lists are 64-bits wide instructions.
Only The Reality CoProcessor can understand these instructions.
Commands like 3d Triangles are comprised as follows:
*****************
cmd:8; // 8 bit command code for Triangle.
pad:24; // 24 bit dummy filler. (all 0's)
flag:8; // Triangle Flags.
v0:8; // Vertex 0's info
v1:8; // Vertex 1's info
v2:8; // Vertex 2's info
*****************
Now you may look at the above coding and think how can the RealityCop
understand that.
Well it decodes to this:
cmd:8; // Code which is equal to: -65 (0xbf);
pad:24; // Dummy filler equals: 0x000000;
------>
flag:8; // 0,1 or 2 <- this tells RealityCop which Vertex's color to use.
v0:8; // These refer to a vertex from 0 - 255 in the
v1:8; // internal vertex buffer which must be loaded by
v2:8; // another ucode function (a DMA transfer one)
-- The Vertex Transfer DMA ucode is this:
cmd:8; // 4 (0x04) means G_VTX;
vert:8; // bits 7-4 are (# de vertices = [1 to 16]-1)
// bits 3-0 are (Starting Vertex # to Store from)
len:16; // Bytes to transfer (Vertex_Size*Vertices)
------>
ptr:32; // 32-bit pointer - pointing to the Vertex Data e.g 0x8020..
**********************************************************************
Now thats been briefly explained, heres how to transfer Graphics lists etc.
These are in the lowest & simplist level possible.
Ok we know that at 0xA400:0000 - 0xA400:0FFF [DMEM] Data
0xA400:1000 - 0xA400:1FFF [IMEM] 64-bit wide Instrs.
Now 'osSpTaskStart(OSTask *ptr);' is a macro comprising of:
osSpTaskLoad(OSTask *taskptr);
osSpTaskStartGo(OSTask *taskptr);
So what we would do is:
***************************************************************
1) Generate a Graphics Display List (gbi.h in ultra.zip) contains
every macro code for this.
or Generate a Audio List (abi.h in ultra.zip).
2) use osSpTaskLoad(Taskptr address);
3) use osSpTaskStartGo(Taskptr address);
4) And then you will have to check the SP & DP interface status regs.
and wait till they have completed the job.
(Anarko's Opcode list contains the Registers)
***************************************************************
This document is aimed at those who want to make 3d Fx and audio stuff
using just pure ASM. It could be useful if someone wants to make a
trainer or intro for a game and wants the 3d fx!!!!!!!!!
Also for the people who are just curious about Reality Cop Stuff!!!!
Remember that when translating the structure OSTask.
*The u64 pointers are 4 bytes long since they are 32-bit pointers.
They would only be 8bytes long (64-bits) if they were just allocated
varibles. The Structure is exactly 64 bytes wide!!!!!!!!!!!
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
osSpTaskStart(OSTask *Taskptr)
{
osSpTaskLoad(&Taskptr);
osSpTaskStartGo(&Taskptr);
}
osSpTaskLoad(OSTask *Taskptr)
{
OSTask *tptr; // new mashable ptr.
// OSTask is a union which refers to OSTask_t t;
// So it should be Taskptr.t.???;
// But this keeps it simple.
// (1) We Check some things!
if(Taskptr.dram_stack&0xf) return; // Error: Ptr must be divisible by 16.
if(Taskptr.output_buff&0xf) return; // Error: Ptr must be divisible by 16.
if(Taskptr.output_buff_sizeptr&0xf) return; // Error: Ptr must be divisible by 16.
if(Taskptr.yield_data_ptr&0xf) return; // Error: Ptr must be divisible by 16.
tptr = (u32 *) SPFix(&Taskptr); // Fixes & copies the Taskptr to a tempobuff!
if(tptr.flags&1)
{
tptr.ucode_data = (u32 *) tptr.yield_data_ptr;
tptr.ucode_data_size = tptr.yield_data_size;
Taskptr.flags&=0xfffe; // Origs' - All bits but odd/even bit (0)
}
CacheIt(&tptr,64); // Caches the OSTask.
SPstatus(0x2b00);
while(SPpc(0x04001000)==-1);
while(SPdma(1,0x04000fc0,&tptr,64)==-1); // copies 'OSTask' 64-byte struct!
while(SPbusy()); // Wait for SP regs to finish transfer. unreq'ed
while(SPdma(1,0x04001000,tptr.ucode_boot,tptr.ucode_boot_size)==-1); // Copies the Boot Code!
}
/* Sub Funcs */
OSTask Mybuff; // 64 byte temporary task ptr allocated!!
*OSTask SPFix(OSTask *Taskptr)
{
// Function copies Original Taskptr to a temporary one.
// Then fixes up Tempo. one
// Mybuff would be a 64 byte buffer!
COPYDATA(&Taskptr,&Mybuff,64);
if(Mybuff.ucode)
{
Mybuff.ucode = GET_PHYSICAL(Mybuff.ucode);
}
if(Mybuff.ucode_data)
{
Mybuff.ucode_data = GET_PHYSICAL(Mybuff.ucode_data);
}
if(Mybuff.dram_stack)
{
Mybuff.dram_stack = GET_PHYSICAL(Mybuff.dram_stack);
}
if(Mybuff.output_buff)
{
Mybuff.output_buff = GET_PHYSICAL(Mybuff.output_buff);
}
if(Mybuff.output_buff_size)
{
Mybuff.output_buff_size = GET_PHYSICAL(Mybuff.output_buff_size);
}
if(Mybuff.data_ptr)
{
Mybuff.data_ptr = GET_PHYSICAL(Mybuff.data_ptr);
}
if(Mybuff.yield_data_ptr)
{
Mybuff.yield_data_ptr = GET_PHYSICAL(Mybuff.yield_data_ptr);
}
return &Mybuff; // Address for SpTaskLoad to Use.
}
void COPYDATA(source ptr, dest ptr, amount to do)
{
pretty much common sense really!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Do what you want here!!!!!!!!!!!!!!!!
}
u32 GET_PHYSICAL(u32 inaddr)
{
if(inaddr>=0x80000000 && inaddr<0xA0000000)
return inaddr&0x1fffffff; // Bring to Physical address. Kseg0 - > Phys
if(inaddr>=0xA0000000 && inaddr<0xC0000000)
return inaddr&0x1fffffff; // Bring to Physical address. Kseg1 - > Phys
// If Still in then claim Error.
Error(inaddr); // Complain About the Error, Thats If you wanna waste time coding!!!
}
void CacheIt(u32 ptr,u32 size) // Caching Process.
{
u32 temp,temp2;
if(size<1) return;
if(size<8192)
{
temp = ptr-(ptr&0xf); // temp = ptr masked as: ~11110000]
while(temp<ptr+size)
{
asm move T0,temp
asm cache 25,$0(T0)
temp+=16;
}
}
else {
temp = 0x80000000; // Start of RDRAM memory.
temp2 = 0x80000000;
while(temp<temp2+8192)
{
asm move T0,temp
asm cache 1,$0(T0)
temp+=16;
}
}
}
void SPstatus(u32 control)
{
u32 *ptr = (u32 *) 0xa4040010;
ptr[0] = control;
}
int SPpc(u32 program_start)
{
u32 *ptr = (u32 *) 0xa4040010; // Status/Controll.
if(ptr[0]&1)
{
ptr = (u32 *) 0xa4080000; // Program Counter Reg.
ptr[0] = program_start;
return 0; // Ok
}
else return -1; // Not Ready.
}
int SPdma(u32 dir,u32 SPmem,u32 RDRAM,u32 len)
{
u32 newRDRAMvalue;
u32 *ptr = (u32 *) 0xa4040000; // General SP
if(SPmem&7) Error("SPmem address is bad etc. (Too Bumpy)");
if(RDRAM&7) Error("RDRAM address is bad etc. (Too Bumpy)");
if(len&7) Error("len is bad value. etc. (Too Bumpy)");
if(SPbusy()) return -1; // Not Ready.
ptr[0] = SPmem; // SPmemory is stored (12-bit value = 4k range) + 12thbit is [0/1]=[D/I]mem
newRDRAMvalue = 0xAD70(RDRAM);
ptr[1] = newRDRAMvalue; // (0xa4040004) = RDRAM address.
if(dir) ptr[2] = len-1; // 0xa4040008 (RDRAM - > [D/I]mem)
else ptr[3] = len-1; // 0xa404000C (RDRAM < - [D/I]mem)
return 0; // Ok
}
int SPbusy(void)
{
u32 *ptr = (u32 *) 0xa4040010;
if(ptr[0]&0x1c) return 1; // Something's busy:-
// Dma busy,Dma Full,Io Full
else return 0;
}
osSpTaskStartGo(OSTask *Taskptr)
{
u32 *ptr = (u32 *) 0xa4040010; // Control/status reg.
ptr[0] = 0x125; // Clr Halt. (0)
// Clr Broke. (2)
// Clr SStep. (5)
// Set Intr on Brk. (8)
}
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
What you need:-
ucode_boot = 'This can be located in the n64dev\LIBS\OBJ\rspboot.obj'
use: dumpobj [filename.ext] /c to extract the boot out (0x2f -> 0xff) 208 bytes
ucode_boot_size = 208;
ucode = Graphics/Audio Micro Code (.type M_GFX(1) or audio(0) controls this)
ucode_size = size of micro-code to transfer.
Go fishing to find the other params.
*Remember the ucode_boot (208 bytes/26 instrs methinks) tells the Reality Signal Processor (RSP) what to transfer by refering to the DMEM (0xa400:0FC0->0xa400:0FFF) which contains the OSTask info. Nice Idea Nintendo!!
---[By Ichidan:18-12-98]---
"Smash Brothers Crack"'Cracked
---[By Ichidan:21-2-99]---
"Smash Brothers Crack"'Cracked
#Note:
***None of the code listed below requires any DevKit Stuff or GNU***
***You Can Code it into ASM pretty straight-forward (i think:-!)***
There are some cool stuff you'll find listed below, such as:
i) Setting up the N64 video mode (into 320x240-16bitcolours etc.)
ii) Controlling the Audio Interface.
iii) Getting input from the Controller Port.
#How I did it:
"I used the Intro Liberator on Dextrose to extract the intro that
Titanik/CZN coded for Smash Bro's Crack. Then I simply read through
about 2k of code (512 instructions), ignoring the french text and stuff
like "FUCK YOU" <-- Thats at 0x4AB0. The Tool which I used to read the
code was debug.........yeeaahh right, naaaa I used NIEW by Titanik/CZN."
#Time Taken: 4 hours - same time it takes to code the intro fresh!
#Legend:
[*] Means Functions which are probably not used
[!@#$] Means Code that I haven't bothered to translate in to pseudo code.
W[address] Means Load/Store To this address (WORD32)
H[address] Means Load/Store To this address (HALFWORD16)
B[address] Means Load/Store To this address (BYTE8)
WU[address] Means Load/Store To this address (WORD32) - unsigned
HU[address] Means Load/Store To this address (HALFWORD16) - unsigned
BU[address] Means Load/Store To this address (BYTE8) - unsigned
--------0x1000--------- Start of Code:
.org $8012fff8
vidbuff1 EQU $80151430
vidbuff2 EQU $801A9230
//IMAGEPTR EQU $80135A88
audiobuf EQU $a01ddb5c
void mainproc(void)
{
// ****************************************************************
// ******************************************************************
// **** Start of init code: ****
// ******************************************************************
// ****************************************************************
// [1] Set up Stack
SP = 0x803f:ff00; // Usual Stack Set up!
// [2] Set up Video mode - pointing to correct buffer
video_init(2,vidbuff1); // JAL 130E88 (0x1e90 NIEW) //
goto 0x12cc;
***DATA***
"String Of french text"
***DATA***
0x12cc:
// [3] Prevent Audio from playing anything. & Also setup the tune pointer
// this is so that they know what position in the 16-bit wave to add the tune at.
// initially being 0 for the start.
AudioTuneSetup(0x801cea80); // JAL 130974 (0x197C NIEW) "Audio & Audio vars."
// [4] Waits 200*64k clock cycles "using the below method for waiting"
//"repeat <200*64k> " <-- Just a waiting thing. probably for video-screen to refresh, Audio, Controllers, etc.
lui T0,$C8
repeat: bne T0,Rzero,repeat
addi T0,T0,$ffff
// [5] Decompresses the Audio - maybe it's just audio in a different format or something.
// This is just to start the process (maybe the compressed format is just midi or mod)
// 0xa01ddb5c
DecompressAudio(audiobuf); // JAL 130A2C (1A34 NIEW)
// [6] Clear Video Interrupt line!!!
~~[0x12f8:]~~
W[0xA440:0010] = 0 (Clears Interrupt Line)
// [7] CRACK maybe?
// Im not so sure if these lines crack the Smash Brothers.
// it's just a guess, but you can see that they are changing up
// some code!!!!!
; "The Cracking Process" **********************************
"SMASHBRO'S"@0xA002:5C00 = 0x3c08800f "LUI T0,$800f" <--- Crack Smash Bro's
"SMASHBRO'S"@0xA002:5C04 = 0x25080A40 "ADDIU T0,T0,$0A40" <--- Crack Smash Bro's
"SMASHBRO'S"@0xA002:5C08 = 0x3C090003 "LUI T1,$0003" <--- Crack Smash Bro's
lui T0,$A002 ; These 3 lines
ori T0,$5C00 ; just cache the altered SIMM memory:
cache $10,$0(T0) ; A002:5C00 -> 5C0F [16 bytes always]
; Done ****************************************************
~~[0x133c:]~~
// [8] initialise a controller register otherwise program will run for
// a few seconds and then Crash!! as Titanik Explained in Anarko's Opcode
// stuff!!
controller_init();//jal $130E74 (i think you must add 0x1008 to each jal to get real pos)
~~[0x1344:]~~
// ----------------------------------------------------------------- //
// Graphical Clearing Buffers etc. ---------------------------------
~~[0x1344]~~
// Clear Video Buffers (Theres two probably for page flipping!!!) //
T1 = vidbuff1; // 0x80151430
T4 = vidbuff2; // 0x801A9230
T2 = 320*240*2; // SIZE OF VIEW BUFFER (IN BYTES) [0x25800 or 153600 bytes]
while(T2)
{
*T1 = 0x000c000c; // A nice colour (0,0,6) Slightly Blue!!
*T4 = 0x000c000c; // Same applies to both vid buffers.
T1+=4;
T4+=4;
T2-=4;
}
~~[0x137c]~~
// Clear image Buffer
T1 = imagebuffer; // 0x8017B5B0
T2 = 32640 // 320x100 (256 indexed colours)
while(T2)
{
*T1 = 0; // Wipe that image buffer
T1+=4;
T2-=4;
}
~~[0x1398]~~
// Build that Image divider thing. Maybe I'm not sure.
A0 = imagedivider; // 0x8017B0B0
T1 = 159; // (160-1)*4 (320 pixels)
while(T1)
{
*A0 = 0x007e007e; // (0,1,31) Mainly Blue with a tint of Green.
T1--;
}
~~[0x13BC]~~
// Same as above i presume.
A0 = imagedivider2 // 0x80173A30
T1 = 159; // (160-1)*4 (320 pixels)
while(T1)
{
*A0 = 0x007e007e; // (0,1,31)
T1--;
}
~~[0x13E0]~~
// CZN IMAGE adjuster
// Gets CZN image and turns black/transparant pixels to background colour
// bg colour is (0x000c) or (0,0,6) Slightly Blue
T0 = IMAGEPTR; // 0x80135A88 CZN image!! [0x6A90 NIEW address]
T1 = 320*120*2; // 76,800 16-bit (I know it must be 16-bit due to the way it deals with the data)
while(T1)
{
T2 = *T0; // As a halfword unsigned
if(!T2) *T0 = 0x000c; // As a halfword.
else *T0 = T2&0xfffe;
T0+=2;
T1-=2;
}
~~[0x1410]~~
// ****************************************************************
// ******************************************************************
// **** End of init code: ****
// ******************************************************************
// ****************************************************************
// -------------------------------------------------------------------
// ****************************************************************
// ******************************************************************
// **** Start of main loop: ****
// ******************************************************************
// ****************************************************************
// Titanik's typical "some_name equ some_register thingy"
S7 = 14; // These have other EQU names. like pcx_width maybe etc.
S6 = 0;
S1 = 0;
S2 = 0;
mainloop: // 0x1420
"Controller Send Data is @[0x1420]" It's been mashed into main code!!
// This code sends out a request to the N64 SI interface telling
// the controllers what to do.
// The Request is listed below in the 64-byte pif1 code.
[0xa480:0000] = 0x0013:0f80; (&pif1) // Starting RDRAM Address. (0x80130f80)
[0xa480:0010] = 0x1fc0:07c0; // SI address write 64b
// Wait for Vertical Retrace Sync.
waitVI:
"Audio Get info" // This bit checks if the dma buffer can hold an extra 3520 bytes of audio.
// if it's finished then stream some more on.
~~[0x1440]~~
// This code makes sure that the video scan line is above 192
// Reason: 192 down is probably invisible on TV, Hence you can draw
// all over the screen and display won't be seen till it loops around.
// Thats the normal concept of Waiting for the Vsync.
// *Also It would be a good idea to add more audio if posible.
// Since the N64 plays the audio in the buffer and you can also tell it
// to play another one (Which will be played after current one has finished)
// Cool, eh?
T1 = [0xa450:000C]&0x8000; // Check if buffer len full?
if(T1) goto bufferlenfull;
~~[0x1458]~~
W[0x801d:db58]^=1; // Xors with 1;
DecompressAudio(audiobuf+audiopos); // JAL 130A18 (1A2c NIEW) slightly different to other one.
~~[0x148c]~~ // Stream some more audio.
// 0xa01ddb5c = audiobuf, 0x801ddb58 = audiopos
[0xa450:0000]=audiobuf + audiopos; // starting RDRAM Address.
[0xa450:0008]=1; // enable dma
[0xa450:0010]=0x465; // AI DAC rate
[0xa450:0014]=15; // BIT RATE:16 (15+1)
[0xa450:0004]=3520; // AI Length.
bufferlenfull:
~~[0x14c8]~~
currentline = [0xa440:0010]&0x1ff;
if(currentline<384) goto waitVI; // goto 0x1440
// The following is just code which probably does the text scroller
////////////////////////////
// [!@#$] Scroller Code: (0x14c8 to 0x16e8)
////////////////////////////
// Controller Receive Data:
~~[0x16e8]~~
W[0xa480:0000] = 0x0014:8688;(&pif2) // Starting Address (DEST)
W[0xa480:0004] = 0x1fc007c0; // Get The 64-byte Controller data and store it in an address.
if(BU[0xbfc0:07ff]) goto pushed_start; // I think this is if theres no controllers in, then just jump straight in!!
if(HU[0xbfc0:07c4]&0x1000) goto pushed_start; // if Cont1->START
~~[0x1734]~~
goto mainloop; // beq Rzero,Rzero 0x1420;
// ****************************************************************
// ******************************************************************
// **** End of main loop: ****
// ******************************************************************
// ****************************************************************
pushed_start: // 0x173c -- This is the code of what happens when you press Start!
"FADE SCREEN TO BLACK" (0x173c - 0x17d0)
~~[0x17d0]~~
// "RePatch Up ROM CODE"
W[0xA000:0400] = 0x3c088004; // LUI $T0,$8004
W[0xA000:0404] = 0x3c090005; // LUI $T1,$0005
W[0xA000:0408] = 0x2508FEC0; // ADDIU $T0,$T0,$FEC0
W[0xA000:040C] = 0x3529FB20; // ORI $T1,$T1,$FB20
W[0xA000:0624] = 0x3c04B0D8; // LUI $A0,$B0D8
~~[0x1820]~~
Writes Word(0x0000FFFF) to [0xA400:0000-0xA400:1ffc] 8k total (Both D/I-MEM)
^This means that the 0xA400:0000 area will look like this:
00,00,FF,FF,00,00,FF,FF,00,00,FF,FF....
W[0xA400:1000] = 0x000017d7; // First IMEM CODE.
W[0xA000:0310] = 0x000017d7;
W[0xA000:0008] = 0xB0000000; // org/PC = 0xB0000000;
W[0xA460:0010] = 2; // PI reg. Clear Interrupt.
Copies Code from (0xB0D804C0-0xB0D80768) to (0xA000:0000) "Word by Word"
goto execute_rom;
// Some code in here
// Don't know if actually gets round to executing.
// NOTE: The Titanik/CZN style of doing Intro's involves
// changing CODE up itself. So you could find code which
// doesn't make sense but when run works perfectly.
execute_rom:
$T0 = $A000:0400;
jr $T0 // Executes the code!!!.
} (197c)
void AudioTuneSetup(void) // 0x197C NIEW address. Audio Related Function
{
W[0x801DDA88] = 6; // maybe beats
W[0x801DDA8C] = 0; // maybe cycles.
W[0x801DDA90] = 0;
W[0x801DDA98] = 0;
W[0x801DDA94] = 0;
W[0x801DDA9C] = 0; // maybe beat no
T1 = 0x40; // Blanks out an array 64 u32's long!
while(T1)
{
T0 = 0x801DDAA0;
W[T0] = 0;
T0+=4;
T1--;
}
T0 = W[0x801DDA8C]; //
T1 = BU[0x801CEAA0+T0]; // BU = Byte Unsigned
W[0x801DDA90] = T1;
W[0xA4500000] = 0x80000000; // Starting RDRAM Address Audio.
W[0xA4500008] = 1; // ENABLE DMA TRANSFER
W[0xA4500010] = 0xD000; // AI DAC RATE
W[0xA4500014] = 1; // AI BIT RATE
W[0xA4500004] = 0; // AI LENGTH = 0;
} (1a18)
// audiobuf = 0xa01ddb5c
// 0x801cea80 EQU Perhaps Audio Length.
void DecompressAudio(audiobuf *ptr) // 0x1a2c (NIEW) something's wierd here about the jump address.
{ // I think it should start at 1a20
// Think the function just transfers a chunk of audio data from one location to another (i.e to audiobuf *ptr).
// Since this function is BIG (0x400 bytes - 256 instructions long)
// I presume it decodes XMI/MID/MOD/SNG -> WAV (The tune gives it away)
W[0x801dda9c]++;
~~[0x1a44]~~
if(W[0x801dda9c]<W[0x801dda88]) goto skip;
W[0x801dda9c]=0; // Restart beat # again or whatever it is!!
W[0x801dda8c]++;
? W[0x801dda90] = BU[0x801ceaa0]+W[0x801dda8c]];
if(W[0x801cea80]!=W[0x801dda8c]) goto skip;0x1ac4
W[0x801dda8c] = 0; // Reset a counter.
skip:
~~[0x1ac4]~~
if([0x801dda9c]) goto skip2;0x1c7c
// [!@#$] lots more code to sniff out
skip2:0x1c7c
// [!@#$] and here too.
} (0x1e74)
~~[0x1e7c:]~~
void controller_init(void)
{
addiu T0,Rzero,$0008
lui AT,$bfc0
sw T0,$7fc(AT) ; Clear Buttons
} (0x1e88)
~~[0x1e90:]~~
void video_init(A0,A1 (video buffer ptr))
{
// (Writes to all VI words from 0x00 - 0x34)
// Only first two are parameter controlled.
[0xa440:0000] = 0x00013000|A0; // These are reserved bits although
// video_init() is called up with A0=2
// This means 5/5/5/3 (16-bit color)
[0xa440:0004] = A1 (video buffer ptr); // This is where the VI interface scans.
[0xa440:0008] = 320; // 320 pixels width.
[0xa440:000C] = 2; // 2 "interrupt when current half line = 2 i.e 1st line"
[0xa440:0010] = 0; // Clear interrupt line
[0xa440:0014] = 0x03e52239; // VI burst/timing reg. can't be bothered to decipher it.
[0xa440:0018] = 525; // 525 hlines per field.
[0xa440:001C] = 0xC15; // 3093 total duration of a line in 1/4 pixel
[0xa440:0020] = 0x0C150C15; // Horiz. sync leap period.
[0xa440:0024] = 0x006C02EC; // Horiz. start/end of active video.
[0xa440:0028] = 0x002501ff; // Vert. start/end of active video.
[0xa440:002C] = 0x000E0204; // VI vertical burst End of Colour Burst: 516th Hline (258)
// Start of Colour Burst: 14th Hline (7)
[0xa440:0030] = 512; // (1/0.5) Horiz Scale Up Factor. 2.10bit point.
[0xa440:0034] = 1024; // (1/1) Vert Scale Up Factor. 2.10bit point.
} (0x1f20)
0x00001f88 -> +64 bytes: (0x0013:0f80) in N64 memory.
pif1: DW $FF010401
DW $00000000
DW $FF010401
DW $00000000
DW $FF010401
DW $00000000
DW $FF010401
DW $00000000
DW $FE000000
DW $00000000
DW $00000000
DW $00000000
DW $00000000
DW $00000000
DW $00000000
DW $00000001
[*]void Somekindacontrollerfunc(void)
{
~~[0x2048:]~~ "Controller Regarded"
siwait:
T0 = W[0xbfc0:07fc]&0x80; // Some kinda status value
if(T0) goto siwait; // Waits for bit'7 to be set to 0
T0 = W[0xbfc0:07c0+0x24] // From here T0 is the Status of ~"0x24"
S3 = (T0>>13)&1; // Bit'13 Req'ed
S7 = (T0>>12)&1; // Bit'12 Req'ed
if(S3)
{
T3 = 0xA600:0000;
}
S6 = (T0>>8)&0xff; // High Order of ~"0x24"
T2 = (T0&0xff); // Low Order of ~"0x24"
S5 = (T0>>11)&1; // bit'11 of ~"0x24"
// Here we want to set some bit settings. **************
T0 = W[0xbfc0:07c0+0x3c]&0x10; // status bit'4
siwait2:
T1 = W[0xA480:0018]&2; // SI Reg Status [IO rd busy==1]
if(T1) goto siwait2; // Waits until IO rd not busy.
W[0xbfc0:07c0+0x3c]=T0;
//////////////////////////////////////////// **************
~~[0x20bc:]~~ "More PI reg regarded" UNKNOWN
W[0xa460:0014] = 0xff; // dom1 device latency set to 0xff
W[0xa460:0018] = 0xff; // dom1 device width set to 0xff
W[0xa460:001C] = 0x0f; // dom1 page size set to 0xf
W[0xa460:0020] = 0x03; // dom1 release duration set to 3
T1 = W[0xa600:0000]; // Cart Dom1
~~[0x20dc:]~~
[!@#$] These lines have been left out at the mo aswell.
} (0x21c4)
[*]void Somekindacontrollerfunc2&alsoAbitcrazy(A0)
{
~~[0x25b4]~~
T0 = W[0xbfc0:07f0]&0xffff0000; // bits 16-31 req'd
A0&=0xffff; // input value trapped
A0|=T0;
siwait:
T1 = W[0xA480:0018]&2; // SI Reg Status [IO rd busy==1]
if(T1) goto siwait; // Waits until IO rd not busy.
W[0xbfc0:07f0]=A0; // Update the bit control setting.
(0x174-0xE8)/4 NOPS (A long NOP waiting period about 1.5 NIEW SCREENS
T3 = 0xA400:0040 // SP Task Data Buffer a.k.a BOOT/HEADER Buffer
jr T3 // Executes The Whole BOOT!!!
S6 = 0x91 (145)
}
[*]void DefinatelyROMexecutiontypecode(void) Reason: Relates to 0xb000:0008 <--Program Counter Start e.g 0x80246000
{
~~[0x2690]~~
[!@#$] Haevn't even bothered with this one
}
~~[0x6a90]~~
// 0x80135A88 CZN image!! [0x6A90 NIEW address]
IMAGEPTR
Crazy Nation Image which hovers on the screen!!!
(320x120x16-bit RAW image)
76,800bytes (75k)
~~[0x19690]~~
// 0x80148688 (End of CZN image)
~~[0x19690]~~
// Blank (00h) chunk where the pif2 is stored.
pif2: DW 0,0,0,0,0,0,0,0 ;by words we mean 32bits!
DW 0,0,0,0,0,0,0,0 ;I think this is 64 bytes..
~~[0x216D0]~~
20h,"CRAZY NATION! GIVES YOU THE CRACK FOR...."
~~[0x21d04]~~
20h,20h,'#' <-- I think that the hash just terminates the string.
"You are not supposed to read this....Ripping is lame etc."
>>>>>>I say... Everyone Rips code from everyone else, especially from
Nintendo (c)!!!!!!, If They don't Rip code then they use documents
which were made by code rippers in the first PLACE!!!!!!!And If
they don't use documents then they are stupid!!!!!!!!<<<<<<
~~[0x22440]~~ "End Of Crack/Intro"
---[By Ichidan:21-2-99]---