This page includes information regarding the decompilation of the SEQ format and how it is parsed.
The file begins with a 16 byte header. Only the first three four-byte words are used. The last four bytes are always zero. The values of each word used by SEQ files in the game are:
First word
- 0x01
- 0x02
- 0x04
- 0x05
- 0x06
- 0x07
- 0x08
- 0x09
- 0x0C
- 0x0E
- 0x10
- 0x11
- 0x16
- 0x1F
Second Word
- 0x0010
- 0x0020
- 0x0025
- 0x0026
- 0x0027
- 0x0028
- 0x0029
- 0x002A
- 0x002B
- 0x002C
- 0x002D
- 0x002E
- 0x0035
- 0x0040
- 0x004E
- 0x006C
- 0x01A0
- 0x01B0
- 0x0A48
Third Word
- 0x10
- 0x20
- 0x40
The file loading.seq
for example has the first three words: 00 00 00 0E 00 00 00 40 00 00 00 40
, or 0xE, 0x40, and 0x40.
The specific calculation at 0x800c991c is:
void SEQ_Setup(seq_stuff *stuff,int seq_word_one,int seq_word_two,int seq_word_three)
{
void *reg_p_sp;
stuff->seq_word_one = seq_word_one + 1;
stuff->seq_word_two = seq_word_two;
stuff->seq_word_three = seq_word_three;
stuff->size = stuff->seq_word_two + ((stuff->seq_word_one * 0x60) >> 2) + stuff->seq_word_three * (stuff->seq_word_one + -1);
/* Allocate memory for the SEQ, multiply by 4 (<< 2)
likely because size is the number of 4-byte ints */
reg_p_sp = F_LoadMalloc(&HEAP_STRUCT,stuff->size << 2); // start of reg_p->sp
stuff->reg_p_sp = reg_p_sp;
stuff->end_of_reg_p_sp = (stuff->reg_p_sp + stuff->seq_word_one * 0x60);
stuff->field10_0x1c = stuff->end_of_reg_p_sp + stuff->seq_word_two * 4;
/* Null out all of reg_p->sp */
Runtime.PPCEABI.H::memset(stuff->reg_p_sp,0,stuff->seq_word_one * 0x60);
return;
}
So using loading.seq
this would be:
void SEQ_Setup(seq_stuff *stuff, 0xE, 0x40, 0x40)
{
void *reg_p_sp;
stuff->seq_word_one = 0xE + 1; // 0xF
stuff->seq_word_two = 0x40;
stuff->seq_word_three = 0x40;
stuff->size = 0x40 + ((0xF * 0x60) >> 2) + 0x40 * (0xF + -1); // 0x528
reg_p_sp = F_LoadMalloc(&HEAP_STRUCT,stuff->size << 2); // 0x528 << 2 = 0x14A0
stuff->reg_p_sp = reg_p_sp;
stuff->end_of_reg_p_sp = (stuff->reg_p_sp + 0xF * 0x60); // 0xF * 0x60 = 0x5A0
stuff->field10_0x1c = stuff->end_of_reg_p_sp + 0x40 * 4; // 0x40 * 4 = 0x100
Runtime.PPCEABI.H::memset(stuff->reg_p_sp, 0, 0xF * 0x60); // 0xF * 0x60 = 0x5A0
return;
}
Here are the headers of each SEQ file in the game:
Headers
00000011 00000a48 00000040 00000000 /files/chr/ank/0000.seq
00000007 00000028 00000040 00000000 /files/chr/ank/0010.seq
00000001 00000027 00000040 00000000 /files/chr/ank/1000.seq
00000011 00000a48 00000040 00000000 /files/chr/bou/0000.seq
00000007 00000028 00000040 00000000 /files/chr/bou/0010.seq
00000001 0000002c 00000040 00000000 /files/chr/bou/1000.seq
00000011 00000a48 00000040 00000000 /files/chr/cho/0000.seq
00000007 00000028 00000040 00000000 /files/chr/cho/0010.seq
00000001 00000026 00000040 00000000 /files/chr/cho/1000.seq
00000001 0000004e 00000040 00000000 /files/chr/cmn/1000.seq
00000011 00000a48 00000040 00000000 /files/chr/dog/0000.seq
00000007 00000028 00000040 00000000 /files/chr/dog/0010.seq
00000001 00000025 00000040 00000000 /files/chr/dog/1000.seq
00000011 00000a48 00000040 00000000 /files/chr/gai/0000.seq
00000007 00000028 00000040 00000000 /files/chr/gai/0010.seq
00000001 0000002c 00000040 00000000 /files/chr/gai/1000.seq
00000011 00000a48 00000040 00000000 /files/chr/gar/0000.seq
00000007 00000028 00000040 00000000 /files/chr/gar/0010.seq
00000001 0000002c 00000040 00000000 /files/chr/gar/1000.seq
00000011 00000a48 00000040 00000000 /files/chr/hak/0000.seq
00000007 00000028 00000040 00000000 /files/chr/hak/0010.seq
00000001 00000025 00000040 00000000 /files/chr/hak/1000.seq
00000011 00000a48 00000040 00000000 /files/chr/hi2/0000.seq
00000007 00000028 00000040 00000000 /files/chr/hi2/0010.seq
00000001 0000002c 00000040 00000000 /files/chr/hi2/1000.seq
00000011 00000a48 00000040 00000000 /files/chr/hin/0000.seq
00000007 00000028 00000040 00000000 /files/chr/hin/0010.seq
00000001 00000025 00000040 00000000 /files/chr/hin/1000.seq
00000011 00000a48 00000040 00000000 /files/chr/ino/0000.seq
00000007 00000028 00000040 00000000 /files/chr/ino/0010.seq
00000001 00000029 00000040 00000000 /files/chr/ino/1000.seq
00000011 00000a48 00000040 00000000 /files/chr/iru/0000.seq
00000007 00000028 00000040 00000000 /files/chr/iru/0010.seq
00000001 00000025 00000040 00000000 /files/chr/iru/1000.seq
00000011 00000a48 00000040 00000000 /files/chr/ita/0000.seq
00000007 00000028 00000040 00000000 /files/chr/ita/0010.seq
00000001 00000028 00000040 00000000 /files/chr/ita/1000.seq
00000011 00000a48 00000040 00000000 /files/chr/jir/0000.seq
00000007 00000028 00000040 00000000 /files/chr/jir/0010.seq
00000001 00000025 00000040 00000000 /files/chr/jir/1000.seq
00000011 00000a48 00000040 00000000 /files/chr/kab/0000.seq
00000007 00000028 00000040 00000000 /files/chr/kab/0010.seq
00000001 00000026 00000040 00000000 /files/chr/kab/1000.seq
00000011 00000a48 00000040 00000000 /files/chr/kak/0000.seq
00000007 00000028 00000040 00000000 /files/chr/kak/0010.seq
00000001 0000002c 00000040 00000000 /files/chr/kak/1000.seq
00000011 00000a48 00000040 00000000 /files/chr/kan/0000.seq
00000007 00000028 00000040 00000000 /files/chr/kan/0010.seq
00000001 00000025 00000040 00000000 /files/chr/kan/1000.seq
00000011 00000a48 00000040 00000000 /files/chr/kar/0000.seq
00000007 00000028 00000040 00000000 /files/chr/kar/0010.seq
00000001 00000026 00000040 00000000 /files/chr/kar/1000.seq
00000011 00000a48 00000040 00000000 /files/chr/kib/0000.seq
00000007 00000028 00000040 00000000 /files/chr/kib/0010.seq
00000001 00000025 00000040 00000000 /files/chr/kib/1000.seq
00000011 00000a48 00000040 00000000 /files/chr/kid/0000.seq
00000007 00000028 00000040 00000000 /files/chr/kid/0010.seq
00000001 00000035 00000040 00000000 /files/chr/kid/1000.seq
00000011 00000a48 00000040 00000000 /files/chr/kim/0000.seq
00000007 00000028 00000040 00000000 /files/chr/kim/0010.seq
00000001 0000002d 00000040 00000000 /files/chr/kim/1000.seq
00000011 00000a48 00000040 00000000 /files/chr/kis/0000.seq
00000007 00000028 00000040 00000000 /files/chr/kis/0010.seq
00000001 00000026 00000040 00000000 /files/chr/kis/1000.seq
00000011 00000a48 00000040 00000000 /files/chr/loc/0000.seq
00000007 00000028 00000040 00000000 /files/chr/loc/0010.seq
00000001 00000029 00000040 00000000 /files/chr/loc/1000.seq
00000011 00000a48 00000040 00000000 /files/chr/miz/0000.seq
00000007 00000028 00000040 00000000 /files/chr/miz/0010.seq
00000001 00000025 00000040 00000000 /files/chr/miz/1000.seq
00000011 00000a48 00000040 00000000 /files/chr/na9/0000.seq
00000007 00000028 00000040 00000000 /files/chr/na9/0010.seq
00000001 0000002d 00000040 00000000 /files/chr/na9/1000.seq
00000011 00000a48 00000040 00000000 /files/chr/nar/0000.seq
00000007 00000028 00000040 00000000 /files/chr/nar/0010.seq
00000001 0000002e 00000040 00000000 /files/chr/nar/1000.seq
00000011 00000a48 00000040 00000000 /files/chr/nej/0000.seq
00000007 00000028 00000040 00000000 /files/chr/nej/0010.seq
00000001 0000002b 00000040 00000000 /files/chr/nej/1000.seq
00000011 00000a48 00000040 00000000 /files/chr/obo/0000.seq
00000007 00000028 00000040 00000000 /files/chr/obo/0010.seq
00000001 00000025 00000040 00000000 /files/chr/obo/1000.seq
00000011 00000a48 00000040 00000000 /files/chr/oro/0000.seq
00000007 00000028 00000040 00000000 /files/chr/oro/0010.seq
00000001 00000029 00000040 00000000 /files/chr/oro/1000.seq
00000011 00000a48 00000040 00000000 /files/chr/sa2/0000.seq
00000007 00000028 00000040 00000000 /files/chr/sa2/0010.seq
00000001 00000029 00000040 00000000 /files/chr/sa2/1000.seq
00000011 00000a48 00000040 00000000 /files/chr/sak/0000.seq
00000007 00000028 00000040 00000000 /files/chr/sak/0010.seq
00000001 00000027 00000040 00000000 /files/chr/sak/1000.seq
00000011 00000a48 00000040 00000000 /files/chr/sar/0000.seq
00000007 00000028 00000040 00000000 /files/chr/sar/0010.seq
00000001 00000028 00000040 00000000 /files/chr/sar/1000.seq
00000011 00000a48 00000040 00000000 /files/chr/sas/0000.seq
00000007 00000028 00000040 00000000 /files/chr/sas/0010.seq
00000001 0000002b 00000040 00000000 /files/chr/sas/1000.seq
00000011 00000a48 00000040 00000000 /files/chr/sik/0000.seq
00000007 00000028 00000040 00000000 /files/chr/sik/0010.seq
00000001 00000025 00000040 00000000 /files/chr/sik/1000.seq
00000011 00000a48 00000040 00000000 /files/chr/sin/0000.seq
00000007 00000028 00000040 00000000 /files/chr/sin/0010.seq
00000001 00000026 00000040 00000000 /files/chr/sin/1000.seq
00000011 00000a48 00000040 00000000 /files/chr/sko/0000.seq
00000007 00000028 00000040 00000000 /files/chr/sko/0010.seq
00000001 0000002a 00000040 00000000 /files/chr/sko/1000.seq
00000011 00000a48 00000040 00000000 /files/chr/ta2/0000.seq
00000007 00000028 00000040 00000000 /files/chr/ta2/0010.seq
00000001 00000025 00000040 00000000 /files/chr/ta2/1000.seq
00000011 00000a48 00000040 00000000 /files/chr/tay/0000.seq
00000007 00000028 00000040 00000000 /files/chr/tay/0010.seq
00000001 00000028 00000040 00000000 /files/chr/tay/1000.seq
00000011 00000a48 00000040 00000000 /files/chr/tem/0000.seq
00000007 00000028 00000040 00000000 /files/chr/tem/0010.seq
00000001 00000028 00000040 00000000 /files/chr/tem/1000.seq
00000011 00000a48 00000040 00000000 /files/chr/ten/0000.seq
00000007 00000028 00000040 00000000 /files/chr/ten/0010.seq
00000001 00000026 00000040 00000000 /files/chr/ten/1000.seq
00000011 00000a48 00000040 00000000 /files/chr/tsu/0000.seq
00000007 00000028 00000040 00000000 /files/chr/tsu/0010.seq
00000001 0000002d 00000040 00000000 /files/chr/tsu/1000.seq
00000011 00000a48 00000040 00000000 /files/chr/zab/0000.seq
00000007 00000028 00000040 00000000 /files/chr/zab/0010.seq
00000001 00000025 00000040 00000000 /files/chr/zab/1000.seq
00000002 000001b0 00000040 00000000 /files/furu/f_camera.seq
00000002 000001a0 00000040 00000000 /files/game/camera00.seq
00000002 000001a0 00000040 00000000 /files/game/camera01.seq
00000006 0000006c 00000040 00000000 /files/game/game00.seq
00000010 00000020 00000020 00000000 /files/game/m_entry.seq
0000000c 00000040 00000040 00000000 /files/game/m_vs.seq
00000001 00000010 00000010 00000000 /files/game/player00.seq
00000006 00000040 00000040 00000000 /files/kuro/button.seq
0000000e 00000040 00000040 00000000 /files/kuro/loading.seq
00000001 00000010 00000010 00000000 /files/kuro/tmode.seq
0000000c 00000040 00000040 00000000 /files/maki/charsel4.seq
00000008 00000040 00000040 00000000 /files/maki/char_sel.seq
00000008 00000040 00000040 00000000 /files/maki/m_gal.seq
00000005 00000040 00000040 00000000 /files/maki/m_nfile.seq
00000006 00000040 00000040 00000000 /files/maki/m_nsiki.seq
00000007 00000040 00000040 00000000 /files/maki/m_sndplr.seq
0000001f 00000040 00000040 00000000 /files/maki/m_title.seq
00000008 00000040 00000040 00000000 /files/maki/m_viewer.seq
00000008 0000006c 00000020 00000000 /files/stg/001/0000.seq
00000004 00000040 00000020 00000000 /files/stg/001/0100.seq
00000009 0000006c 00000020 00000000 /files/stg/002/0000.seq
00000004 00000040 00000020 00000000 /files/stg/002/0100.seq
00000008 0000006c 00000020 00000000 /files/stg/003/0000.seq
00000004 00000040 00000020 00000000 /files/stg/003/0100.seq
00000008 0000006c 00000020 00000000 /files/stg/004/0000.seq
00000004 00000040 00000020 00000000 /files/stg/004/0100.seq
00000008 0000006c 00000020 00000000 /files/stg/005/0000.seq
00000004 00000040 00000020 00000000 /files/stg/005/0100.seq
00000008 0000006c 00000020 00000000 /files/stg/006/0000.seq
00000004 00000040 00000020 00000000 /files/stg/006/0100.seq
00000008 0000006c 00000020 00000000 /files/stg/007/0000.seq
00000004 00000040 00000020 00000000 /files/stg/007/0100.seq
00000008 0000006c 00000020 00000000 /files/stg/008/0000.seq
00000004 00000040 00000020 00000000 /files/stg/008/0100.seq
00000008 0000006c 00000020 00000000 /files/stg/009/0000.seq
00000004 00000040 00000020 00000000 /files/stg/009/0100.seq
00000008 0000006c 00000020 00000000 /files/stg/010/0000.seq
00000004 00000040 00000020 00000000 /files/stg/010/0100.seq
00000008 0000006c 00000020 00000000 /files/stg/011/0000.seq
00000004 00000040 00000020 00000000 /files/stg/011/0100.seq
00000008 0000006c 00000020 00000000 /files/stg/012/0000.seq
00000004 00000040 00000020 00000000 /files/stg/012/0100.seq
00000008 0000006c 00000020 00000000 /files/stg/013/0000.seq
00000004 00000040 00000020 00000000 /files/stg/013/0100.seq
00000008 0000006c 00000020 00000000 /files/stg/014/0000.seq
00000004 00000040 00000020 00000000 /files/stg/014/0100.seq
00000008 0000006c 00000020 00000000 /files/stg/015/0000.seq
00000004 00000040 00000020 00000000 /files/stg/015/0100.seq
00000008 0000006c 00000020 00000000 /files/stg/016/0000.seq
00000004 00000040 00000020 00000000 /files/stg/016/0100.seq
00000008 0000006c 00000020 00000000 /files/stg/017/0000.seq
00000004 00000040 00000020 00000000 /files/stg/017/0100.seq
00000008 0000006c 00000020 00000000 /files/stg/019/0000.seq
00000005 00000040 00000020 00000000 /files/stg/019/0100.seq
00000008 0000006c 00000020 00000000 /files/stg/020/0000.seq
00000004 00000040 00000020 00000000 /files/stg/020/0100.seq
00000008 0000006c 00000020 00000000 /files/stg/021/0000.seq
00000004 00000040 00000020 00000000 /files/stg/021/0100.seq
00000008 0000006c 00000020 00000000 /files/stg/022/0000.seq
00000004 00000040 00000020 00000000 /files/stg/022/0100.seq
00000008 0000006c 00000020 00000000 /files/stg/023/0000.seq
00000004 00000040 00000020 00000000 /files/stg/023/0100.seq
00000008 0000006c 00000020 00000000 /files/stg/024/0000.seq
00000004 00000040 00000020 00000000 /files/stg/024/0100.seq
00000008 0000006c 00000020 00000000 /files/stg/025/0000.seq
00000004 00000040 00000020 00000000 /files/stg/025/0100.seq
00000008 0000006c 00000020 00000000 /files/stg/026/0000.seq
00000004 00000040 00000020 00000000 /files/stg/026/0100.seq
00000008 0000006c 00000020 00000000 /files/stg/027/0000.seq
00000004 00000040 00000020 00000000 /files/stg/027/0100.seq
00000008 0000006c 00000020 00000000 /files/stg/028/0000.seq
00000004 00000040 00000020 00000000 /files/stg/028/0100.seq
00000008 0000006c 00000020 00000000 /files/stg/029/0000.seq
00000004 00000040 00000020 00000000 /files/stg/029/0100.seq
00000008 0000006c 00000020 00000000 /files/stg/030/0000.seq
00000004 00000040 00000020 00000000 /files/stg/030/0100.seq
00000008 0000006c 00000020 00000000 /files/stg/031/0000.seq
00000004 00000040 00000020 00000000 /files/stg/031/0100.seq
00000008 0000006c 00000020 00000000 /files/stg/032/0000.seq
00000004 00000040 00000020 00000000 /files/stg/032/0100.seq
00000016 00000040 00000040 00000000 /files/story/s00.seq
00000016 00000040 00000040 00000000 /files/story/s01.seq
00000016 00000040 00000040 00000000 /files/story/s02.seq
00000016 00000040 00000040 00000000 /files/story/s03.seq
00000016 00000040 00000040 00000000 /files/story/s04.seq
00000016 00000040 00000040 00000000 /files/story/s05.seq
00000016 00000040 00000040 00000000 /files/story/s06.seq
00000016 00000040 00000040 00000000 /files/story/s07.seq
00000016 00000040 00000040 00000000 /files/story/s08.seq
00000016 00000040 00000040 00000000 /files/story/s09.seq
00000016 00000040 00000040 00000000 /files/story/s0e.seq
00000016 00000040 00000040 00000000 /files/story/s10.seq
00000016 00000040 00000040 00000000 /files/story/s11.seq
00000016 00000040 00000040 00000000 /files/story/s12.seq
00000016 00000040 00000040 00000000 /files/story/s13.seq
00000016 00000040 00000040 00000000 /files/story/s14.seq
00000016 00000040 00000040 00000000 /files/story/s15.seq
00000016 00000040 00000040 00000000 /files/story/s16.seq
00000016 00000040 00000040 00000000 /files/story/s17.seq
00000016 00000040 00000040 00000000 /files/story/s18.seq
00000016 00000040 00000040 00000000 /files/story/s19.seq
00000016 00000040 00000040 00000000 /files/story/s1e.seq
00000016 00000040 00000040 00000000 /files/story/s20.seq
00000016 00000040 00000040 00000000 /files/story/s21.seq
00000016 00000040 00000040 00000000 /files/story/s22.seq
00000016 00000040 00000040 00000000 /files/story/s23.seq
00000016 00000040 00000040 00000000 /files/story/s24.seq
Before it is used, a SEQ file will first be initialized. This calls the function at 0x80099388 I call seq_init()
. It takes three arguments.
- The String of the SEQ file to be read, without the .seq extension. e.g.
"maki/charsel4"
- An unknown integer used during initialization of the seq initialization struct.
- An unused value. Likely used during development.
This function will read the header and initialize a struct based on it.
seq_init_struct
seq_init_struct[0x0] = 0
seq_init_struct[0x1] = 0 (appears to have originally been used for something is no longer used)
seq_init_struct[0x2] = (SEQ Header Word 2) + (((SEQ Header Word 1 + 1) * 0x60) >> 2) + SEQ Header Word 1
seq_init_struct[0x3] = 0
seq_init_struct[0x4] = SEQ Header Word 1 + 1;
seq_init_struct[0x5] = SEQ Header Word 2
seq_init_struct[0x6] = SEQ Header Word 3
seq_init_struct[0x7] = Pointer made using 80222ba8 and seq_init_struct[0x2]
seq_init_struct[0x8] = seq_init_struct[7] + seq_init_struct[4] * 0x60
seq_init_struct[0x9] = seq_init_struct[8] + seq_init_struct[5] * 4
seq_init_struct[0xA] = pointer to something related to the file extension
seq_init_struct[0xb] = pointer to beginning of seq file data
seq_init_struct[0xc] = 0
seq_init_struct[0xd] = 0
seq_init_struct[0xe] = 0
seq_init_struct[0xf] = 0
seq_init_struct[0x10] = 0
Many pointers appear to be set after this based on the number of SEQ Header Word 1 using numbers derived from SEQ Header Word 2 and 3
Opcodes are read from the seq file in the seq_parse method. Each full opcode is four bytes long. The first byte defines the opcode group and the second byte defines the opcode within that opcode group to use. The third and fourth byte may be used to additionally configure the full opcode.
Each opcode will jump to code in the game to execute. It uses the following function to find the code to execute:
// Find the opcode group method
0x802103a0 + (opcode >> 0x16 & 0x3fc)
By bit shifting by 0x16, it multiplies the top byte by four. This is because each pointer is four bytes long, so we need the opcode group index multiplied by four. It is &'d with 0x3fc (001111111100
in binary) in order to force it to be a multiple of four.
So for example:
- Read opcode, e.g.
0x01320000
(00000001001100100000000000000000
in binary) - Use bit shifting to get the top 10 bits, the binary
0000000100
in this case. - & it with
0x3fc
(001111111100
in binary) - For this example, that doesn't change the value and it stays as
100
in binary, or 4 in hex. - This value is added as an offset to
0x802103a0
, which is a location to a pointer table in memory. - For this example, we get the final value
0x800a5698
, which is the second pointer in the opcode pointer table.
The highest value that can come from this math is 0x3fc
, so the opcode pointer table is between 0x802103a0
and 0x8021079C
Opcode Pointer Table
Opcode | Offset | Code Pointer | Purpose |
---|---|---|---|
0x0 | 0x0 | 800A6068 | SEQ_CmdSEQ1 |
0x1 | 0x4 | 800A5698 | SEQ_CmdSEQ2 |
0x2 | 0x8 | 800A52F8 | SEQ_CmdTSK |
0x3 | 0xc | 800A51B0 | SEQ_CmdREG |
0x4 | 0x10 | 800A4B40 | SEQ_CmdI |
0x5 | 0x14 | 800A44C4 | SEQ_CmdIC |
0x6 | 0x18 | 800A3ED4 | SEQ_CmdIS |
0x7 | 0x1c | 800A3888 | SEQ_CmdIL |
0x8 | 0x20 | 800A32C0 | SEQ_CmdF |
0x9 | 0x24 | 800A2A8C | SEQ_CmdP |
0xa | 0x28 | 800A274C | SEQ_CmdIV |
0xb | 0x2c | 800A1C5C | SEQ_CmdFV |
0xc | 0x30 | 800A1894 | SEQ_CmdFM |
0xd | 0x34 | 800A188C | SEQ_CmdRGB |
0xe | 0x38 | 800AA9B8 | SEQ_CmdMEM |
0xf | 0x3c | 800AA430 | SEQ_CmdFILE |
0x10 | 0x40 | 800A9C1C | SEQ_CmdGOBJ |
0x11 | 0x44 | 800A99F0 | SEQ_CmdOBJ |
0x12 | 0x48 | 800A8E68 | |
0x13 | 0x4c | 800A8594 | |
0x14 | 0x50 | 800A76EC | |
0x15 | 0x54 | 800A75C0 | SEQ_CmdPAUSE |
0x16 | 0x58 | 800A7204 | Sounds |
0x17 | 0x5c | 800A713C | |
0x18 | 0x60 | 800A7054 | |
0x19 | 0x64 | 800A6B1C | SEQ_CmdPRT |
0x1a | 0x68 | 800A6458 | Call HSD functions |
0x1b | 0x6c | 800A6324 | |
0x1c | 0x70 | 800A6228 | |
0x1d | 0x74 | 800BB7A0 | |
0x1e | 0x78 | 800BB5F8 | |
0x1f | 0x7c | 800BB338 | |
0x20 | 0x80 | 800BA19C | |
0x21 | 0x84 | 800B9458 | |
0x22 | 0x88 | 800B832C | |
0x23 | 0x8c | 800B7D98 | |
0x24 | 0x90 | 800B3EC4 | Battle related |
0x25 | 0x94 | 800B3CE4 | |
0x26 | 0x98 | 800C0288 | |
0x27 | 0x9c | 800B097C | |
0x28 | 0xa0 | 800B0320 | |
0x29 | 0xa4 | 800B214C | |
0x2a | 0xa8 | 800B1750 | |
0x2b | 0xac | 800B1590 | Particles |
0x2c | 0xb0 | 800B24B8 | Empty and unused |
0x2d | 0xb4 | 800B24B0 | Empty and unused |
0x2e | 0xb8 | 800B24A8 | Empty and unused |
0x2f | 0xbc | 800B24A0 | Empty and unused |
0x30 | 0xc0 | 800B2498 | Empty and unused |
0x31 | 0xc4 | 800B3580 | |
0x32 | 0xc8 | 800B3020 | |
0x33 | 0xcc | 800B25D0 | |
0x34 | 0xd0 | 800B24C0 | |
0x35 | 0xd4 | 00000000 | Invalid |
0x36 | 0xd8 | 800960B4 | |
0x37 | 0xdc | 800952F4 | |
0x38 | 0xe0 | 80094324 | |
0x39 | 0xe4 | 800924F0 | |
0x3a | 0xe8 | 80091248 | |
0x3b | 0xec | 8009228C | |
0x3c | 0xf0 | 80091B8C | Menu logic |
0x3d | 0xf4 | 800C6228 | |
0x3e | 0xf8 | 80090EF8 | |
0x3f | 0xfc | 800C5EDC | |
0x40 | 0x100 | 800C57BC | |
0x41 | 0x104 | 800C531C | |
0x42 | 0x108 | 800C5124 | |
0x43 | 0x10c | 800C4FCC | |
0x44 | 0x110 | 800C4688 | Save data |
0x45 | 0x114 | 00000000 | Invalid |
0x46 | 0x118 | 800C88A8 | |
0x47 | 0x11c | 800C8404 | |
0x48 | 0x120 | 800C8108 | |
0x49 | 0x124 | 800C7D20 | |
0x4a | 0x128 | 800C7C5C | |
0x4b | 0x12c | 800C7424 | |
0x4c | 0x130 | 800C6900 | |
0x4d | 0x134 | 800C676C | |
0x4e | 0x138 | 00000000 | Invalid |
0x4f | 0x13c | 00000000 | Invalid |
0x50 | 0x140 | 800C6534 | |
0x51 | 0x144 | 00000000 | Invalid |
0x52 | 0x148 | 00000000 | Invalid |
0x53 | 0x14c | 00000000 | Invalid |
0x54 | 0x150 | 00000000 | Invalid |
0x55 | 0x154 | 800AAD24 | |
0x56 | 0x158 | 800AAC68 | |
0x57 | 0x15c | 00000000 | Invalid |
0x58 | 0x160 | 00000000 | Invalid |
0x59 | 0x164 | 00000000 | Invalid |
0x5a | 0x168 | 00000000 | Invalid |
0x5b | 0x16c | 800BFBB0 | |
0x5c | 0x170 | 800BE9EC | |
0x5d | 0x174 | 00000000 | Invalid |
0x5e | 0x178 | 00000000 | Invalid |
0x5f | 0x17c | 00000000 | Invalid |
0x60 | 0x180 | 00000000 | Invalid |
0x61 | 0x184 | 800AB754 |
It will then jump to the code found in the opcode pointer table. When we jump to 0x800a5698
, it then checks the second byte of the opcode. This second byte further breaks down the action to be performed.
There are 82 total opcode groups. 6 of the groups are empty (resulting in a no-op), leaving 76 with actual instructions in them. The number of instructions in each group varies. Each instruction for each opcode group can be found in the respective pages below for each opcode group.
Opcode Group Pages
- Group 00: SEQ_CmdSEQ1
- Group 01: SEQ_CmdSEQ2
- Group 02: SEQ_CmdTSK
- Group 03: SEQ_CmdREG
- Group 04: SEQ_CmdI
- Group 05: SEQ_CmdIC
- Group 06: SEQ_CmdIS
- Group 07: SEQ_CmdIL
- Group 08: SEQ_CmdF
- Group 09: SEQ_CmdP
- Group 0A: SEQ_CmdIV
- Group 0B: SEQ_CmdFV
- Group 0C: SEQ_CmdFM
- Group 0D: SEQ_CmdRGB
- Group 0E: SEQ_CmdMEM
- Group 0F: SEQ_CmdFILE
- Group 10
- Group 11: SEQ_CmdOBJ
- Group 12
- Group 13
- Group 14: SEQ_CmdHIT
- Group 15: SEQ_CmdPAUSE
- Group 16
- Group 17
- Group 18
- Group 19
- Group 1A
- Group 1B
- Group 1C
- Group 1E
- Group 1F
- Group 20
- Group 21
- Group 22
- Group 23
- Group 24
- Group 25
- Group 26
- Group 27
- Group 28
- Group 29
- Group 2A
- Group 2B
- Group 31
- Group 32
- Group 33
- Group 34
- Group 36
- Group 37
- Group 38
- Group 39
- Group 3A
- Group 3B
- Group 3C
- Group 3D
- Group 3E
- Group 3F
- Group 40
- Group 41
- Group 42
- Group 43
- Group 44
- Group 46
- Group 47
- Group 48
- Group 49
- Group 4A
- Group 4B
- Group 4C
- Group 4D
- Group 50
- Group 55
- Group 56
- Group 5B
- Group 5C
- Group 61
Each opcode group method takes in three parameters, seq_p
, reg_p
, and pc
. We know this is the case because opcode 02
in group 00
prints them out:
sprintf("sys_bp(): seq_p%08x reg_p%08x pc%08x\n", seq_p, reg_p, pc);
The first parameter seq_p
is a pointer to a variety of information related to the seq files being executed. One such example is the offset in memory to the start of the current seq file being executed.
seq_p->seq_p_sp is field 0x20 on seq_p, and seems to have lots of interesting data in it.
seq_p->seq_p_sp->field_0x1c = Battle frame count. Number of frames since the battle started. seq_p->seq_p_sp->field_0x2c = Used in synchronous timers. How much to subtract from the timer per frame, seems to default to 0x100. seq_p->seq_p_sp->field_0x38 = Pointer to this character's chr_p. seq_p->seq_p_sp->field_0x3c = Pointer to the opposing character's chr_p. seq_p->seq_p_sp->field_0x98->field_0x18 = Character index (player 1, player 2, player 3, player 4)?
The second parameter reg_p
holds pointers to the registers used. There are 18 registers. Despite this, the size of it in appears to be the first four-byte word of the seq file plus 1 times 0x60.
reg_p_size = (first_word + 1) * 0x60
So for example, game00.seq
starts with 0x00000006
, so it will initialize a reg_p
of size 0x2A0
.
The third parameter pc
is a pointer to the current opcode being executed in the seq file. It will move from opcode to opcode and branch when told to. When set to 0 it will cease executing opcodes.
op1
- The operand fromSEQ_RegCMD1
or the first operand fromSEQ_RegCMD2
.op2
- The second operand fromSEQ_RegCMD2
.varX
- An operand that follows after the opcode word, where X is the index (starting at 1).
The structs for reg_p
seem to all be next to each other in memory.
- seq_p[5][0x17]: Memory address of the start of the current SEQ file.
- reg_p[0x00]: Possibly a general purpose register (
gpr0
). - reg_p[0x01]: Possibly a general purpose register (
gpr1
). - reg_p[0x02]: Possibly a general purpose register (
gpr2
). - reg_p[0x03]: Possibly a general purpose register (
gpr3
). - reg_p[0x04]: Possibly a general purpose register (
gpr4
). - reg_p[0x05]: Possibly a general purpose register (
gpr5
). - reg_p[0x06]: Possibly a general purpose register (
gpr6
). - reg_p[0x07]: Possibly a general purpose register (
gpr7
). - reg_p[0x08]: Possibly a general purpose register (
gpr8
). - reg_p[0x09]: Possibly a general purpose register (
gpr9
). - reg_p[0x0A]: Possibly a general purpose register (
gpr10
). - reg_p[0x0B]: Possibly a general purpose register (
gpr11
). - reg_p[0x0C]: Possibly a general purpose register (
gpr12
). - reg_p[0x0D]: Possibly a general purpose register (
gpr13
). - reg_p[0x0E]: Possibly a general purpose register (
gpr14
). - reg_p[0x0F]: Possibly a general purpose register (
gpr15
). - reg_p[0x10]: Possibly a general purpose register (
gpr16
). - reg_p[0x11]: Possibly a general purpose register (
gpr17
). - reg_p[0x12]: Possibly a general purpose register (
gpr18
). - reg_p[0x13]: Currently unknown, appears to be used alongside the Condition Register (
cr
). - reg_p[0x14]: Count Register (
ctr
). Holds a counter. Set by opcode 0402 (reg_p[0x15] also is set to this counter) and read/decremented by opcode 013B. - reg_p[0x15]: Condition Register (
cr
). Holds values to be compared for branching. Set by opcode group 04 and compared in opcode group 01. - reg_p[0x16]: Stored PC (
stored_pc
). Holds a program counter while the program counter is reset to zero. Set by opcode 0100 and 0101 and used in the functionseq_parse(...)
. Reset by opcode 0001. - reg_p[0x17]: Stack Pointer (
sp
). The stack pointer to push and pop values from, such as return addresses for subroutine calls.
Any of the above registers can be read from by certain opcodes. You will know this can be done if the opcode calls seq_read_params
. If the last byte is under 0x18, it will return the value in the registers associated with that value. For example, the opcode 01500013
will read from register 0x13.
If the last byte is between 0x18 and 0x30, it will access from stored registers at seq_p[5].