Skip to content

Commit 1346383

Browse files
committed
tmp
1 parent 9ab3d7b commit 1346383

File tree

8 files changed

+268
-24
lines changed

8 files changed

+268
-24
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ set(gemu_sources
2727
src/instructions.c
2828
src/log.c
2929
src/macros.c
30+
src/mapper.c
3031
src/num.c
3132
src/sdl.c)
3233

src/data.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "data.h"
2+
#include "macros.h"
23

34
bool CartridgeType_has_ram(const CartridgeType self)
45
{
@@ -18,3 +19,29 @@ bool CartridgeType_has_ram(const CartridgeType self)
1819
self == CartridgeType_Mbc7SensorRumbleRamBattery ||
1920
self == CartridgeType_Huc1RamBattery;
2021
}
22+
23+
size_t rom_banks_from_size_code(const u8 rom_size_code)
24+
{
25+
BAIL_IF(rom_size_code > 0x08, "invalid ROM size code: $%02X",
26+
rom_size_code);
27+
28+
return 1 << (rom_size_code + 1);
29+
}
30+
31+
size_t ram_banks_from_size_code(const u8 ram_size_code)
32+
{
33+
switch (ram_size_code) {
34+
case 0x00:
35+
return 0;
36+
case 0x02:
37+
return 1;
38+
case 0x03:
39+
return 4;
40+
case 0x04:
41+
return 16;
42+
case 0x05:
43+
return 8;
44+
default:
45+
BAIL("invalid RAM size code: $%02X", ram_size_code);
46+
}
47+
}

src/data.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,10 @@ typedef enum : u8 {
5252
CartridgeType_Huc1RamBattery = 0xFF,
5353
} CartridgeType;
5454

55-
void CartridgeType_log_info(CartridgeType self);
56-
5755
bool CartridgeType_has_ram(CartridgeType self);
5856

57+
size_t rom_banks_from_size_code(u8 rom_size_code);
58+
59+
size_t ram_banks_from_size_code(u8 ram_size_code);
60+
5961
#endif

src/frontend.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -394,8 +394,8 @@ static void update_texture(const State *const state)
394394

395395
const SDL_PixelFormatDetails *const pixel_format =
396396
SDL_GetPixelFormatDetails(surface->format);
397-
BAIL_IF(pixel_format == nullptr, "Could not get pixel format: %s",
398-
SDL_GetError());
397+
BAIL_IF_NULL(pixel_format, "Could not get pixel format: %s",
398+
SDL_GetError());
399399

400400
SDL_FillSurfaceRect(surface, nullptr,
401401
SDL_MapRGB(pixel_format, nullptr, 0, 0, 0));

src/game_boy.c

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include "data.h"
44
#include "log.h"
55
#include "macros.h"
6+
#include "mapper.h"
67
#include "num.h"
78
#include "stdinc.h"
89
#include "string.h"
@@ -82,16 +83,6 @@ static void GameBoy_reset(GameBoy *const self)
8283

8384
static void GameBoy_validate_rom(const GameBoy *const self)
8485
{
85-
BAIL_IF(self->rom[RomHeader_CartridgeType] != 0x00,
86-
"Unsupported cartridge type (ctype: $%02X)",
87-
self->rom[RomHeader_CartridgeType]);
88-
89-
BAIL_IF(
90-
!CartridgeType_has_ram(self->rom[RomHeader_CartridgeType]) &&
91-
self->rom[RomHeader_RamSize] != 0,
92-
"Cartridge type does not have RAM, but header indicates otherwise (ctype: $%02, RAM size: $%02X)",
93-
self->rom[RomHeader_CartridgeType], self->rom[RomHeader_RamSize]);
94-
9586
BAIL_IF(
9687
self->rom_len != 0x8000 * ((size_t)1 << self->rom[RomHeader_RomSize]),
9788
"Actual ROM size does not match header-specified size. (specified: $%02X, was: $%02X)",
@@ -137,9 +128,11 @@ GameBoy GameBoy_new(const u8 *const boot_rom)
137128
void GameBoy_destroy(GameBoy *const self)
138129
{
139130
free(self->rom);
140-
141131
self->rom = nullptr;
142132
self->rom_len = 0;
133+
134+
Mapper_destroy(self->mapper);
135+
self->mapper = nullptr;
143136
}
144137

145138
void GameBoy_log_cartridge_info(const GameBoy *const self)
@@ -166,12 +159,16 @@ void GameBoy_load_rom(GameBoy *const self, const u8 *const rom,
166159
free(self->rom);
167160

168161
self->rom = malloc(rom_len * sizeof(self->rom[0]));
169-
BAIL_IF(self->rom == nullptr, "Could not allocate memory for new ROM");
162+
BAIL_IF_NULL(self->rom);
170163

171164
memcpy(self->rom, rom, rom_len * sizeof(self->rom[0]));
172165
self->rom_len = rom_len;
173166

174167
GameBoy_validate_rom(self);
168+
169+
Mapper_destroy(self->mapper);
170+
self->mapper = Mapper_from_rom(self->rom, self->rom_len);
171+
175172
GameBoy_reset(self);
176173

177174
if (!self->boot_rom_exists)
@@ -271,15 +268,15 @@ u8 GameBoy_read_mem(const void *const ctx, const u16 addr)
271268
if (self->rom == nullptr)
272269
BAIL("Tried to read non-existing ROM");
273270

274-
// 0000-7FFF (ROM bank)
275-
return self->rom[addr];
271+
// 0000-8FFF (from cartridge)
272+
return Mapper_read(self->mapper, self->rom, self->rom_len, addr);
276273
}
277274

278275
if (addr <= 0x9FFF) // 8000-9FFF (VRAM)
279276
return self->vram[addr - 0x8000];
280277

281-
if (addr <= 0xBFFF) // A000-BFFF (External RAM)
282-
BAIL("TODO: GameBoy_read_mem (addr = $%04X)", addr);
278+
if (addr <= 0xBFFF) // A000-BFFF (from cartridge)
279+
return Mapper_read(self->mapper, self->rom, self->rom_len, addr);
283280

284281
if (addr <= 0xDFFF) // C000-DFFF (WRAM)
285282
return self->ram[addr - 0xC000];
@@ -399,14 +396,13 @@ void GameBoy_write_mem(void *const ctx, const u16 addr, const u8 value)
399396

400397
if (addr <= 0x7FFF) {
401398
// 0000-7FFF (ROM bank)
402-
log_debug("TODO: GameBoy_write_mem ROM (addr = $%04X, $%02X)", addr,
403-
value);
399+
Mapper_write(self->mapper, addr, value);
404400
} else if (addr <= 0x9FFF) {
405401
// 8000-9FFF (VRAM)
406402
self->vram[addr - 0x8000] = value;
407403
} else if (addr <= 0xBFFF) {
408404
// A000-BFFF (External RAM)
409-
BAIL("TODO: GameBoy_write_mem ERAM (addr = $%04X, $%02X)", addr, value);
405+
Mapper_write(self->mapper, addr, value);
410406
} else if (addr <= 0xDFFF) {
411407
// C000-DFFF (WRAM)
412408
self->ram[addr - 0xC000] = value;

src/game_boy.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#define GEMU_GAME_BOY_H
33

44
#include "cpu.h"
5+
#include "mapper.h"
56
#include <stddef.h>
67

78
constexpr int GB_LCD_WIDTH = 160;
@@ -71,6 +72,7 @@ typedef struct {
7172
typedef struct {
7273
JoypadState joypad;
7374
Cpu cpu;
75+
Mapper *mapper;
7476
bool boot_rom_exists;
7577
bool boot_rom_enable;
7678
u8 ram[0x2000];
@@ -120,7 +122,7 @@ typedef struct {
120122
[[nodiscard]] GameBoy GameBoy_new(const u8 *boot_rom);
121123

122124
/**
123-
* \brief Frees a previously-created GameBoy.
125+
* \brief Cleans up a previously-created GameBoy.
124126
*
125127
* \param self the GameBoy to destruct.
126128
*

src/mapper.c

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
#include "mapper.h"
2+
#include "data.h"
3+
#include "macros.h"
4+
#include "stdinc.h"
5+
#include <stddef.h>
6+
#include <stdlib.h>
7+
8+
typedef struct {
9+
u8 (*read)(const Mapper *mapper, const u8 *rom, size_t rom_len, u16 addr);
10+
void (*write)(Mapper *mapper, u16 addr, u8 value);
11+
void (*destroy)(Mapper *mapper);
12+
} MapperInterface;
13+
14+
struct Mapper {
15+
const MapperInterface *const vtable;
16+
};
17+
18+
typedef struct {
19+
Mapper base;
20+
} NoMbcMapper;
21+
22+
typedef struct {
23+
Mapper base;
24+
size_t rom_banks;
25+
size_t rom_bank_num;
26+
u8 banking_mode_sel;
27+
} Mbc1Mapper;
28+
29+
static u8 NoMbcMapper_read([[maybe_unused]] const Mapper *const base,
30+
const u8 *const rom, const size_t rom_len,
31+
const u16 addr)
32+
{
33+
if (addr < rom_len)
34+
return rom[addr];
35+
36+
return 0xFF;
37+
}
38+
39+
static void NoMbcMapper_write([[maybe_unused]] Mapper *const base,
40+
[[maybe_unused]] const u16 addr,
41+
[[maybe_unused]] const u8 value)
42+
{
43+
}
44+
45+
static void NoMbcMapper_destroy([[maybe_unused]] Mapper *const base)
46+
{
47+
}
48+
49+
static u8 Mbc1Mapper_read(const Mapper *const base, const u8 *const rom,
50+
const size_t rom_len, const u16 addr)
51+
{
52+
const Mbc1Mapper *const self = (const void *)base;
53+
54+
if (self->banking_mode_sel == 1)
55+
log_info("read from $%04X, mode = %i", addr, self->banking_mode_sel);
56+
57+
if (addr < 0x4000) // 0000-3FFF (ROM bank X0)
58+
return rom[addr];
59+
60+
if (addr < 0x8000) // 4000-7FFF (ROM bank 01-7F)
61+
return rom[(0x4000 * self->rom_bank_num) + addr - 0x4000];
62+
63+
return 0xFF;
64+
}
65+
66+
static void Mbc1Mapper_write(Mapper *const base, const u16 addr, const u8 value)
67+
{
68+
Mbc1Mapper *const self = (void *)base;
69+
70+
if (addr >= 0x2000 && addr < 0x4000) {
71+
// 2000-3FFFF (ROM bank number)
72+
self->rom_bank_num = (value & 0x11111) % self->rom_banks;
73+
74+
if (self->rom_bank_num == 0)
75+
self->rom_bank_num = 1;
76+
} else if (addr >= 0x6000 && addr < 0x8000) {
77+
// 6000-7FFF (banking mode select)
78+
self->banking_mode_sel = value & 1;
79+
}
80+
}
81+
82+
static void Mbc1Mapper_destroy([[maybe_unused]] Mapper *const base)
83+
{
84+
}
85+
86+
Mapper *Mapper_from_rom(const u8 *rom, const size_t rom_len)
87+
{
88+
BAIL_IF(rom_len < 0x8000);
89+
90+
const u8 ctype = rom[RomHeader_CartridgeType];
91+
const u8 rom_size = rom[RomHeader_RomSize];
92+
const u8 ram_size = rom[RomHeader_RamSize];
93+
94+
BAIL_IF(ram_size == 1, "invalid RAM size");
95+
96+
switch (ctype) {
97+
case CartridgeType_RomOnly: {
98+
static const MapperInterface vtable = {
99+
.read = NoMbcMapper_read,
100+
.write = NoMbcMapper_write,
101+
.destroy = NoMbcMapper_destroy,
102+
};
103+
104+
NoMbcMapper *const mapper = malloc(sizeof(*mapper));
105+
BAIL_IF_NULL(mapper);
106+
107+
const Mapper base = (Mapper){.vtable = &vtable};
108+
memcpy(&mapper->base, &base, sizeof(base));
109+
110+
return &mapper->base;
111+
}
112+
case CartridgeType_Mbc1: {
113+
static const MapperInterface vtable = {
114+
.read = Mbc1Mapper_read,
115+
.write = Mbc1Mapper_write,
116+
.destroy = Mbc1Mapper_destroy,
117+
};
118+
119+
Mbc1Mapper *const mapper = malloc(sizeof(*mapper));
120+
BAIL_IF_NULL(mapper);
121+
122+
const Mapper base = (Mapper){.vtable = &vtable};
123+
memcpy(&mapper->base, &base, sizeof(base));
124+
125+
mapper->banking_mode_sel = 0;
126+
mapper->rom_banks = rom_size;
127+
128+
return &mapper->base;
129+
}
130+
default:
131+
BAIL("unimplemented mapper: $%02X", ctype);
132+
}
133+
}
134+
135+
u8 Mapper_read(const Mapper *const self, const u8 *rom, const size_t rom_len,
136+
u16 addr)
137+
{
138+
BAIL_IF(addr >= 0x8000 && (addr < 0xA000 || addr >= 0xC000),
139+
"unexpected mapper read (addr = $%04X)", addr);
140+
141+
return self->vtable->read(self, rom, rom_len, addr);
142+
}
143+
144+
void Mapper_write(Mapper *const self, const u16 addr, const u8 value)
145+
{
146+
self->vtable->write(self, addr, value);
147+
}
148+
149+
void Mapper_destroy(Mapper *const self)
150+
{
151+
if (self != nullptr) {
152+
self->vtable->destroy(self);
153+
free(self);
154+
}
155+
}

0 commit comments

Comments
 (0)