#include "mbc1.h" #include "mem.h" #include #include namespace mbc1 { #define ROM_BANK_SIZE 0x4000 #define RAM_BANK_SIZE 0x2000 uint8_t bootrom[256]; uint8_t *rom; uint8_t vram[8192]; uint8_t exram[4 * RAM_BANK_SIZE]; uint8_t wram[8192]; uint8_t hram[512]; uint8_t tags[65536]; uint8_t current_rom_bank = 1; uint8_t current_ram_bank = 0; bool ram_enabled = false; bool banking_mode = false; // false = ROM banking mode, true = RAM banking mode uint8_t getKeypad(uint8_t value) { const uint8_t *keys = SDL_GetKeyboardState(NULL); value = value & 0xf0; if (value & 0x10) { if (!keys[SDL_SCANCODE_RETURN]) value = value | 0x8; if (!keys[SDL_SCANCODE_SPACE]) value = value | 0x4; if (!keys[SDL_SCANCODE_Z]) value = value | 0x2; if (!keys[SDL_SCANCODE_X]) value = value | 0x1; } else if (value & 0x20) { if (!keys[SDL_SCANCODE_DOWN]) value = value | 0x8; if (!keys[SDL_SCANCODE_UP]) value = value | 0x4; if (!keys[SDL_SCANCODE_LEFT]) value = value | 0x2; if (!keys[SDL_SCANCODE_RIGHT]) value = value | 0x1; } else { value = value | 0x0f; } return value; } uint8_t readMem(uint16_t address) { if (address < 0x8000) { if ( (address < 0x0100) && ((hram[0x150]&0x01)==0) ) return bootrom[address]; if (address < 0x4000) { // ROM Bank 0 return rom[address]; } else { // Switchable ROM bank uint32_t banked_address = (current_rom_bank * ROM_BANK_SIZE) + (address - 0x4000); return rom[banked_address]; } } else if (address < 0xA000) { return vram[address - 0x8000]; } else if (address < 0xC000) { if (ram_enabled) { uint32_t banked_address = (current_ram_bank * RAM_BANK_SIZE) + (address - 0xA000); return exram[banked_address]; } return 0xFF; // Return open bus value when RAM is disabled } else if (address < 0xE000) { return wram[address - 0xC000]; } else if (address < 0xFE00) { return wram[address - 0xE000]; } else { if (address==0xFF00) { hram[address - 0XFE00] = getKeypad(hram[address - 0XFE00]); } return hram[address - 0XFE00]; } } void writeMem(uint16_t address, uint8_t value) { if (address < 0x8000) { if (address < 0x2000) { // Enable/disable RAM ram_enabled = (value & 0x0F) == 0x0A; } else if (address < 0x4000) { // Select ROM bank value &= 0x1F; // Lower 5 bits are used if (value == 0) value = 1; // Bank 0 is not allowed current_rom_bank = (current_rom_bank & 0x60) | value; } else if (address < 0x6000) { // Select RAM bank or upper bits of ROM bank if (banking_mode) { current_ram_bank = value & 0x03; // 2 bits for RAM bank } else { current_rom_bank = (current_rom_bank & 0x1F) | ((value & 0x03) << 5); } } else { // Select banking mode banking_mode = value & 0x01; } } else if (address < 0xA000) { vram[address - 0x8000] = value; } else if (address < 0xC000) { if (ram_enabled) { uint32_t banked_address = (current_ram_bank * RAM_BANK_SIZE) + (address - 0xA000); exram[banked_address] = value; } } else if (address < 0xE000) { wram[address - 0xC000] = value; } else if (address < 0xFE00) { wram[address - 0xE000] = value; } else { if ( (address==0xFF50) && ((value&0x01) != 1) ) return; //Only allow disabling boot room if ( (address==0xFF00) ) { value = value & 0x30; } if ( (address==0xFF04) ) { hram[address-0xFE00] = 0; return; } if ( (address==0xFF46) ) mem::init_dma_transfer(value); hram[address - 0xFE00] = value; } } uint8_t getTag(uint16_t address) { return tags[address]; } void setTag(uint16_t address, uint8_t value) { tags[address] = value; } void saveState(FILE* f) { } void loadState(FILE *f) { } uint8_t* rawPtr(uint16_t address) { if (address < 0x8000) { if ( (address < 0x0100) && ((hram[0x150]&0x01)==0) ) return &bootrom[address]; if (address < 0x4000) { // ROM Bank 0 return &rom[address]; } else { // Switchable ROM bank uint32_t banked_address = (current_rom_bank * ROM_BANK_SIZE) + (address - 0x4000); return &rom[banked_address]; } } else if (address < 0xA000) { return &vram[address - 0x8000]; } else if (address < 0xC000) { if (ram_enabled) { uint32_t banked_address = (current_ram_bank * RAM_BANK_SIZE) + (address - 0xA000); return &exram[banked_address]; } return nullptr; // Return open bus value when RAM is disabled } else if (address < 0xE000) { return &wram[address - 0xC000]; } else if (address < 0xFE00) { return &wram[address - 0xE000]; } else { return &hram[address - 0XFE00]; } } void reset() { FILE *f = fopen("dmg_boot.bin", "rb"); if (!f) { printf("ABORTING: 'dmg_boot.bin' not found!\n"); exit(1); } fseek(f, 0, SEEK_END); const int size = ftell(f); fseek(f, 0, SEEK_SET); fread(bootrom, size, 1, f); fclose(f); for (int i=0; i<8192; ++i) { vram[i] = 0; } for (int i=0; i<4*RAM_BANK_SIZE; ++i) { exram[i] = 0; } for (int i=0; i<8192; ++i) { wram[i] = 0; } for (int i=0; i<512; ++i) { hram[i] = 0; } for (int i=0; i<65536; ++i) { tags[i] = MEMTAG_NONE; } } void init(uint8_t *rom, uint32_t rom_size, uint32_t ram_size) { mem::readMem = mbc1::readMem; mem::writeMem = mbc1::writeMem; mem::getTag = mbc1::getTag; mem::setTag = mbc1::setTag; mem::saveState = mbc1::saveState; mem::loadState = mbc1::loadState; mem::reset = mbc1::reset; mem::rawPtr = mbc1::rawPtr; mbc1::rom = rom; reset(); } }