render objs, fix bug with SRL, tetris is playable

This commit is contained in:
Matthew Laux 2022-08-01 21:26:31 -05:00
parent 580c349fc7
commit 0f43ebf4cc
3 changed files with 96 additions and 34 deletions

View File

@ -59,7 +59,7 @@ GLuint make_output_texture() {
return image_texture;
}
unsigned char default_palette[] = { 0, 0x55, 0xaa, 0xff };
unsigned char default_palette[] = { 0xff, 0xaa, 0x55, 0x00 };
void convert_output(struct lcd *lcd) {
int x, y;

View File

@ -213,7 +213,7 @@ static u8 srl(struct cpu *cpu, u8 value)
}
clear_flag(cpu, FLAG_SIGN);
clear_flag(cpu, FLAG_HALF_CARRY);
return 0;
return result;
}
static u8 swap(struct cpu *cpu, u8 value)
@ -761,7 +761,7 @@ void cpu_step(struct cpu *cpu)
case 0xd2: // JP NC,a16
temp16 = read16(cpu, cpu->pc);
cpu->pc += 2;
if (flag_isset(cpu, FLAG_CARRY)) {
if (!flag_isset(cpu, FLAG_CARRY)) {
cpu->pc = temp16;
cpu->cycle_count += instructions[opc].cycles_branch - instructions[opc].cycles;
}
@ -772,6 +772,14 @@ void cpu_step(struct cpu *cpu)
cpu->cycle_count += instructions[opc].cycles_branch - instructions[opc].cycles;
}
break;
case 0xda: // JP C, u16
temp16 = read16(cpu, cpu->pc);
cpu->pc += 2;
if (flag_isset(cpu, FLAG_CARRY)) {
cpu->pc = temp16;
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;

132
src/dmg.c
View File

@ -95,11 +95,9 @@ void dmg_write(void *_dmg, u16 address, u8 data)
struct dmg *dmg = (struct dmg *) _dmg;
if (address < 0x4000) {
printf("warning: writing 0x%04x in rom\n", address);
dmg->rom->data[address] = data;
} else if (address < 0x8000) {
// TODO switchable rom bank
printf("warning: writing 0x%04x in rom\n", address);
dmg->rom->data[address] = data;
} else if (address < 0xa000) {
dmg->video_ram[address - 0x8000] = data;
} else if (address < 0xc000) {
@ -135,44 +133,9 @@ void dmg_request_interrupt(struct dmg *dmg, int nr)
dmg->interrupt_requested |= nr;
}
void dmg_step(void *_dmg)
// TODO move to lcd.c, it needs to be able to access dmg_read though
static void render_background(struct dmg *dmg, int lcdc)
{
struct dmg *dmg = (struct dmg *) _dmg;
// order of dependencies? i think cpu needs to step first then update
// all other hw
cpu_step(dmg->cpu);
// each line takes 456 cycles
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);
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);
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;
int window_base = (lcdc & LCDC_WINDOW_TILE_MAP) ? 0x9c00 : 0x9800;
int use_unsigned = lcdc & LCDC_BG_TILE_DATA;
@ -205,6 +168,97 @@ void dmg_step(void *_dmg)
}
}
}
}
struct oam_entry {
u8 pos_y;
u8 pos_x;
u8 tile;
u8 attrs;
};
// TODO: only ten per scanline, priority
static void render_objs(struct dmg *dmg)
{
struct oam_entry *oam = (struct oam_entry *) dmg->lcd->oam;
int k, lcd_x, lcd_y, off;
for (k = 0; k < 40; k++, oam++) {
if (oam->pos_y == 0 || oam->pos_y >= 160) {
continue;
}
if (oam->pos_x == 0 || oam->pos_y >= 168) {
continue;
}
lcd_x = oam->pos_x - 8;
lcd_y = oam->pos_y - 16;
off = 256 * lcd_y + lcd_x;
int eff_addr = 0x8000 + 16 * oam->tile;
int b, i;
for (b = 0; b < 16; b += 2) {
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] |= (data2 & (1 << i)) ? 1 : 0;
off++;
}
off += 248;
}
}
}
void dmg_step(void *_dmg)
{
struct dmg *dmg = (struct dmg *) _dmg;
// order of dependencies? i think cpu needs to step first then update
// all other hw
cpu_step(dmg->cpu);
// each line takes 456 cycles
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);
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);
}
// TODO: do all of this per-scanline instead of everything in vblank
if (next_scanline == 144) {
// vblank has started, draw all the stuff from ram into the lcd
dmg_request_interrupt(dmg, INT_VBLANK);
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);
if (lcdc & LCDC_ENABLE_BG) {
render_background(dmg, lcdc);
}
if (lcdc & LCDC_ENABLE_WINDOW) {
// printf("window\n");
}
if (lcdc & LCDC_ENABLE_OBJ) {
render_objs(dmg);
}
// now copy 256x256 buf to 160x144 based on window registers
lcd_copy(dmg->lcd);