An ISA definition for Kingdom Hearts 2 AI https://govanify.com/post/kh2ai/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

526 lines
9.5 KiB

#
#
# Instructions
#
#
# 0x1 =========
# standard push
# so this is how the game does it, it pushes a value, normal stuff. THE. THING.
# IS. it can sometime push an address too, that a syscall relocates. so we're
# going to have to be hacky to get the entire file to be analyzed. sad day.
# ssub_opc is always equal 0, we just define it in a more specific fashion to
# prefer push.v over _push.v, which is dynamically created by the analyzer
:push.v full_ext is opcode=0 & ( sub_opc=1 | sub_opc=0 ) ; full_ext {
push(full_ext:4);
}
#:pushc CLABEL is opcode=0 & ( sub_opc=1 | sub_opc=0 ) ; CLABEL & full_ext {
# push(full_ext:4);
#}
#push and add
:push2_unk0 is opcode_ext=0 & sub_opc_ext=2 & opesub=0 {
}
# push and add to pointer
:push.ap rn, ope2 is opcode_ext=0 & sub_opc_ext=2 & opesub=1 & ope2 & rn {
}
:push2_unk2 is opcode_ext=0 & sub_opc_ext=2 & opesub=2 {
}
:push.l LABEL02 is opcode_ext=0 & sub_opc_ext=2 & opesub=3 & LABEL02 {
push(LABEL02:4);
}
:push3_unk0 is opcode_ext=0 & sub_opc_ext=3 & opesub=0 {
}
#push and add
:push.a rn, ope2 is opcode_ext=0 & sub_opc_ext=3 & opesub=1 & ope2 & rn {
}
#push and add
:push3_unk2 is opcode_ext=0 & sub_opc_ext=3 & opesub=2 {
}
# never used in practice... push pointer as data and not label
:push.ln NOT_LABEL03 is opcode_ext=0 & sub_opc_ext=3 & opesub=3 & NOT_LABEL03 {
push(NOT_LABEL03);
}
# 0x1 =========
# sometimes it has arguments, to check!
# this is a pop_at!!!!!
:pop_unk0 is opcode_ext=1 & ope3=0 & ope2 & rn {
}
:pop.a rn, ope2 is opcode_ext=1 & ope3=1 & ope2 & rn {
}
:popat_unk2 is opcode_ext=1 & ope3=2 & ope2 & rn {
}
# no shit this isn't used in practice
:pop.l LABEL02 is opcode_ext=1 & ope3=3 & LABEL02 {
push(LABEL02:4);
}
:unk2_unk0 is opcode_ext=2 & ope3=0; opcode{
}
:unk2_unk1 is opcode_ext=2 & ope3=1; opcode{
}
:unk2_unk2 is opcode_ext=2 & ope3=2; opcode{
}
:unk2_unk3 is opcode_ext=2 & ope3=3; opcode{
}
# push and add to stack
:push.as ope2 is opcode_ext=3 & ope2{
local tmp:4 = sp;
pop(tmp);
tmp=tmp+ope2;
push(tmp);
}
:unk4 is opcode=4 {
}
# 0x5 =========
# comparison ops
# convert float to int
:cfti is opcode=5 & sub_opc=0 & ssub_opc=0{
local tmp:4 = sp;
pop(tmp);
tmp = round(tmp);
push(tmp);
}
# convert to negative
:neg is opcode=5 & sub_opc=0 & ssub_opc=2{
local tmp:4 = sp;
pop(tmp);
tmp=-tmp;
push(tmp);
}
# invert
:inv is opcode=5 & sub_opc=0 & ssub_opc=3{
local tmp:4 = sp;
pop(tmp);
tmp = ~tmp;
push(tmp);
}
# is equal zero
:eqz is opcode=5 & sub_opc=0 & ( ssub_opc=4 | ssub_opc=8 ){
local tmp:4 = sp;
pop(tmp);
local ret = (tmp == 0);
push(ret);
}
# absolute
:abs is opcode=5 & sub_opc=0 & ssub_opc=5{
local tmp:4 = sp;
pop(tmp);
if(tmp s<= 0) goto <min>;
goto <done>;
<min>
tmp=-tmp;
<done>
push(tmp);
}
# most significant bit
:msb is opcode=5 & sub_opc=0 & ssub_opc=6{
local tmp:4 = sp;
pop(tmp);
tmp = tmp >> 0x1F;
push(tmp);
}
# inferior to one
:info is opcode=5 & sub_opc=0 & ssub_opc=7{
local tmp:4 = sp;
pop(tmp);
push((tmp s< 1));
}
# not equal to zero
:neqz is opcode=5 & sub_opc=0 & ssub_opc=9{
local tmp:4 = sp;
pop(tmp);
push((tmp != 0));
}
# most significant bit inverted
:msbi is opcode=5 & sub_opc=0 & ssub_opc=0xA{
local tmp:4 = sp;
pop(tmp);
tmp = tmp >> 0x1F;
push(~tmp);
}
# is positive
:ipos is opcode=5 & sub_opc=0 & ssub_opc=0xb{
local tmp:4 = sp;
pop(tmp);
push((tmp s> 0));
}
# 0x5 --- floats
# convert int to float
:citf is opcode=5 & sub_opc=1 & ssub_opc=0{
local tmp:4 = sp;
pop(tmp);
tmp=int2float(tmp);
push(tmp);
}
# convert to negative (float)
:negf is opcode=5 & sub_opc=1 & ssub_opc=2{
}
# ABS (float)
:absf is opcode=5 & sub_opc=1 & ssub_opc=5{
local tmp:4 = sp;
pop(tmp);
tmp=abs(tmp);
push(tmp);
}
# inferior to zero (float)
:infzf is opcode=5 & sub_opc=1 & ssub_opc=6{
local tmp:4 = sp;
pop(tmp);
push((tmp f< 0));
}
# inferior or equal to zero (float)
:infoezf is opcode=5 & sub_opc=1 & ssub_opc=7{
local tmp:4 = sp;
pop(tmp);
push((tmp f<= 0));
}
# equal to zero (float)
:eqzf is opcode=5 & sub_opc=1 & ssub_opc=8{
local tmp:4 = sp;
pop(tmp);
push((tmp f== 0));
}
# not equal to zero (float)
:neqzf is opcode=5 & sub_opc=1 & ssub_opc=9{
local tmp:4 = sp;
pop(tmp);
push((tmp f!= 0));
}
# superior or equal to zero (float)
:supoezf is opcode=5 & sub_opc=1 & ssub_opc=0xA{
local tmp:4 = sp;
pop(tmp);
push((tmp f>= 0));
}
# superior to zero (float)
:supzf is opcode=5 & sub_opc=1 & ssub_opc=0xB{
local tmp:4 = sp;
pop(tmp);
push((tmp f> 0));
}
# 0x5 =========
# 0x6 =========
# APU operations
# addition
:add is opcode=6 & sub_opc=0 & ssub_opc=0{
local tmp:4 = sp;
local tmp2:4 = sp;
pop(tmp);
pop(tmp2);
push(tmp2+tmp);
}
# substraction
:sub is opcode=6 & sub_opc=0 & ssub_opc=1{
local tmp:4 = sp;
local tmp2:4 = sp;
pop(tmp);
pop(tmp2);
push(tmp2-tmp);
}
# multiplication
:mul is opcode=6 & sub_opc=0 & ssub_opc=2{
local tmp:4 = sp;
local tmp2:4 = sp;
pop(tmp);
pop(tmp2);
push(tmp2 * tmp);
}
# division
:div is opcode=6 & sub_opc=0 & ssub_opc=3{
local tmp:4 = sp;
local tmp2:4 = sp;
pop(tmp);
pop(tmp2);
push(tmp2 s/ tmp);
}
# modulo
:mod is opcode=6 & sub_opc=0 & ssub_opc=4{
local tmp:4 = sp;
local tmp2:4 = sp;
pop(tmp);
pop(tmp2);
push(tmp2 s% tmp);
}
# logical and
:and is opcode=6 & sub_opc=0 & ssub_opc=5{
local tmp:4 = sp;
local tmp2:4 = sp;
pop(tmp);
pop(tmp2);
push(tmp2&tmp);
}
# logical or
:or is opcode=6 & sub_opc=0 & ssub_opc=6{
local tmp:4 = sp;
local tmp2:4 = sp;
pop(tmp);
pop(tmp2);
push(tmp2|tmp);
}
# logical exclusive or
:xor is opcode=6 & sub_opc=0 & ssub_opc=7{
local tmp:4 = sp;
local tmp2:4 = sp;
pop(tmp);
pop(tmp2);
push(tmp2^tmp);
}
# shift logical left
:sll is opcode=6 & sub_opc=0 & ssub_opc=8{
local tmp:4 = sp;
local tmp2:4 = sp;
pop(tmp);
pop(tmp2);
push(tmp2<<(tmp&0x1F));
}
# shift right arithmetic
:sra is opcode=6 & sub_opc=0 & ssub_opc=9{
local tmp:4 = sp;
local tmp2:4 = sp;
pop(tmp);
pop(tmp2);
push(tmp2>>(tmp&0x1F));
}
# not equal to zero (2 variable stack edition)
:eqzv is opcode=6 & sub_opc=0 & ssub_opc=0xA{
local tmp:4 = sp;
local tmp2:4 = sp;
pop(tmp);
pop(tmp2);
local ret:4 = 1;
if(tmp!=0) goto <next>;
goto <end>;
<next>
if(tmp2==0) goto <end>;
ret=0;
<end>
push(ret);
}
# equal to zero (2 variable stack edition)
:neqzv is opcode=6 & sub_opc=0 & ssub_opc=0xB{
local tmp:4 = sp;
local tmp2:4 = sp;
pop(tmp);
pop(tmp2);
local ret:4 = 1;
if(tmp==0) goto <next>;
goto <end>;
<next>
if(tmp2!=0) goto <end>;
ret=0;
<end>
push(ret);
}
# addition (float)
:addf is opcode=6 & sub_opc=1 & ssub_opc=0{
local tmp:4 = sp;
local tmp2:4 = sp;
pop(tmp);
pop(tmp2);
push(tmp2 f+ tmp);
}
# substraction (float)
:subf is opcode=6 & sub_opc=1 & ssub_opc=1{
local tmp:4 = sp;
local tmp2:4 = sp;
pop(tmp);
pop(tmp2);
push(tmp2 f- tmp);
}
# multiplication (float)
:mulf is opcode=6 & sub_opc=1 & ssub_opc=2{
local tmp:4 = sp;
local tmp2:4 = sp;
pop(tmp);
pop(tmp2);
push(tmp2 f* tmp);
}
# division (float)
:divf is opcode=6 & sub_opc=1 & ssub_opc=3{
local tmp:4 = sp;
local tmp2:4 = sp;
pop(tmp);
pop(tmp2);
push(tmp2 f/ tmp);
}
# modulo (float)
:modf is opcode=6 & sub_opc=1 & ssub_opc=4{
local tmp:4 = sp;
local tmp2:4 = sp;
pop(tmp);
pop(tmp2);
# primitive doesn't exist, so we do with what we can
local ret:4 = fmod(tmp2, tmp);
push(ret);
}
# 0x6 =========
:jmp7_unk1 LABEL8 is opcode_ext=7 & ope3=0 & LABEL8 {
call LABEL8;
}
:jmp7_unk2 LABEL8 is opcode_ext=7 & ope3=1 & LABEL8 {
call LABEL8;
}
:jmp7_unk3 LABEL8 is opcode_ext=7 & ope3=2 & LABEL8 {
call LABEL8;
}
# jump
# TODO: verify first arg!
:jmp ope3, LABEL8 is opcode_ext=8 & LABEL8 & ope3 {
call LABEL8;
}
# 0x9 =========
:exit iarg is opcode=9 & ( ssub_opc=0 | ssub_opc=1 ) & iarg{
exit(iarg:1);
}
# return
:ret is opcode=9 & ssub_opc=2{
return[ra];
}
# push cached -> push last cached pushed element to stack
# don't ask me, this entire ISA is cursed
:push.ca is opcode=9 & ssub_opc=3{
}
# push copy -> push last pushed element to stack
:push.c is opcode=9 & ssub_opc=5{
}
# sinus; arg in radians
:sin is opcode=9 & ssub_opc=6{
local tmp:4 = sp;
pop(tmp);
local ret:4 = sin(tmp);
push(ret);
}
# cosinus; arg in radians
:cos is opcode=9 & ssub_opc=7{
local tmp:4 = sp;
pop(tmp);
local ret:4 = cos(tmp);
push(ret);
}
# degrees to radians
# /!\ radians are [0-2pi] in this engine
:degr is opcode=9 & ssub_opc=8{
local tmp:4 = sp;
pop(tmp);
local ret:4 = degrees_to_radians(tmp);
push(ret);
}
# radians to degree
:radd is opcode=9 & ssub_opc=9{
local tmp:4 = sp;
pop(tmp);
local ret:4 = radians_to_degrees(tmp);
push(ret);
}
# 0x9 =========
#:syscall opesub,ope2 is opcode_ext=0xA & opesub & ope2 {
# if (opesub:4==1) goto <table1>;
# <table1>
# if (ope2:4==6) goto <_syscall1_6>;
# # unknown args or no changes necessary
# system_call(opesub:4,ope2:4);
# goto <done>;
# <_syscall1_6>
# syscall1_6();
# goto <done>;
# <done>
#}
:syscall opesub,ope2 is opcode_ext=0xA & opesub & ope2 {
system_call(opesub:4,ope2:4);
}
:unkB is opcode=0xB {
}