speedup on 68k by eliminating indirect calls

This commit is contained in:
Matthew Laux 2022-08-02 14:47:38 -05:00
parent 4cde94d284
commit 2b6a315b0e
8 changed files with 90 additions and 100 deletions

View File

@ -30,7 +30,8 @@ int emulator_main(int argc, char *argv[])
// test the cpu, rom, and dmg independently and use the cpu
// for other non-GB stuff
dmg_new(&dmg, &cpu, &rom, &lcd);
cpu_bind_mem_model(&cpu, &dmg, dmg_read, dmg_write);
cpu.dmg = &dmg;
// cpu_bind_mem_model(&cpu, &dmg, dmg_read, dmg_write);
cpu.pc = 0x100;

View File

@ -156,7 +156,8 @@ int main(int argc, char *argv[])
// test the cpu, rom, and dmg independently and use the cpu
// for other non-GB stuff
dmg_new(&dmg, &cpu, &rom, &lcd);
cpu_bind_mem_model(&cpu, &dmg, dmg_read, dmg_write);
cpu.dmg = &dmg;
// cpu_bind_mem_model(&cpu, &dmg, dmg_read, dmg_write);
cpu.pc = 0x100;

View File

@ -2,20 +2,10 @@
#include <stdlib.h>
#include "cpu.h"
#include "dmg.h"
#include "types.h"
#include "instructions.h"
void cpu_bind_mem_model(
struct cpu *cpu,
void *mem_model,
u8 (*mem_read)(void *, u16),
void (*mem_write)(void *, u16, u8)
) {
cpu->mem_model = mem_model;
cpu->mem_read = mem_read;
cpu->mem_write = mem_write;
}
int flag_isset(struct cpu *cpu, int flag)
{
return (cpu->f & flag) != 0;
@ -66,7 +56,7 @@ void cpu_panic(struct cpu *cpu)
static inline u8 read8(struct cpu *cpu, u16 address)
{
return cpu->mem_read(cpu->mem_model, address);
return dmg_read(cpu->dmg, address);
}
static inline u16 read16(struct cpu *cpu, u16 address)
@ -78,12 +68,12 @@ static inline u16 read16(struct cpu *cpu, u16 address)
static inline void write8(struct cpu *cpu, u16 address, u8 data)
{
cpu->mem_write(cpu->mem_model, address, data);
dmg_write(cpu->dmg, address, data);
}
static inline void write16(struct cpu *cpu, u16 address, u16 data)
{
cpu->mem_write(cpu->mem_model, address, data);
dmg_write(cpu->dmg, address, data);
}
static void inc_with_carry(struct cpu *regs, u8 *reg)
@ -493,15 +483,15 @@ static u16 check_interrupts(struct cpu *cpu)
return 0;
}
u16 enabled = cpu->mem_read(cpu->mem_model, 0xffff);
u16 requested = cpu->mem_read(cpu->mem_model, 0xff0f);
u16 enabled = dmg_read(cpu->dmg, 0xffff);
u16 requested = dmg_read(cpu->dmg, 0xff0f);
for (k = 0; k < NUM_INTERRUPTS; k++) {
int check = 1 << k;
if ((enabled & check) && (requested & check)) {
// clear request flag for this interrupt and disable all further
// interrupts until service routine executes EI or RETI
cpu->mem_write(cpu->mem_model, 0xff0f, requested & ~check);
dmg_write(cpu->dmg, 0xff0f, requested & ~check);
cpu->interrupt_enable = 0;
return handlers[k];
}
@ -522,7 +512,7 @@ void cpu_step(struct cpu *cpu)
return;
}
u8 opc = cpu->mem_read(cpu->mem_model, cpu->pc);
u8 opc = dmg_read(cpu->dmg, cpu->pc);
#ifdef GB6_DEBUG
printf("0x%04x %s\n", cpu->pc, instructions[opc].format);
#endif

View File

@ -3,6 +3,8 @@
#include "types.h"
struct dmg;
struct cpu
{
u8 a;
@ -18,17 +20,18 @@ struct cpu
u32 cycle_count;
u8 interrupt_enable;
u8 (*mem_read)(void *, u16);
void (*mem_write)(void *, u16, u8);
void *mem_model;
struct dmg *dmg;
// u8 (*mem_read)(void *, u16);
// void (*mem_write)(void *, u16, u8);
// void *mem_model;
};
void cpu_bind_mem_model(
struct cpu *cpu,
void *mem_model,
u8 (*mem_read)(void *, u16),
void (*mem_write)(void *, u16, u8)
);
// void cpu_bind_mem_model(
// struct cpu *cpu,
// void *mem_model,
// u8 (*mem_read)(void *, u16),
// void (*mem_write)(void *, u16, u8)
// );
void cpu_step(struct cpu *cpu);
int flag_isset(struct cpu *cpu, int flag);

View File

@ -262,22 +262,22 @@ void dmg_step(void *_dmg)
dmg_request_interrupt(dmg, INT_LCDSTAT);
}
int lcdc = lcd_read(dmg->lcd, REG_LCDC);
if (lcdc & LCDC_ENABLE_BG) {
render_background(dmg, lcdc);
}
// int lcdc = lcd_read(dmg->lcd, REG_LCDC);
// if (lcdc & LCDC_ENABLE_BG) {
// render_background(dmg, lcdc);
// }
if (lcdc & LCDC_ENABLE_WINDOW) {
// printf("window\n");
}
// if (lcdc & LCDC_ENABLE_WINDOW) {
// // printf("window\n");
// }
lcd_apply_scroll(dmg->lcd);
// lcd_apply_scroll(dmg->lcd);
if (lcdc & LCDC_ENABLE_OBJ) {
render_objs(dmg);
}
// if (lcdc & LCDC_ENABLE_OBJ) {
// render_objs(dmg);
// }
lcd_draw(dmg->lcd);
// lcd_draw(dmg->lcd);
}
} else {
int scan = lcd_read(dmg->lcd, REG_LY);

View File

@ -6,16 +6,6 @@
#include "dmg.h"
#include "rom.h"
static int mbc_noop_read(struct mbc *mbc, struct dmg *dmg, u16 addr, u8 *out_data)
{
return 0;
}
static int mbc_noop_write(struct mbc *mbc, struct dmg *dmg, u16 addr, u8 data)
{
return 0;
}
static int mbc1_read(struct mbc *mbc, struct dmg *dmg, u16 addr, u8 *out_data)
{
if (addr >= 0x4000 && addr <= 0x7fff) {
@ -60,35 +50,29 @@ static int mbc1_write(struct mbc *mbc, struct dmg *dmg, u16 addr, u8 data)
return 0;
}
struct mbc mbc_noop = {
mbc_noop_read,
mbc_noop_write,
};
struct mbc mbc1 = {
mbc1_read,
mbc1_write,
};
struct mbc *mbc_new(int type)
{
switch (type) {
case 0:
return &mbc_noop;
case 1:
case 2:
case 3:
return &mbc1;
static struct mbc mbc;
if (type > 3) {
return NULL;
}
return NULL;
mbc.type = type;
return &mbc;
}
int mbc_read(struct mbc *mbc, struct dmg *dmg, u16 addr, u8 *out_data)
{
return mbc->read_fn(mbc, dmg, addr, out_data);
if (mbc->type == 0) {
return 0;
}
return mbc1_read(mbc, dmg, addr, out_data);
}
int mbc_write(struct mbc *mbc, struct dmg *dmg, u16 addr, u8 data)
{
return mbc->write_fn(mbc, dmg, addr, data);
if (mbc->type == 0) {
return 0;
}
return mbc1_write(mbc, dmg, addr, data);
}

View File

@ -6,8 +6,6 @@
struct dmg;
struct mbc {
int (*read_fn)(struct mbc *, struct dmg *, u16, u8 *);
int (*write_fn)(struct mbc *, struct dmg *, u16, u8);
int type;
int rom_bank;
int ram_bank;
@ -16,7 +14,10 @@ struct mbc {
};
struct mbc *mbc_new(int type);
// set *out_data and return 1 if handled, return 0 for base dmg behavior
int mbc_read(struct mbc *mbc, struct dmg *dmg, u16 addr, u8 *out_data);
// return 1 if handled, return 0 for base dmg behavior
int mbc_write(struct mbc *mbc, struct dmg *dmg, u16 addr, u8 data);
#endif

View File

@ -59,18 +59,18 @@ Rect offscreenRect = { 0, 0, 144, 160 };
BitMap offscreenBmp;
int lastTicks;
int execTime;
void Render(void)
{
long k = 0, dst, bit;
for (dst = 0; dst < 20 * 144; dst++) {
for (bit = 7; bit >= 0; bit--) {
offscreen[dst] |= lcd.pixels[k++];
offscreen[dst] <<= 1;
}
dst++;
}
// long k = 0, dst, bit;
// for (dst = 0; dst < 20 * 144; dst++) {
// for (bit = 7; bit >= 0; bit--) {
// offscreen[dst] |= lcd.pixels[k++];
// offscreen[dst] <<= 1;
// }
// dst++;
// }
/*
offscreen[dst] = lcd.pixels[k++] << 7;
@ -83,16 +83,25 @@ void Render(void)
offscreen[dst] |= lcd.pixels[k++];
*/
SetPort(g_wp);
CopyBits(&offscreenBmp, &g_wp->portBits, &offscreenRect, &offscreenRect, srcCopy, NULL);
// CopyBits(&offscreenBmp, &g_wp->portBits, &offscreenRect, &offscreenRect, srcCopy, NULL);
//EraseRect(&g_wp->portRect);
// MoveTo(10, 160);
// char debug[128];
// sprintf(debug, "PC: %04x", cpu.pc);
// C2PStr(debug);
// DrawString(debug);
EraseRect(&g_wp->portRect);
MoveTo(10, 180);
char debug[128];
double ms = execTime / 600.0;
sprintf(debug, "10000 insn %d ticks, %f ms per instruction", execTime, ms);
C2PStr(debug);
DrawString(debug);
}
// 417 ticks
// 10000 instructions
// 0.0417 tick per instruction
// 1/60 second per tick
// 0.000695 second per instruction
// 0.695 ms per instruction
void StartEmulation(void)
{
g_wp = NewWindow(0, &windowBounds, WINDOW_TITLE, true,
@ -188,7 +197,7 @@ void ShowAboutBox(void)
// DrawDialog(dp);
// while(!GetNextEvent(mDownMask, &e));
// while(WaitMouseUp());
DisposeDialog(dp);
}
@ -264,25 +273,26 @@ int main(int argc, char *argv[])
int executed;
int paused = 0;
int pause_next = 0;
InitEverything();
lcd_new(&lcd);
dmg_new(&dmg, &cpu, &rom, &lcd);
cpu_bind_mem_model(&cpu, &dmg, dmg_read, dmg_write);
cpu.dmg = &dmg;
// cpu_bind_mem_model(&cpu, &dmg, dmg_read, dmg_write);
cpu.pc = 0x100;
int start = TickCount();
while(g_running) {
if (emulationOn) {
int k;
int start = TickCount();
for (k = 0; k < 10000; k++) {
dmg_step(&dmg);
int now = TickCount();
if (now > lastTicks + 100) {
lastTicks = now;
Render();
}
if (Button()) g_running = false;
}
execTime = TickCount() - start;
emulationOn = false;
Render();
} else {
if(WaitNextEvent(everyEvent, &evt, 0, 0) != nullEvent) {
if (IsDialogEvent(&evt)) {