@@ 1,3 1,5 @@
+use sm83;
+
export type cart = struct {
- rom0: [16384]u8,
+ sm83::mmu,
};
@@ 1,3 1,5 @@
+// XXX: These if statement chains might be better implemented as a mapping table
+// or something. Dunno.
use sm83;
export type mmu = struct {
@@ 6,12 8,13 @@ export type mmu = struct {
vram: [0x2000]u8,
ram0: [0x1000]u8,
ram1: [0x1000]u8,
+ ram2: [0x80]u8,
sprites: [0xA0]u8,
};
// Creates a new DMG MMU.
export fn new_mmu(cart: *cart) *mmu = {
- return alloc(mmu {
+ let mmu = alloc(mmu {
readb = &mmu_readb,
readw = &mmu_readw,
writeb = &mmu_writeb,
@@ 19,6 22,7 @@ export fn new_mmu(cart: *cart) *mmu = {
cart = cart,
...
});
+ return mmu;
};
// Frees a DMG MMU.
@@ 26,18 30,73 @@ export fn mmu_free(mmu: *mmu) void = {
free(mmu);
};
-fn mmu_readb(mmu: *sm83::mmu, addr: u16) u8 = {
- abort(); // TODO
+fn mmu_readb(mem: *sm83::mmu, addr: u16) u8 = {
+ const mem = mem: *mmu;
+ const base = addr >> 8;
+ if (base >= 0x00 && base < 0x80) {
+ return mem.cart.readb(mem.cart, addr);
+ } else if (base >= 0xA0 && base < 0xC0) {
+ return mem.cart.readb(mem.cart, addr);
+ };
+
+ if (base >= 0xC0 && base < 0xD0) {
+ return mem.ram0[addr - 0xC000];
+ } else if (base >= 0xD0 && base < 0xE0) {
+ return mem.ram1[addr - 0xD000];
+ } else if (base >= 0xE0 && base < 0xF0) {
+ return mem.ram0[addr - 0xE000];
+ } else if (base >= 0xF0 && base < 0xDE) {
+ return mem.ram1[addr - 0xF000];
+ };
+
+ if (addr >= 0xFE00 && addr < 0xFEA0) {
+ return mem.sprites[addr - 0xFE00];
+ };
+
+ if (addr >= 0xFF80 && addr < 0xFFFF) {
+ return mem.ram2[addr - 0xFF80];
+ };
+
+ if (addr >= 0xFF00) {
+ // TODO: I/O
+ return 0;
+ };
+
+ // "Unusable" memory
+ return 0;
};
fn mmu_readw(mmu: *sm83::mmu, addr: u16) u16 = {
- abort(); // TODO
+ const low: u16 = mmu_readb(mmu, addr);
+ const high: u16 = mmu_readb(mmu, addr + 1);
+ return low | (high << 8);
};
-fn mmu_writeb(mmu: *sm83::mmu, addr: u16, b: u8) void = {
- abort(); // TODO
+fn mmu_writeb(mem: *sm83::mmu, addr: u16, b: u8) void = {
+ const mem = mem: *mmu;
+ const base = addr >> 8;
+ if (base >= 0x00 && base < 0x80) {
+ mem.cart.writeb(mem.cart, addr, b);
+ } else if (base >= 0xA0 && base < 0xC0) {
+ mem.cart.writeb(mem.cart, addr, b);
+ } else if (base >= 0xC0 && base < 0xD0) {
+ mem.ram0[addr - 0xC000] = b;
+ } else if (base >= 0xD0 && base < 0xE0) {
+ mem.ram1[addr - 0xD000] = b;
+ } else if (base >= 0xE0 && base < 0xF0) {
+ mem.ram0[addr - 0xE000] = b;
+ } else if (base >= 0xF0 && base < 0xDE) {
+ mem.ram1[addr - 0xF000] = b;
+ } else if (addr >= 0xFE00 && addr < 0xFEA0) {
+ mem.sprites[addr - 0xFE00] = b;
+ } else if (addr >= 0xFF80 && addr < 0xFFFF) {
+ mem.ram2[addr - 0xFF80] = b;
+ } else if (addr >= 0xFF00) {
+ void; // TODO: I/O
+ };
};
fn mmu_writew(mmu: *sm83::mmu, addr: u16, w: u16) void = {
- abort(); // TODO
+ mmu_writeb(mmu, addr, (w & 0xFF): u8);
+ mmu_writeb(mmu, addr + 1, (w >> 8): u8);
};