add more instructions, fix INC/DEC [HL], first attempt at lcd "mode" timing

This commit is contained in:
Matthew Laux 2022-07-25 22:55:13 -05:00
parent 0351226479
commit bc980ec1e5
5 changed files with 96 additions and 21 deletions

View File

@ -27,7 +27,6 @@ static const char *PC_FORMAT = "PC: 0x%02x";
unsigned char output_image[256 * 256 * 4];
unsigned char vram_tiles[256 * 96 * 4];
unsigned char full_address_space[0x10000];
struct key_input {
int scancode;
@ -60,13 +59,15 @@ GLuint make_output_texture() {
return image_texture;
}
unsigned char default_palette[] = { 0, 0x55, 0xaa, 0xff };
void convert_output(struct lcd *lcd) {
int x, y;
int out_index = 0;
for (y = 0; y < 256; y++) {
for (x = 0; x < 256; x++) {
int val = lcd->buf[y * 256 + x];
int fill = 255 - val * 85;
int fill = default_palette[val];
//int fill = val ? 255 : 0;
output_image[out_index++] = fill;
output_image[out_index++] = fill;
@ -103,12 +104,14 @@ void convert_vram(struct dmg *dmg) {
}
}
void fill_memory_editor(struct dmg *dmg)
static ImU8 read_mem(const ImU8* data, size_t off)
{
int k;
for (k = 0; k < 0x10000; k++) {
full_address_space[k] = dmg_read(dmg, k);
}
return dmg_read((void *) data, (u16) off);
}
static void write_mem(ImU8 *data, size_t off, ImU8 d)
{
dmg_write(data, (u16) off, d);
}
// Main code
@ -193,6 +196,9 @@ int main(int argc, char *argv[])
GLuint texture = make_output_texture();
GLuint vram_texture = make_output_texture();
editor.ReadFn = read_mem;
editor.WriteFn = write_mem;
// for flag checkboxes
bool z_flag = false;
bool n_flag = false;
@ -318,10 +324,7 @@ int main(int argc, char *argv[])
ImGui::End();
}
fill_memory_editor(&dmg);
editor.DrawWindow("Memory", full_address_space, 0x10000, 0x0000);
editor.DrawWindow("ROM", dmg.rom->data, 0x8000, 0);
editor.DrawWindow("Memory", &dmg, 0x10000, 0x0000);
// Rendering
ImGui::Render();

View File

@ -515,8 +515,8 @@ void cpu_step(struct cpu *cpu)
case 0x2d: dec_with_carry(cpu, &cpu->l); break;
case 0x33: cpu->sp++; break;
case 0x34: temp = read8(cpu, read_hl(cpu)); inc_with_carry(cpu, &temp); break;
case 0x35: temp = read8(cpu, read_hl(cpu)); dec_with_carry(cpu, &temp); break;
case 0x34: temp = read8(cpu, read_hl(cpu)); inc_with_carry(cpu, &temp); write8(cpu, read_hl(cpu), temp); break;
case 0x35: temp = read8(cpu, read_hl(cpu)); dec_with_carry(cpu, &temp); write8(cpu, read_hl(cpu), temp); break;
case 0x3b: cpu->sp--; break;
case 0x3c: inc_with_carry(cpu, &cpu->a); break;
@ -684,6 +684,20 @@ void cpu_step(struct cpu *cpu)
case 0xc3: // JP a16
cpu->pc = read16(cpu, cpu->pc);
break;
case 0xc4: // CALL NZ, u16
temp16 = read16(cpu, cpu->pc);
cpu->pc += 2;
if (!flag_isset(cpu, FLAG_ZERO)) {
push(cpu, cpu->pc);
cpu->pc = temp16;
}
break;
case 0xd0: // RET NC
if (!flag_isset(cpu, FLAG_CARRY)) {
cpu->pc = pop(cpu);
cpu->cycle_count += instructions[opc].cycles_branch - instructions[opc].cycles;
}
break;
case 0xd2: // JP NC,a16
temp16 = read16(cpu, cpu->pc);
cpu->pc += 2;
@ -692,6 +706,12 @@ void cpu_step(struct cpu *cpu)
cpu->cycle_count += instructions[opc].cycles_branch - instructions[opc].cycles;
}
break;
case 0xd8: // RET C
if (flag_isset(cpu, FLAG_CARRY)) {
cpu->pc = pop(cpu);
cpu->cycle_count += instructions[opc].cycles_branch - instructions[opc].cycles;
}
break;
case 0x80: add(cpu, cpu->b, 0); break;
case 0x81: add(cpu, cpu->c, 0); break;
@ -736,6 +756,11 @@ void cpu_step(struct cpu *cpu)
case 0x9e: subtract(cpu, read8(cpu, read_hl(cpu)), 1, 0); break;
case 0x9f: subtract(cpu, cpu->a, 1, 0); break;
case 0xd6: // SUB A, u8
subtract(cpu, read8(cpu, cpu->pc), 0, 0);
cpu->pc++;
break;
// AND
case 0xa0: and(cpu, cpu->b); break;
case 0xa1: and(cpu, cpu->c); break;
@ -793,6 +818,9 @@ void cpu_step(struct cpu *cpu)
case 0xf7: push(cpu, cpu->pc); cpu->pc = 0x30; break;
case 0xff: push(cpu, cpu->pc); cpu->pc = 0x38; break;
case 0x27: // DAA
break;
case 0x76: // HALT
break;

View File

@ -86,7 +86,7 @@ u8 dmg_read(void *_dmg, u16 address)
// not sure about any of this yet
// commented out bc of memory view window
// fprintf(stderr, "don't know how to read 0x%04x\n", address);
return 0;
return 0xff;
}
}
@ -119,8 +119,8 @@ void dmg_write(void *_dmg, u16 address, u8 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);
dmg->joypad_selected = !(data & (1 << 4));
dmg->action_selected = !(data & (1 << 5));
} else if (address == 0xff0f) {
dmg->interrupt_requested = data;
} else if (address == 0xffff) {
@ -144,22 +144,33 @@ void dmg_step(void *_dmg)
cpu_step(dmg->cpu);
// each line takes 456 cycles
if (dmg->cpu->cycle_count - dmg->last_lcd_update >= 456) {
int cycle_diff = dmg->cpu->cycle_count - dmg->last_lcd_update;
if (cycle_diff >= 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);
if (lcd_isset(dmg->lcd, REG_STAT, STAT_INTR_SOURCE_MATCH)) {
dmg_request_interrupt(dmg, INT_LCDSTAT);
}
} else {
lcd_clear_bit(dmg->lcd, REG_STAT, STAT_FLAG_MATCH);
}
if (next_scanline >= 144 && next_scanline < 154) {
lcd_set_mode(dmg->lcd, 1);
}
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);
if (lcd_isset(dmg->lcd, REG_STAT, STAT_INTR_SOURCE_VBLANK)) {
dmg_request_interrupt(dmg, INT_LCDSTAT);
}
int lcdc = lcd_read(dmg->lcd, REG_LCDC);
int bg_base = (lcdc & LCDC_BG_TILE_MAP) ? 0x9c00 : 0x9800;
@ -186,8 +197,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--) {
dmg->lcd->buf[off] = ((data1 & (1 << i)) ? 1 : 0);// << 1;
//dmg->lcd->buf[off] |= (data1 & (1 << i)) ? 1 : 0;
dmg->lcd->buf[off] = ((data1 & (1 << i)) ? 1 : 0) << 1;
dmg->lcd->buf[off] |= (data2 & (1 << i)) ? 1 : 0;
off++;
}
off += 248;
@ -199,5 +210,19 @@ void dmg_step(void *_dmg)
lcd_copy(dmg->lcd);
lcd_draw(dmg->lcd);
}
} else {
int scan = lcd_read(dmg->lcd, REG_LY);
if (scan < 144) {
if (cycle_diff < 80) {
lcd_set_mode(dmg->lcd, 2);
} else if (cycle_diff < 230) {
// just midpoint between 168 to 291, todo improve
lcd_set_mode(dmg->lcd, 3);
} else {
lcd_set_mode(dmg->lcd, 0);
}
} else {
// in vblank. mode should stay as 1
}
}
}

View File

@ -15,6 +15,18 @@ void lcd_clear_bit(struct lcd *lcd, u16 addr, u8 bit)
lcd_write(lcd, addr, lcd_read(lcd, addr) & ~(1 << bit));
}
int lcd_isset(struct lcd *lcd, u16 addr, u8 bit)
{
u8 val = lcd_read(lcd, addr);
return val & (1 << bit);
}
void lcd_set_mode(struct lcd *lcd, int mode)
{
u8 val = lcd_read(lcd, REG_STAT);
lcd_write(lcd, REG_STAT, (val & 0xfc) | mode);
}
void lcd_new(struct lcd *lcd)
{
lcd->buf = malloc(256 * 256);

View File

@ -24,6 +24,11 @@
#define REG_LCD_LAST REG_WX
#define STAT_FLAG_MATCH 2
#define STAT_INTR_SOURCE_HBLANK 3
#define STAT_INTR_SOURCE_VBLANK 4
#define STAT_INTR_SOURCE_MODE2 5
#define STAT_INTR_SOURCE_MATCH 6
#define LCDC_ENABLE_BG (1 << 0)
#define LCDC_ENABLE_OBJ (1 << 1)
@ -50,6 +55,8 @@ 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);
int lcd_isset(struct lcd *lcd, u16 addr, u8 bit);
void lcd_set_mode(struct lcd *lcd, int mode);
// i feel like i'm going to need to call this every cycle and update regs
int lcd_step(struct lcd *lcd);