Final Fantasy III SNES disassembled (C source reimplementation in progress)

Givemesteak

Active Member
Newcomer
Joined
Aug 4, 2024
Messages
39
Reaction score
61
Trophies
0
Age
37
XP
228
Country
Sweden
Hi, not sure if I am shooting myself in the foot by opening this thread but here we go.

I have fully disassembled Final Fantasy III/VI and it builds the identical input ROM.
Work has started on converting it to C. Several functions are already reimplemented in C and build the identical SNES rom.

I don't know how much interest there is in this kind of project but it's one of my favorite games of all time so I hope to eventually have complete, readable and documented source code for this game.

The end goal is being able to port this to other platforms.

I'll keep this thread updated when I have things to share and milestones are reached and so on.

The reason why I am not yet sharing any repo to the source is that it's still full of extracted game-assets and that's copyright material.
Eventually I can remove the assets and just provide the scripts to extract the assets.
But for now I am running frequent rebuilds and tests so that's not a priority at the moment.
 
Last edited by Givemesteak,
Gracias por tu trabajo; a mí también me gusta mucho este juego y me encantaría jugarlo en la Nintendo Switch con herramientas modernas.
 
+8KB across 443 routines are now C owned. And builds the exact rom with matching hashes.

With a lot of compiler stuff getting sorted out I am hoping that progress will speed up. However I am like 1.2% done translating it to C. And once that's done then there will be a lot of clean-up and documentation to make sure we have a nice, tidy and readable source.

I expect this will take a long time to complete.
 
How can you build a C version with the exact matching hashes, as the game was written in 65816 assembly ?
Well, if you match the functions written in assembly and make a ton of compiler tweaks then they should compile the same bytes. At least that's what has been working for me so far.

My pipeline uses Clang to parse C, followed by My own 65816 code generator, alongside modified compiler paths.
So we are therefor doing both reverse engineering and compiler development
 
Last edited by Givemesteak,
Well, if you match the functions written in assembly and make a ton of compiler tweaks then they should compile the same bytes. At least that's what has been working for me so far.

My pipeline uses Clang to parse C, followed by My own 65816 code generator, alongside modified compiler paths.
So we are therefor doing both reverse engineering and compiler development
That’s not how it works. No C compiler can generate the same code as a hand-written 65816 assembly.
You don’t seems to understand how the various decomp projects works : you have to find the exact compiler used for the project, and compare the generated assembly code from your reimplementation, with the binary from the game’s executable.
There is no such thing in SNES games written in assembly (you can have a look at various snes games leaks).

SNES to C projects, like snesrev’s project (https://github.com/snesrev/smw) ane reimplementation. The closest thing you can have for FF6 is Everything8215’s project (https://github.com/everything8215/ff6).

So, either you show some proof, either you’re lying.

(And if you want some proof that I know what I’m talking about, you’d understand the screenshot below)

1791012482741.png
 
That’s not how it works. No C compiler can generate the same code as a hand-written 65816 assembly.
You don’t seems to understand how the various decomp projects works : you have to find the exact compiler used for the project, and compare the generated assembly code from your reimplementation, with the binary from the game’s executable.
There is no such thing in SNES games written in assembly (you can have a look at various snes games leaks).

SNES to C projects, like snesrev’s project (https://github.com/snesrev/smw) ane reimplementation. The closest thing you can have for FF6 is Everything8215’s project (https://github.com/everything8215/ff6).

So, either you show some proof, either you’re lying.

(And if you want some proof that I know what I’m talking about, you’d understand the screenshot below)

View attachment 593726

It's possible that you are right that this is an impossible task.
But I am going to continue exploring this approach as I think it's far more interesting.

I already disassembled the entire game

I'll post some proof when/if I am ready.

But I have released stuff based on disassembly work before, I ported features from Pokemon Yellow over to Pokemon Crystal and released the .ips patch.

I am not lying about working on this. But perhaps I will run into a wall where I have to realize that this is impossible, time will tell.

fade_in.c
C:
typedef unsigned char u8;

void func_C00F4D(void) {
    *(volatile u8 *)0x004a = 0x10;
    *(volatile u8 *)0x004c = 0x10;
}

fade_out.c
C:
typedef unsigned char u8;

void func_C00F56(void) {
    *(volatile u8 *)0x004a = 0x90;
    *(volatile u8 *)0x004c = 0xf0;
}

fade_update.c
C:
typedef unsigned char u8;

void func_C00F5F(void)
{
    if ((signed char)*(volatile u8*)0x4a >= 0) {
        if ((*(volatile u8*)0x4c & 0xf0) == 0xf0)
            goto complete;
        *(volatile u8*)0x4c = (*(volatile u8*)0x4a & 0x1f) + *(volatile u8*)0x4c;
    } else {
        if (*(volatile u8*)0x4c == 0)
            goto complete;
        *(volatile u8*)0x10 = *(volatile u8*)0x4a & 0x1f;
        *(volatile u8*)0x4c = *(volatile u8*)0x4c - *(volatile u8*)0x10;
    }
    goto upload;
complete:
    *(volatile u8*)0x4a = 0;
upload:
    *(volatile u8*)0x2100 = *(volatile u8*)0x4c >> 4;
}

So we are going lower level than the one you provided in the screenshot.
 
Last edited by Givemesteak,

Site & Scene News

New Hot Discussed User Submitted