starting on lcd

This commit is contained in:
Matt Laux 2019-10-22 01:30:19 -05:00
parent fe43c07883
commit b42faf8149
6 changed files with 100 additions and 6 deletions

View File

@ -1,6 +1,6 @@
#!/bin/sh
mkdir -p build
cd build
cmake ..
cmake -DCMAKE_BUILD_TYPE=Debug ..
make
cd ..

View File

@ -3,13 +3,16 @@
#include "dmg.h"
#include "cpu.h"
#include "rom.h"
#include "lcd.h"
int main(int argc, char *argv[])
{
struct cpu cpu;
struct rom rom;
struct dmg dmg;
int executed = 0;
struct lcd lcd;
int executed;
if (argc < 2) {
printf("no rom specified\n");
@ -24,12 +27,12 @@ int main(int argc, char *argv[])
// this might be too much abstraction but it'll let me
// test the cpu, rom, and dmg independently and use the cpu
// for other non-GB stuff
dmg_new(&dmg, &cpu, &rom);
dmg_new(&dmg, &cpu, &rom, &lcd);
cpu_bind_mem_model(&cpu, &dmg, dmg_read, dmg_write);
cpu.pc = 0;
for (; executed < 100000; executed++) {
for (executed = 0; executed < 100000; executed++) {
cpu_step(&cpu);
}

View File

@ -2,14 +2,16 @@
#include "cpu.h"
#include "rom.h"
#include "lcd.h"
#include "dmg.h"
#include "types.h"
#include "bootstrap.h"
void dmg_new(struct dmg *dmg, struct cpu *cpu, struct rom *rom)
void dmg_new(struct dmg *dmg, struct cpu *cpu, struct rom *rom, struct lcd *lcd)
{
dmg->cpu = cpu;
dmg->rom = rom;
dmg->lcd = lcd;
}
u8 dmg_read(void *_dmg, u16 address)
@ -30,10 +32,13 @@ u8 dmg_read(void *_dmg, u16 address)
return 0;
} else if (address < 0xe000) {
return dmg->main_ram[address - 0xc000];
} else if (lcd_is_valid_addr(address)) {
return lcd_read(dmg->lcd, address);
} else if (address >= 0xff80 && address <= 0xfffe) {
return dmg->zero_page[address - 0xff80];
} else {
// not sure about any of this yet
fprintf(stderr, "don't know how to read 0x%04x\n", address);
return 0;
}
}
@ -54,9 +59,22 @@ void dmg_write(void *_dmg, u16 address, u8 data)
// TODO switchable ram bank
} else if (address < 0xe000) {
dmg->main_ram[address - 0xc000] = data;
} 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 {
// not sure about any of this yet
}
}
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);
lcd_step(dmg->lcd);
}

View File

@ -13,9 +13,12 @@ struct dmg {
u8 zero_page[0x80];
};
void dmg_new(struct dmg *dmg, struct cpu *cpu, struct rom *rom);
void dmg_new(struct dmg *dmg, struct cpu *cpu, struct rom *rom, struct lcd *lcd);
// why did i make these void *
u8 dmg_read(void *dmg, u16 address);
void dmg_write(void *dmg, u16 address, u8 data);
void dmg_step(void *dmg);
#endif

View File

@ -3,6 +3,35 @@
#include "types.h"
#include "lcd.h"
static void 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)
{
lcd_write(lcd, addr, lcd_read(lcd, addr) & ~(1 << bit));
}
u8 lcd_is_valid_addr(u16 addr)
{
return addr >= REG_LCD_BASE && addr <= REG_LCD_LAST;
}
u8 lcd_read(struct lcd *lcd, u16 addr)
{
return lcd->regs[addr - REG_LCD_BASE];
}
void lcd_write(struct lcd *lcd, u16 addr, u8 value)
{
if (addr == REG_LY) {
// writing to this register always resets it
value = 0;
}
lcd->regs[addr - REG_LCD_BASE] = value;
}
void lcd_put_pixel(struct lcd *lcd, u8 x, u8 y, u8 value)
{
if (x >= LCD_WIDTH || y >= LCD_HEIGHT) {
@ -10,4 +39,18 @@ void lcd_put_pixel(struct lcd *lcd, u8 x, u8 y, u8 value)
return;
}
lcd->pixels[y * LCD_WIDTH + x] = value;
}
void 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

@ -6,10 +6,37 @@
#define LCD_WIDTH 160
#define LCD_HEIGHT 144
#define REG_LCD_BASE 0xff40
#define REG_LCDC 0xff40
#define REG_STAT 0xff41
#define REG_SCY 0xff42
#define REG_SCX 0xff43
#define REG_LY 0xff44
#define REG_LYC 0xff45
#define REG_DMA 0xff46
#define REG_BGP 0xff47
#define REG_OBP0 0xff48
#define REG_OBP1 0xff49
#define REG_WY 0xff4a
#define REG_WX 0xff4b
#define REG_LCD_LAST REG_WX
#define STAT_FLAG_MATCH 2
struct lcd {
u8 regs[0x0c];
u8 *pixels;
};
u8 lcd_is_valid_addr(u16 addr);
u8 lcd_read(struct lcd *lcd, u16 addr);
void lcd_write(struct lcd *lcd, u16 addr, u8 value);
void lcd_put_pixel(struct lcd *lcd, u8 x, u8 y, u8 value);
// i feel like i'm going to need to call this every cycle and update regs
void lcd_step(struct lcd *lcd);
#endif