Compare commits

...

4 commits

Author SHA1 Message Date
599fd01376 ah OK that byte is OK to occupy 2025-03-28 10:48:31 -05:00
75af41af5f Change the hidecursor patch so it's not inside the pixel loop
it's probably microscopically faster
2025-03-28 10:48:31 -05:00
6cba995c88 Support higher resolutions
This works in cursory testing in the finder at e.g. 1280x720 (115200
bytes of screen RAM)

Widths 1024 pixels and above need extra patching because of sites
where the row width in bytes is loaded with signed 8-bit moveq.
The existing  simpler patches are preserved when this is not needed,
especially as hidecursor now does a fair amount of extra work
re-loading d0 in every iteration of the hide loop, which simplified
the patch.
2025-03-28 10:48:31 -05:00
bb9f2470a6 standalone patcher program
This also includes the sound buffer fix in https://github.com/evansm7/umac/issues/15
2025-03-28 10:47:45 -05:00
3 changed files with 286 additions and 127 deletions

View file

@ -56,7 +56,10 @@ DISP_WIDTH ?= 512
DISP_HEIGHT ?= 342 DISP_HEIGHT ?= 342
CFLAGS_CFG = -DDISP_WIDTH=$(DISP_WIDTH) -DDISP_HEIGHT=$(DISP_HEIGHT) CFLAGS_CFG = -DDISP_WIDTH=$(DISP_WIDTH) -DDISP_HEIGHT=$(DISP_HEIGHT)
all: main all: main patcher
patcher: src/rom.c
$(CC) $(CFLAGS) -DUMAC_STANDALONE_PATCHER -o $@ $<
$(MUSASHI_SRC): $(MUSASHI)/m68kops.h $(MUSASHI_SRC): $(MUSASHI)/m68kops.h
@ -74,7 +77,7 @@ main: $(OBJS)
clean: clean:
make -C $(MUSASHI) clean make -C $(MUSASHI) clean
rm -f $(MY_OBJS) main rm -f $(MY_OBJS) main patcher
################################################################################ ################################################################################
# Mac driver sources (no need to generally rebuild # Mac driver sources (no need to generally rebuild

258
src/rom.c
View file

@ -55,6 +55,18 @@ static const uint8_t sony_driver[] = {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
static int rom_patch1(uint8_t *rom_base, int disp_width, int disp_height, int mem_size);
#if !defined(UMAC_STANDALONE_PATCHER)
int rom_patch(uint8_t *rom_base) {
return rom_patch1(rom_base, DISP_WIDTH, DISP_HEIGHT, UMAC_MEMSIZE * 1024);
}
#endif
#undef DISP_WIDTH
#undef DISP_HEIGHT
#undef UMAC_MEMSIZE
static uint32_t rom_get_version(uint8_t *rom_base) static uint32_t rom_get_version(uint8_t *rom_base)
{ {
#if BYTE_ORDER == LITTLE_ENDIAN #if BYTE_ORDER == LITTLE_ENDIAN
@ -80,7 +92,7 @@ static uint32_t rom_get_version(uint8_t *rom_base)
} while (0) } while (0)
static void rom_patch_plusv3(uint8_t *rom_base) static int rom_patch_plusv3(uint8_t *rom_base, int disp_width, int disp_height, int ram_size)
{ {
/* Inspired by patches in BasiliskII! /* Inspired by patches in BasiliskII!
*/ */
@ -100,13 +112,13 @@ static void rom_patch_plusv3(uint8_t *rom_base)
* - No IWM init * - No IWM init
* - new Sound? * - new Sound?
*/ */
#if UMAC_MEMSIZE > 128 && UMAC_MEMSIZE < 512 if (ram_size > 128*1024 && ram_size < 512*1024) {
/* Hack to change memtop: try out a 256K Mac :) */ /* Hack to change memtop: try out a 256K Mac :) */
for (int i = 0x376; i < 0x37e; i += 2) for (int i = 0x376; i < 0x37e; i += 2)
ROM_WR16(i, M68K_INST_NOP); ROM_WR16(i, M68K_INST_NOP);
ROM_WR16(0x376, 0x2a7c); // moveal #RAM_SIZE, A5 ROM_WR16(0x376, 0x2a7c); // moveal #ram_size, A5
ROM_WR16(0x378, RAM_SIZE >> 16); ROM_WR16(0x378, ram_size >> 16);
ROM_WR16(0x37a, RAM_SIZE & 0xffff); ROM_WR16(0x37a, ram_size & 0xffff);
/* That overrides the probed memory size, but /* That overrides the probed memory size, but
* P_ChecksumRomAndTestMemory returns a failure code for * P_ChecksumRomAndTestMemory returns a failure code for
* things that aren't 128/512. Skip that: * things that aren't 128/512. Skip that:
@ -116,17 +128,17 @@ static void rom_patch_plusv3(uint8_t *rom_base)
* allowing the ROM checksum to fail (it returns failure, then * allowing the ROM checksum to fail (it returns failure, then
* we carry on). This avoids wild RAM addrs being accessed. * we carry on). This avoids wild RAM addrs being accessed.
*/ */
#endif
#if DISP_WIDTH != 512 || DISP_HEIGHT != 342 /* Fix up the sound buffer as used by BootBeep */
#define SCREEN_SIZE (DISP_WIDTH*DISP_HEIGHT/8) ROM_WR32(0x292, ram_size - 768);
#define SCREEN_DISTANCE_FROM_TOP (SCREEN_SIZE + 0x380) }
#if (SCREEN_DISTANCE_FROM_TOP >= 65536)
#error "rom.c: Screen res patching maths won't work for a screen this large" if(disp_width != 512 || disp_height != 342) {
#endif int screen_size = (disp_width*disp_height/8);
#define SCREEN_BASE (0x400000-SCREEN_DISTANCE_FROM_TOP) int screen_distance_from_top = screen_size + 0x380;
#define SCREEN_BASE_L16 (SCREEN_BASE & 0xffff) int screen_base = 0x400000-screen_distance_from_top;
#define SBCOORD(x, y) (SCREEN_BASE + ((DISP_WIDTH/8)*(y)) + ((x)/8)) printf("screen size=%d screen_base=%x\n", screen_size, screen_base);
#define SBCOORD(x, y) (screen_base + ((disp_width/8)*(y)) + ((x)/8))
/* Changing video res: /* Changing video res:
* *
@ -134,7 +146,7 @@ static void rom_patch_plusv3(uint8_t *rom_base)
* buffer lands underneath sound/other buffers at top of mem, * buffer lands underneath sound/other buffers at top of mem,
* i,e, 0x3fa700 = 0x400000-0x5580-0x380. So any new buffer * i,e, 0x3fa700 = 0x400000-0x5580-0x380. So any new buffer
* will be placed (and read out from for the GUI) at * will be placed (and read out from for the GUI) at
* MEM_TOP-0x380-SCREEN_SIZE. * MEM_TOP-0x380-screen_size.
* *
* For VGA, size is 0x9600 bytes (0x2580 words) * For VGA, size is 0x9600 bytes (0x2580 words)
*/ */
@ -148,11 +160,43 @@ static void rom_patch_plusv3(uint8_t *rom_base)
/* Now 0x46-0x57 can be used */ /* Now 0x46-0x57 can be used */
unsigned int patch_0 = 0x46; unsigned int patch_0 = 0x46;
ROM_WR16(patch_0 + 0, 0x9bfc); /* suba.l #imm32, A5 */ ROM_WR16(patch_0 + 0, 0x9bfc); /* suba.l #imm32, A5 */
ROM_WR16(patch_0 + 2, 0); /* (Could add more here) */ ROM_WR32(patch_0 + 2, screen_distance_from_top);
ROM_WR16(patch_0 + 4, SCREEN_DISTANCE_FROM_TOP);
ROM_WR16(patch_0 + 6, 0x6000); /* bra */ ROM_WR16(patch_0 + 6, 0x6000); /* bra */
ROM_WR16(patch_0 + 8, 0x3a4 - (patch_0 + 8)); /* Return to 3a4 */ ROM_WR16(patch_0 + 8, 0x3a4 - (patch_0 + 8)); /* Return to 3a4 */
// Additional patches needed if DISP_WIDTH is 1024 or above
unsigned int patch_2 = 0x32;
unsigned int patch_1 = patch_0 + 10;
if ((disp_width / 8) >= 128) {
ROM_WR16(patch_1 + 0, 0x3a3c); /* move.l ..., D5 */
ROM_WR16(patch_1 + 2, disp_width / 8); /* ^^^ */
ROM_WR16(patch_1 + 4, 0xc2c5); /* mulu D5, D1 */
ROM_WR16(patch_1 + 6, 0x4e75); /* rts */
if (patch_1 + 8 > 0x58) {
RERR("patch_1 extends too far (0x%x > 0x58)\n", patch_1 + 8);
return -1;
}
// is this the illegal instruction handler entry? if it is, it
// eventually falls through to 'check if test software exists',
// below.... @sc's annotated disassembly suggests "never called by the mac plus"
// but it looks to me like 0x2e is in the vector table at 0x16...
// patch it to jump down to after the test software check too.
ROM_WR16(0x2e, 0x6000); /* bra */
ROM_WR16(0x30, 0x62-0x30); /* offset */
ROM_WR16(patch_2 + 0, 0x303c); /* move.l ..., D0 */
ROM_WR16(patch_2 + 2, disp_width / 8); /* ^^^ */
ROM_WR16(patch_2 + 4, 0x41f8); /* Lea.L (CrsrSave), A0 */
ROM_WR16(patch_2 + 6, 0x088c); /* ^^^^^^^^ */
ROM_WR16(patch_2 + 8, 0x4e75); /* rts */
if (patch_2 + 10 > 0x41) {
RERR("patch_2 extends too far (0x%x > 0x41)\n", patch_2);
return -1;
}
}
/* Magic screen-related locations in Mac Plus ROM 4d1f8172: /* Magic screen-related locations in Mac Plus ROM 4d1f8172:
* *
* 8c : screen base addr (usually 3fa700, now 3f6680) * 8c : screen base addr (usually 3fa700, now 3f6680)
@ -185,19 +229,19 @@ static void rom_patch_plusv3(uint8_t *rom_base)
* 1e6e : x * 1e6e : x
* 1e82 : y * 1e82 : y
*/ */
ROM_WR16(0x8c, SCREEN_BASE_L16); ROM_WR32(0x8a, screen_base);
ROM_WR16(0x148, SCREEN_BASE_L16); ROM_WR32(0x146, screen_base);
ROM_WR32(0x164, SBCOORD(DISP_WIDTH/2 - (48/2), DISP_HEIGHT/2 + 8)); ROM_WR32(0x164, SBCOORD(disp_width/2 - (48/2), disp_height/2 + 8));
ROM_WR16(0x188, DISP_WIDTH/8); ROM_WR16(0x188, disp_width/8);
ROM_WR16(0x194, DISP_WIDTH/8); ROM_WR16(0x194, disp_width/8);
ROM_WR16(0x19c, (6*DISP_WIDTH/8)-1); ROM_WR16(0x19c, (6*disp_width/8)-1);
ROM_WR32(0x1a4, SBCOORD(DISP_WIDTH/2 - 8, DISP_HEIGHT/2 + 8 + 8)); ROM_WR32(0x1a4, SBCOORD(disp_width/2 - 8, disp_height/2 + 8 + 8));
ROM_WR16(0x1ee, (SCREEN_SIZE/4)-1); ROM_WR16(0x1ee, (screen_size/4)-1);
ROM_WR32(0xf0c, SBCOORD(DISP_WIDTH/2 - 16, DISP_HEIGHT/2 - 26)); ROM_WR32(0xf0c, SBCOORD(disp_width/2 - 16, disp_height/2 - 26));
ROM_WR32(0xf18, SBCOORD(DISP_WIDTH/2 - 8, DISP_HEIGHT/2 - 20)); ROM_WR32(0xf18, SBCOORD(disp_width/2 - 8, disp_height/2 - 20));
ROM_WR32(0x7e0, SBCOORD(DISP_WIDTH/2 - 16, DISP_HEIGHT/2 - 26)); ROM_WR32(0x7e0, SBCOORD(disp_width/2 - 16, disp_height/2 - 26));
ROM_WR32(0x7f2, SBCOORD(DISP_WIDTH/2 - 8, DISP_HEIGHT/2 - 11)); ROM_WR32(0x7f2, SBCOORD(disp_width/2 - 8, disp_height/2 - 11));
/* Patch "SubA #$5900, A5" to subtract 0x9880. /* Patch "SubA #$5900, A5" to subtract 0x9880.
* However... can't just patch the int16 immediate, as that's * However... can't just patch the int16 immediate, as that's
@ -209,29 +253,46 @@ static void rom_patch_plusv3(uint8_t *rom_base)
ROM_WR16(0x3a0, 0x6000); /* bra */ ROM_WR16(0x3a0, 0x6000); /* bra */
ROM_WR16(0x3a2, patch_0 - 0x3a2); /* ...to patch0, returns at 0x3a4 */ ROM_WR16(0x3a2, patch_0 - 0x3a2); /* ...to patch0, returns at 0x3a4 */
ROM_WR16(0x474, DISP_WIDTH/8); ROM_WR16(0x474, disp_width/8);
ROM_WR16(0x494, DISP_HEIGHT); ROM_WR16(0x494, disp_height);
ROM_WR16(0x498, DISP_WIDTH); ROM_WR16(0x498, disp_width);
ROM_WR16(0xa0e, DISP_HEIGHT); /* copybits? */ ROM_WR16(0xa0e, disp_height); /* copybits? */
ROM_WR16(0xa10, DISP_WIDTH); ROM_WR16(0xa10, disp_width);
ROM_WR16(0xee2, (DISP_WIDTH/8)-4); /* tPutIcon bytes per row, minus 4 */ ROM_WR16(0xee2, (disp_width/8)-4); /* tPutIcon bytes per row, minus 4 */
ROM_WR16(0xef2, DISP_WIDTH/8); /* tPutIcon bytes per row */ ROM_WR16(0xef2, disp_width/8); /* tPutIcon bytes per row */
ROM_WR16(0xf36, (DISP_WIDTH/8)-2); /* tPutIcon bytes per row, minus 2 */ ROM_WR16(0xf36, (disp_width/8)-2); /* tPutIcon bytes per row, minus 2 */
ROM_WR8(0x1cd1, DISP_WIDTH/8); /* hidecursor */
ROM_WR16(0x1d48, DISP_WIDTH-32); /* 1d46+2 was originally 512-32 rite? */ // getting the stride of the framebuffer for hidecursor
ROM_WR16(0x1d4e, DISP_WIDTH-32); /* 1d4c+2 is 480, same */ if ((disp_width / 8) >= 128) {
ROM_WR16(0x1d6e, DISP_HEIGHT-16); /* showcursor (YESS fixed Y crash bug!) */ ROM_WR16(0x1ccc, 0x4eba); /* (hidecursor) jsr */
ROM_WR16(0x1d74, DISP_HEIGHT); /* showcursor */ ROM_WR16(0x1cce, patch_2 - 0x1cce); /* .. to patch2, returns at 1cd0 */
ROM_WR8(0x1d93, DISP_WIDTH/8); /* showcursor */ ROM_WR16(0x1cd0, 0x4e71); /* nop */
ROM_WR16(0x1e68, DISP_HEIGHT); /* mScrnSize */ } else {
ROM_WR16(0x1e6e, DISP_WIDTH); /* mScrnSize */ ROM_WR8(0x1cd1, disp_width/8); /* hidecursor */
ROM_WR16(0x1e82, DISP_HEIGHT); /* tScrnBitMap */ }
ROM_WR16(0x1d48, disp_width-32); /* 1d46+2 was originally 512-32 rite? */
ROM_WR16(0x1d4e, disp_width-32); /* 1d4c+2 is 480, same */
ROM_WR16(0x1d6e, disp_height-16); /* showcursor (YESS fixed Y crash bug!) */
ROM_WR16(0x1d74, disp_height); /* showcursor */
ROM_WR8(0x1d93, disp_width/8); /* showcursor */
ROM_WR16(0x1e68, disp_height); /* mScrnSize */
// getting the stride of the framebuffer for showcursor
if ((disp_width / 8) >= 128) {
ROM_WR16(0x1d92, 0x4eba); /* jsr */
ROM_WR16(0x1d94, patch_1 - 0x1d94); /* .. to patch1, returns at 1d96 */
} else {
ROM_WR8(0x1d93, disp_width/8); /* showcursor */
}
ROM_WR16(0x1e6e, disp_width); /* mScrnSize */
ROM_WR16(0x1e82, disp_height); /* tScrnBitMap */
}
/* FIXME: Welcome To Macintosh is drawn at the wrong position. Find where that's done. */ /* FIXME: Welcome To Macintosh is drawn at the wrong position. Find where that's done. */
#endif return 0;
} }
int rom_patch(uint8_t *rom_base) static int rom_patch1(uint8_t *rom_base, int disp_width, int disp_height, int mem_size)
{ {
uint32_t v = rom_get_version(rom_base); uint32_t v = rom_get_version(rom_base);
int r = -1; int r = -1;
@ -239,8 +300,7 @@ int rom_patch(uint8_t *rom_base)
*/ */
switch(v) { switch(v) {
case ROM_PLUSv3_VERSION: case ROM_PLUSv3_VERSION:
rom_patch_plusv3(rom_base); r = rom_patch_plusv3(rom_base, disp_width, disp_height, mem_size);
r = 0;
break; break;
default: default:
@ -250,3 +310,99 @@ int rom_patch(uint8_t *rom_base)
return r; return r;
} }
#if defined(UMAC_STANDALONE_PATCHER)
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char **argv) {
uint8_t *rom_base;
char *rom_filename = "4D1F8172 - MacPlus v3.ROM";
char *rom_dump_filename = NULL; // Raw bytes
char *rom_header_filename = NULL; // C header
int ch;
int disp_width = 512;
int disp_height = 342;
int ram_size = 128;
while ((ch = getopt(argc, argv, "vm:r:w:W:")) != -1) {
switch (ch) {
case 'v':
disp_width = 640;
disp_height = 480;
break;
case 'm':
ram_size = atoi(optarg);
break;
case 'r':
rom_filename = strdup(optarg);
break;
case 'W':
rom_dump_filename = strdup(optarg);
break;
case 'w':
rom_header_filename = strdup(optarg);
break;
case '?':
abort();
}
}
if (!rom_dump_filename && !rom_header_filename) {
printf("Must specify either a -W (binary) or -w (C header) output file");
abort();
}
printf("Opening ROM '%s'\n", rom_filename);
int ofd = open(rom_filename, O_RDONLY);
if (ofd < 0) {
perror("ROM");
return 1;
}
struct stat sb;
fstat(ofd, &sb);
off_t _rom_size = sb.st_size;
rom_base = mmap(0, _rom_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, ofd, 0);
if (rom_base == MAP_FAILED) {
printf("Can't mmap ROM!\n");
return 1;
}
if (rom_patch1(rom_base, disp_width, disp_height, ram_size*1024)) {
printf("Failed to patch ROM\n");
return 1;
}
if (rom_dump_filename) {
int rfd = open(rom_dump_filename, O_CREAT | O_TRUNC | O_RDWR, 0655);
if (rfd < 0) {
perror("ROM dump");
return 1;
}
ssize_t written = write(rfd, rom_base, _rom_size);
if (written < 0) {
perror("ROM dump write");
return 1;
}
if (written < _rom_size) {
printf("*** WARNING: Short write to %s!\n",
rom_dump_filename);
} else {
printf("Dumped ROM to %s\n", rom_dump_filename);
}
close(rfd);
}
if (rom_header_filename) {
FILE *ofd = fopen(rom_header_filename, "w");
if (!ofd) { perror("fopen"); abort(); }
for(off_t i=0; i<_rom_size; i++) {
fprintf(ofd, "%d,", rom_base[i]);
if(i % 16 == 15) fprintf(ofd, "\n");
}
fprintf(ofd, "\n");
printf("Dumped ROM to %s as header\n", rom_header_filename);
fclose(ofd);
}
}
#endif

View file

@ -54,7 +54,7 @@ static void print_help(char *n)
"\t-i\t\t\tDisassembled instruction trace\n", n); "\t-i\t\t\tDisassembled instruction trace\n", n);
} }
#define DISP_SCALE 2 #define DISP_SCALE (DISP_WIDTH < 800 && DISP_HEIGHT < 600 ? 2 : 1)
static uint32_t framebuffer[DISP_WIDTH*DISP_HEIGHT]; static uint32_t framebuffer[DISP_WIDTH*DISP_HEIGHT];