draw for system 6. it's slow

This commit is contained in:
Matthew Laux 2022-07-20 22:21:36 -05:00
parent 8d87ee1f26
commit b23d52737e
12 changed files with 137 additions and 47 deletions

View File

@ -54,8 +54,8 @@ GLuint make_output_texture() {
glGenTextures(1, &image_texture);
glBindTexture(GL_TEXTURE_2D, image_texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
return image_texture;
}
@ -66,7 +66,8 @@ void convert_output(struct lcd *lcd) {
for (y = 0; y < 256; y++) {
for (x = 0; x < 256; x++) {
int val = lcd->buf[y * 256 + x];
int fill = val ? 255 : 0;
int fill = 255 - val * 85;
//int fill = val ? 255 : 0;
output_image[out_index++] = fill;
output_image[out_index++] = fill;
output_image[out_index++] = fill;

View File

@ -174,7 +174,16 @@ static u8 shift_right(struct cpu *cpu, u8 value)
static u8 swap(struct cpu *cpu, u8 value)
{
return ((value & 0xf0) >> 4) | ((value & 0x0f) << 4);
u8 ret = ((value & 0xf0) >> 4) | ((value & 0x0f) << 4);
if(ret == 0) {
set_flag(cpu, FLAG_ZERO);
} else {
clear_flag(cpu, FLAG_ZERO);
}
clear_flag(cpu, FLAG_SIGN);
clear_flag(cpu, FLAG_HALF_CARRY);
clear_flag(cpu, FLAG_CARRY);
return ret;
}
static void xor(struct cpu *regs, u8 value)
@ -634,6 +643,8 @@ void cpu_step(struct cpu *cpu)
break;
case 0x2f: // CPL
cpu->a = ~cpu->a;
set_flag(cpu, FLAG_SIGN);
set_flag(cpu, FLAG_HALF_CARRY);
break;
case 0x31: // LD SP,d16
cpu->sp = read16(cpu, cpu->pc);
@ -756,6 +767,10 @@ void cpu_step(struct cpu *cpu)
case 0xb5: or(cpu, cpu->l); break;
case 0xb6: or(cpu, read8(cpu, read_hl(cpu))); break;
case 0xb7: or(cpu, cpu->a); break;
case 0xf6:
or(cpu, read8(cpu, cpu->pc));
cpu->pc++;
break;
// CP
case 0xb8: subtract(cpu, cpu->b, 0, 1); break;

View File

@ -39,9 +39,18 @@ void dmg_set_button(struct dmg *dmg, int field, int button, int pressed)
static u8 get_button_state(struct dmg *dmg)
{
return dmg->action_selected ? dmg->action_buttons : dmg->joypad;
u8 ret = 0;
if (dmg->action_selected) {
ret |= dmg->action_buttons;
}
if (dmg->joypad_selected) {
ret |= dmg->joypad;
}
return ret;
}
static int counter;
u8 dmg_read(void *_dmg, u16 address)
{
struct dmg *dmg = (struct dmg *) _dmg;
@ -66,6 +75,9 @@ u8 dmg_read(void *_dmg, u16 address)
return dmg->zero_page[address - 0xff80];
} else if (address == 0xff00) {
return get_button_state(dmg);
} else if (address == 0xff04) {
counter++;
return counter;
} else if (address == 0xff0f) {
return dmg->interrupt_requested;
} else if (address == 0xffff) {
@ -93,12 +105,21 @@ void dmg_write(void *_dmg, u16 address, u8 data)
} else if (address < 0xc000) {
// TODO switchable ram bank
} else if (address < 0xe000) {
// printf("write ram %04x %02x\n", address, data);
dmg->main_ram[address - 0xc000] = data;
} else if (address == 0xFF46) {
u16 src = data << 8;
int k = 0;
// printf("oam dma %04x\n", src);
for (u16 addr = src; addr < src + 0xa0; addr++) {
dmg->lcd->oam[k++] = dmg_read(dmg, addr);
}
} else if (lcd_is_valid_addr(address)) {
lcd_write(dmg->lcd, address, data);
} else if (address >= 0xff80 && address <= 0xfffe) {
dmg->zero_page[address - 0xff80] = data;
} else if (address == 0xff00) {
dmg->joypad_selected = data & (1 << 4);
dmg->action_selected = data & (1 << 5);
} else if (address == 0xff0f) {
dmg->interrupt_requested = data;
@ -126,9 +147,19 @@ void dmg_step(void *_dmg)
if (dmg->cpu->cycle_count - dmg->last_lcd_update >= 456) {
dmg->last_lcd_update = dmg->cpu->cycle_count;
int next_scanline = lcd_step(dmg->lcd);
// update LYC
if (next_scanline == lcd_read(dmg->lcd, REG_LYC)) {
lcd_set_bit(dmg->lcd, REG_STAT, STAT_FLAG_MATCH);
dmg_request_interrupt(dmg, INT_LCDSTAT);
} else {
lcd_clear_bit(dmg->lcd, REG_STAT, STAT_FLAG_MATCH);
}
if (next_scanline == 144) {
// vblank has started, draw all the stuff from ram into the lcd
dmg_request_interrupt(dmg, INT_VBLANK);
dmg_request_interrupt(dmg, INT_SERIAL);
int lcdc = lcd_read(dmg->lcd, REG_LCDC);
int bg_base = (lcdc & LCDC_BG_TILE_MAP) ? 0x9c00 : 0x9800;
@ -136,7 +167,7 @@ void dmg_step(void *_dmg)
int use_unsigned = lcdc & LCDC_BG_TILE_DATA;
int tilebase = use_unsigned ? 0x8000 : 0x9000;
printf("%04x %04x %04x\n", bg_base, window_base, tilebase);
//printf("%04x %04x %04x\n", bg_base, window_base, tilebase);
int k = 0, off = 0;
int tile_y = 0, tile_x = 0;
@ -155,9 +186,8 @@ void dmg_step(void *_dmg)
int data1 = dmg_read(dmg, eff_addr + b);
int data2 = dmg_read(dmg, eff_addr + b + 1);
for (i = 7; i >= 0; i--) {
// monochrome for now
dmg->lcd->buf[off] = (data1 & (1 << i)) ? 1 : 0;
//dmg->lcd->buf[off] |= (data2 & (1 << i)) ? 1 : 0;
dmg->lcd->buf[off] = ((data1 & (1 << i)) ? 1 : 0);// << 1;
//dmg->lcd->buf[off] |= (data1 & (1 << i)) ? 1 : 0;
off++;
}
off += 248;

View File

@ -25,6 +25,7 @@ struct dmg {
u8 video_ram[0x2000];
u8 zero_page[0x80];
u32 last_lcd_update;
int joypad_selected;
int action_selected; // non-0 if A/B/start/select selected, 0 for directions
u8 interrupt_enabled;
u8 interrupt_requested;

View File

@ -5,12 +5,12 @@
#include "types.h"
#include "lcd.h"
static void set_bit(struct lcd *lcd, u16 addr, u8 bit)
void lcd_set_bit(struct lcd *lcd, u16 addr, u8 bit)
{
lcd_write(lcd, addr, lcd_read(lcd, addr) | (1 << bit));
}
static void clear_bit(struct lcd *lcd, u16 addr, u8 bit)
void lcd_clear_bit(struct lcd *lcd, u16 addr, u8 bit)
{
lcd_write(lcd, addr, lcd_read(lcd, addr) & ~(1 << bit));
}
@ -18,6 +18,7 @@ static void clear_bit(struct lcd *lcd, u16 addr, u8 bit)
void lcd_new(struct lcd *lcd)
{
lcd->buf = malloc(256 * 256);
memset(lcd->buf, 0, 256 * 256);
// todo < 8 bpp
lcd->pixels = malloc(LCD_WIDTH * LCD_HEIGHT);
}
@ -41,9 +42,6 @@ void lcd_write(struct lcd *lcd, u16 addr, u8 value)
lcd->oam[addr - 0xfe00] = value;
} else {
lcd->regs[addr - REG_LCD_BASE] = value;
if (addr == 0xFF46) {
// OAM DMA
}
}
}
@ -64,13 +62,6 @@ void lcd_copy(struct lcd *lcd)
int lcd_step(struct lcd *lcd)
{
// update LYC
if (lcd_read(lcd, REG_LY) == lcd_read(lcd, REG_LYC)) {
set_bit(lcd, REG_STAT, STAT_FLAG_MATCH);
} else {
clear_bit(lcd, REG_STAT, STAT_FLAG_MATCH);
}
// step to next scanline 0-153
u8 next_scanline = (lcd_read(lcd, REG_LY) + 1) % 154;
lcd_write(lcd, REG_LY, next_scanline);

View File

@ -48,6 +48,9 @@ void lcd_write(struct lcd *lcd, u16 addr, u8 value);
void lcd_put_pixel(struct lcd *lcd, u8 x, u8 y, u8 value);
void lcd_set_bit(struct lcd *lcd, u16 addr, u8 bit);
void lcd_clear_bit(struct lcd *lcd, u16 addr, u8 bit);
// i feel like i'm going to need to call this every cycle and update regs
int lcd_step(struct lcd *lcd);
void lcd_copy(struct lcd *lcd);

View File

@ -19,6 +19,7 @@ int rom_load(struct rom *rom, const char *filename)
rom->type = 0; // TODO read type from cart
rom->data = malloc(len);
rom->length = len;
if (fread(rom->data, 1, len, fp) < len) {
return 0;
}

View File

@ -4,11 +4,11 @@
#include "types.h"
struct rom {
u32 length;
int type;
u8 *data;
};
int rom_load(struct rom *rom, const char *filename);
void rom_free(struct rom *rom);

View File

@ -3,6 +3,8 @@ cmake_minimum_required(VERSION 3.9)
include_directories(../src)
set(CMAKE_CXX_FLAGS "-O3")
add_application(Emulator
../src/bootstrap.c
../src/cpu.c

View File

@ -17,14 +17,24 @@
#include "emulator.h"
#include "dmg.h"
#include "cpu.h"
#include "rom.h"
#include "lcd.h"
WindowPtr g_wp;
DialogPtr stateDialog;
unsigned char g_running;
unsigned char emulationOn;
static Point windowPt = { WINDOW_Y, WINDOW_X };
static Rect windowBounds = { WINDOW_Y, WINDOW_X, WINDOW_Y + WINDOW_HEIGHT, WINDOW_X + WINDOW_WIDTH };
emu_state theState;
struct cpu cpu;
struct rom rom;
struct lcd lcd;
struct dmg dmg;
void InitEverything(void)
{
@ -45,10 +55,35 @@ void InitEverything(void)
g_running = 1;
}
char offscreen[32 * 256];
Rect offscreenRect = { 0, 0, 256, 256 };
BitMap offscreenBmp;
int lastTicks;
void Render(void)
{
MoveTo(10, 10);
DrawString("\pTest 123");
long k = 0, dst;
for (dst = 0; dst < 32 * 256; dst++) {
offscreen[dst] = lcd.buf[k++] << 7
| lcd.buf[k++] << 6
| lcd.buf[k++] << 5
| lcd.buf[k++] << 4
| lcd.buf[k++] << 3
| lcd.buf[k++] << 2
| lcd.buf[k++] << 1
| lcd.buf[k++];
}
SetPort(g_wp);
CopyBits(&offscreenBmp, &g_wp->portBits, &offscreenRect, &g_wp->portRect, srcCopy, NULL);
//EraseRect(&g_wp->portRect);
MoveTo(10, 160);
char debug[128];
sprintf(debug, "PC: %04x", cpu.pc);
C2PStr(debug);
DrawString(debug);
}
void StartEmulation(void)
@ -57,7 +92,10 @@ void StartEmulation(void)
noGrowDocProc, (WindowPtr) -1, true, 0);
SetPort(g_wp);
offscreenBmp.baseAddr = offscreen;
offscreenBmp.bounds = offscreenRect;
offscreenBmp.rowBytes = 32;
emulationOn = 1;
}
bool LoadRom(StrFileName fileName, short vRefNum)
@ -66,12 +104,11 @@ bool LoadRom(StrFileName fileName, short vRefNum)
short fileNo;
long amtRead;
if(theState.rom != NULL) {
if(rom.data != NULL) {
// unload existing ROM
free((char *) theState.rom);
theState.romLength = 0;
free((char *) rom.data);
rom.length = 0;
}
err = FSOpen(fileName, vRefNum, &fileNo);
@ -79,16 +116,16 @@ bool LoadRom(StrFileName fileName, short vRefNum)
return false;
}
GetEOF(fileNo, (long *) &theState.romLength);
theState.rom = (unsigned char *) malloc(theState.romLength);
if(theState.rom == NULL) {
GetEOF(fileNo, (long *) &rom.length);
rom.data = (unsigned char *) malloc(rom.length);
if(rom.data == NULL) {
Alert(ALRT_NOT_ENOUGH_RAM, NULL);
return false;
}
amtRead = theState.romLength;
amtRead = rom.length;
FSRead(fileNo, &amtRead, theState.rom);
FSRead(fileNo, &amtRead, rom.data);
return true;
}
@ -112,7 +149,6 @@ bool ShowOpenBox(void)
return false;
}
DialogPtr stateDialog;
void ShowStateDialog(void)
{
DialogPtr dp;
@ -207,15 +243,34 @@ void OnMouseDown(EventRecord *pEvt)
}
// -- ENTRY POINT --
int main(int argc, char *argv[])
{
EventRecord evt;
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.pc = 0x100;
int start = TickCount();
while(g_running) {
if(WaitNextEvent(everyEvent, &evt, 10, 0) != nullEvent) {
if (emulationOn) {
dmg_step(&dmg);
int now = TickCount();
if (now > lastTicks + 100) {
lastTicks = now;
Render();
}
}
if(WaitNextEvent(everyEvent, &evt, 0, 0) != nullEvent) {
if (IsDialogEvent(&evt)) {
DialogRef hitBox;
DialogItemIndex hitItem;

View File

@ -44,12 +44,4 @@ typedef unsigned char bool;
#define true 1
#define false 0
typedef struct _emu_state {
struct dmg *cpu;
u8 *rom;
unsigned long int romLength;
} emu_state;
extern emu_state theState;
#endif

View File

@ -4,4 +4,3 @@ void lcd_draw(struct lcd *lcd)
{
}