Zelda: A Link to the Past (SNES) re-implemented in C
github.com
github.com
So not simply recreated, it's a 100% accurate replica of the original game. Crazy.
What, by the way, was the original SNES "OS" written in?
The source code of the SNES Doom port was open sourced if you wanna take a look: https://github.com/RandalLinden/DOOM-FX
For example, how do they ensure that the stack layout matches the SNES, the right mix of variables in registers vs in memory, and so on?
What they are saying is that they can run their own C code along side the original assembly inside their own virtual SNES and compare the memory and register state after each operation. They aren't saying their code checks against a physical SNES. They are saying the virtual system state after running their C code in their virtual SNES matches the state after the original ASM code runs in their virtual SNES.
None of this is to minimize the work. It is a crazy difficult/obsessive project to pull off.
EDIT: While downvoted, it is likely true. ChatGPT + Github Copilot are amazing at translating code between languages, especially from minimized code or inferring TypeScript typings from JavaScript.
Also, keep in mind that translating between source code in two languages is fairly easy, while translating machine code to a compilable language is very hard. It requires knowledge of the machine itself which may or may not exist. Maybe ChatGPT knows enough about SNES to do this? Probably not.
Setting a register to some magic constant and then pushing it to some unknown address will do SOMETHING in the computer but you don't know what or why. It's honestly really messy.
https://www.romhacking.net/forum/index.php?topic=32277.0
And then GPTChat gave me this:
#include <stdint.h>
#define SONG_TABLE_LEN 32
#define SONG_HEADER_LEN 8
#define SONG_HEADER_ITEM_TAKEN_LEN 7
#define SONG_HEADER_END_LEVEL_LEN 7
#define SONG_HEADER_OVERWORLD_LEN 8
#define SONG_HEADER_UNDERWORLD_LEN 8
#define SONG_HEADER_LAST_LEVEL_LEN 8
#define SONG_HEADER_GANON_LEN 8
#define SONG_HEADER_ENDING_LEN 8
const uint8_t SongTable[SONG_TABLE_LEN] = {
0x7D, 0xB5, 0x6E, 0x67, 0x7D, 0xAD, 0x64, 0x64,
0x75, 0x7D, 0x85, 0x95, 0x7D, 0x8D, 0x95, 0x9D,
0xA5, 0xBD, 0xC5, 0xCD, 0xD5, 0xDD, 0xD5, 0xE5,
0xED, 0x24, 0x2C, 0x34, 0x3C, 0x44, 0x34, 0x4C,
0x54, 0x5C, 0x44, 0xF5
};
...
void DriveAudio(void) {
unsigned char i;
unsigned char Square0Note;
unsigned char Square1Note;
unsigned char TriangleNote;
unsigned char NoiseNote;
unsigned char Envelope;
unsigned int NoteLength;
Square0Note = SongScript[SongHeader[SongSelect][4]];
Square1Note = Square0Note;
TriangleNote = SongScript[SongHeader[SongSelect][3]];
NoiseNote = SongScript[SongHeader[SongSelect][5]];
Envelope = SongHeader[SongSelect][6];
NoteLength = SongLength[SongScript[SongHeader[SongSelect][0]] + (Envelope & 0x07)];
// Play square wave on channel 1
Square1Note = Square0Note;
if (Square1Note & 0x80) Square1Note = 0;
Square1Note &= 0x3F;
Square1Note |= (Envelope & 0x10) | 0x40;
Square1Note &= 0x7F;
for (i = 0; i < Square1Note; ++i) {
// Output audio waveform data
}
// Play triangle wave on channel 2
if (TriangleNote & 0x80) TriangleNote = 0;
TriangleNote &= 0x7F;
for (i = 0; i < TriangleNote; ++i) {
// Output audio waveform data
}
// Play noise on channel 4
if (NoiseNote & 0x80) NoiseNote = 0;
NoiseNote &= 0x3F;
NoiseNote |= (Envelope & 0x20) | 0x40;
for (i = 0; i < NoiseNote; ++i) {
// Output audio waveform data
}
// Wait for note length to complete
for (i = 0; i < NoteLength; ++i) {
// Wait
}
}
The places where it can not fill in the details is because there are subroutines that are called whose body I didn't include in the prompt. Basically if you take a recursive approach where you feed ChatGPT incrementally the subroutines and whatnot, it can reconstruct it.[cut and past a bunch of code that fit within the ChatGPT buffer]
And it worked.
for (i = 0; i < Square1Note; ++i) {
// Output audio waveform data
}https://arstechnica.com/gaming/2021/11/reverse-engineering-t...
Oot seems to be clear it's decompiled the ROM and can deterministically make a ROM that runs on the hardware and emulator.
I thought it was a modern reimplementation but it seems to use parts of a SNES emulator.
And seems to run standalone but with parts of SNES hardware there too... Perhaps that made reusing assets easier than converting them. And translating graphics easier to.
Which cites and is modeled on MathOnNapkins's disassembly of the US version: https://www.zeldix.net/t143-disassembly-zelda-docs, https://www.romhacking.net/forum/index.php?topic=13592.0
Asking for a speedrunning friend.
If RISC-V is a success, write RISC-V assembly once, run everywhere.
https://en.wikipedia.org/wiki/Java_processor
;)