Skip to content

Instantly share code, notes, and snippets.

@bryc
Last active December 11, 2016 18:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bryc/9e6a926150433f99ec89625d660403cc to your computer and use it in GitHub Desktop.
Save bryc/9e6a926150433f99ec89625d660403cc to your computer and use it in GitHub Desktop.
ultraSMS/MSX2 rom inserters
Original process:
ultraSMS and ultraMSX2 both have a rominserter.exe file which insert a ROM into
the respective v64 (byteswapped) emulator at a specific offset. It actually inserts the ROM byteswapped,
allowing the V64jr or other to re-swap it when loading on the N64. This is quite stupid.
The filesize of the output ROM appears to be incompatible with 64drive, and must be 1052672 bytes.
Also, to run on 64drive's USB mode, they must not be in v64 format, and must be in the original z64 format.
TODO: Load large ROMs into the rominserter and see exactly where it stops writing at. Should shed light
My process:
Modify the original ROMs provided:
a) Byteswap them to native format
b) Pad them to 1028 KiB (1052672 bytes)
Insert the ROM properly
a) Start writing at specific offset
b) Stop writing at the proper offset (re-check size, specially ultraMSX2)
c) Add ROM detection and hotswap required offsets, so I don't need 2 versions of the code
Recalculate N64 CRC
a) Either use an external tool (easiest) or integrate CRC code in app (robust)
----
ultraMSX2 has problems loading MSX2 mx2 files, but loads MSX1 rom files 75% of the time.
This may be due to inaccurate ending for write address.
ultraSMS supports GameGear but also is able to run MasterSystem, albeit heavily glitched.
#include <stdio.h>
main(int argc, char *argv[]) {
int i, len, ofs;
unsigned char BASEROM[1052672];
// Read Base ROM -----------------------
FILE *fp = fopen(argv[1], "rb");
fseek(fp, 0, SEEK_END);
int baseSize = ftell(fp); // Get filesize before rewind
rewind(fp);
fread(BASEROM, baseSize, 1, fp);
fclose(fp);
// Detect v64 and unswap ---------------
if(BASEROM[0x00] == 0x37) {
for(i = 0; i < sizeof(BASEROM); i += 2) {
BASEROM[i + 0] = BASEROM[i + 0] ^ BASEROM[i + 1];
BASEROM[i + 1] = BASEROM[i + 0] ^ BASEROM[i + 1];
BASEROM[i + 0] = BASEROM[i + 0] ^ BASEROM[i + 1];
}
}
// Detect Base ROM (first digit of CRC)
switch(BASEROM[0x10]) {
case 0x4E: // ultraMSX2
ofs = 0x2DF48; len = 131072;
break;
case 0xF2: // ultraSMS
ofs = 0x1B410; len = 524288;
break;
}
// Load ROM to inject ------------------
FILE *fp3 = fopen(argv[2], "rb");
for (i = ofs; i < ofs + len; i++) {
BASEROM[i] = fgetc(fp3);
}
fclose(fp3);
// Write final ROM ---------------------
FILE *fp2 = fopen("patched.z64", "wb");
fwrite(BASEROM, 1, sizeof(BASEROM), fp2);
fclose(fp2);
return 0;
}
@ECHO OFF
gcc -o insrom insrom.c
IF NOT %ERRORLEVEL% EQU 0 PAUSE
/*
usage
insrom ultraSMS.z64 columns.gg
note: only use byteswapped version of ultraSMS/ultraMSX2.
argv[1] = Base ROM (ultraSMS.z64 or ultraMSX2.z64)
argv[2] = Insert ROM (.gg, .msx rom etc)
Goal:
1. Support ultraSMS and ultraMSX2
2. Detect byte format (v64, z64)
3. Resize base ROM properly for output if incorrect
4. Overwrite ROM area in offset:
UltraSMS offset: 0x1b410
UltraSMS size rom limit: 512 KiB / 524288
UltraMSX2 offset: 0x2df48
UltraMSX2 size rom limit: 128 KiB / 131072
5. Update CRC using n64crc.c
*/
#include <stdio.h>
unsigned char BASEROM[1052672]; // proper size
int romsize = 131072; // 128 kB
int insertAt = 0x2DF48; // insert MSX ROM at 0x2DF48
main(int argc, char *argv[])
{
if (argc != 3) {return 1;} // Exit program if not 3 arguments
// Read Base ROM ------------------------
FILE *fp = fopen(argv[1], "rb");
fseek(fp, 0, SEEK_END);
int basesize = ftell(fp);
rewind(fp);
fread(BASEROM, basesize, 1, fp);
fclose(fp);
// Load ROM to insert --------------------
FILE *fp3 = fopen(argv[2], "rb");
int addr, ch;
for (addr = insertAt; addr < insertAt + romsize; addr++) {
ch = fgetc(fp3);
if(ch != EOF) { // Stop at last byte in ROM to prevent extra 0xFF's
BASEROM[addr] = ch;
} else {break;}
}
fclose(fp3);
// Write final ROM ------------------------
FILE *fp2 = fopen("output.z64" , "wb");
fwrite(BASEROM, 1, sizeof(BASEROM), fp2);
fclose(fp2);
}
/*
usage
insrom ultraSMS.z64 columns.gg
note: only use byteswapped version of ultraSMS/ultraMSX2.
argv[1] = Base ROM (ultraSMS.z64 or ultraMSX2.z64)
argv[2] = Insert ROM (.gg, .msx rom etc)
Goal:
1. Support ultraSMS and ultraMSX2
2. Detect byte format (v64, z64)
3. Resize base ROM properly for output if incorrect
4. Overwrite ROM area in offset:
UltraSMS offset: 0x1b410
UltraSMS size rom limit: 512 KiB / 524288
UltraMSX2 offset: 0x2df48
UltraMSX2 size rom limit: 128 KiB / 131072
5. Update CRC using n64crc.c
*/
#include <stdio.h>
unsigned char BASEROM[1052672]; // proper size
int romsize = 524288; // 512 KiB
int insertAt = 0x1B410; // insert GG ROM at 0x1B410
main(int argc, char *argv[])
{
if (argc != 3) {return 1;} // Exit program if not 3 arguments
// Read Base ROM ------------------------
FILE *fp = fopen(argv[1], "rb");
fseek(fp, 0, SEEK_END);
int basesize = ftell(fp);
rewind(fp);
fread(BASEROM, basesize, 1, fp);
fclose(fp);
// Load ROM to insert --------------------
FILE *fp3 = fopen(argv[2], "rb");
int addr, ch;
for (addr = insertAt; addr < insertAt + romsize; addr++) {
ch = fgetc(fp3);
if(ch != EOF) { // Stop at last byte in ROM to prevent extra 0xFF's
BASEROM[addr] = ch;
} else {break;}
}
fclose(fp3);
// Write final ROM -----------------------
FILE *fp2 = fopen("output.z64" , "wb");
fwrite(BASEROM, 1, sizeof(BASEROM), fp2);
fclose(fp2);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment