#include "mem.h" #include "sm83.h" #include #include #include #include "APU.h" #include "mbc_none.h" #include "mbc1.h" #define DIV hram[0x104] // 0xff04 - 0xfe00 #define TIMA hram[0x105] // 0xff05 - 0xfe00 #define TMA hram[0x106] // 0xff06 - 0xfe00 #define TAC hram[0x107] // 0xff07 - 0xfe00 namespace mem { void (*resetMbc)(void); uint8_t (*readRom)(uint16_t); void (*writeRom)(uint16_t, uint8_t); uint8_t (*readRam)(uint16_t); void (*writeRam)(uint16_t, uint8_t); uint8_t bootrom[256]; uint8_t *rom; uint8_t vram[8192]; uint8_t wram[8192]; uint8_t hram[512]; uint8_t tags[65536]; char *title = nullptr; uint32_t rom_size = 0; uint32_t ram_size = 0; uint16_t dma_address = 0; uint8_t dma_pos = 160; uint16_t dma_dots = 0; uint16_t div_counter = 0; uint16_t timer_counter = 0; void init(uint8_t* rom, const int size) { title = (char*)&rom[0x134]; uint8_t mapper_type = rom[0x147]; rom_size = 32768 * (1 << rom[0x148]); int sizes[] = { 0, 0, 8, 32, 128, 64}; ram_size = sizes[rom[0x149]] * 1024; switch (mapper_type) { case 0x00: mbc_none::init(rom, rom_size, ram_size); mem::resetMbc = mbc_none::reset; mem::readRom = mbc_none::readRom; mem::writeRom = mbc_none::writeRom; mem::readRam = mbc_none::readRam; mem::writeRam = mbc_none::writeRam; break; case 0x01: case 0x02: case 0x03: mbc1::init(rom, rom_size, ram_size); mem::resetMbc = mbc1::reset; mem::readRom = mbc1::readRom; mem::writeRom = mbc1::writeRom; mem::readRam = mbc1::readRam; mem::writeRam = mbc1::writeRam; break; }; APU::init(); } 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<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; } resetMbc(); APU::reset(); } 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]; return readRom(address); } else if (address < 0xA000) { return vram[address - 0x8000]; } else if (address < 0xC000) { return readRam(address); } 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]); } else if (address>=0xFF10 && address<=0xFF3F) { return APU::readRegister(address); } return hram[address - 0XFE00]; } } void writeMem(uint16_t address, uint8_t value) { if (address < 0x8000) { writeRom(address, value); } else if (address < 0xA000) { vram[address - 0x8000] = value; } else if (address < 0xC000) { writeRam(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 } else if ( (address==0xFF00) ) { value = value & 0x30; } else if ( (address==0xFF04) ) { hram[address-0xFE00] = 0; return; } else if ( (address==0xFF0F) ) { // IF hram[address-0xFE00] = value; sm83::processInterrupts(); return; } else if (address>=0xFF10 && address<=0xFF3F) { // APU APU::writeRegister(address, value); return; } else if ( (address==0xFF46) ) { // OAM DMA 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) { return &hram[address-0xfe00]; } void init_dma_transfer(uint8_t source) { dma_address = source << 8; dma_pos = 0; dma_dots = 0; } uint16_t timer_frequencies[4] { 256*4, 4*4, 16*4, 64*4 }; void update_mapped(const uint32_t dt) { // DIV Divider register (0xFF04) (val com a timer bàsic) div_counter += dt; if (div_counter>=256) { div_counter -= 256; bool bitset = DIV&0x10; DIV++; if (bitset && !(DIV&0x10)) APU::incDIVAPU(); } // Timer if (TAC&0x4) { // if bit 3 of mem(0xff07) is 1, timer enabled uint16_t freq = timer_frequencies[TAC&0x03]; timer_counter += dt; if (timer_counter>=freq) { timer_counter -= freq; if (TIMA<255) TIMA++; else { TIMA = TMA; sm83::interrupt(INTERRUPT_TIMER); } } } // APU APU::update(dt); // OAM DMA if (dma_pos<160) { dma_dots += dt; while (dma_dots >= 4 && dma_pos<160) { dma_dots -= 4; hram[dma_pos] = mem::readMem(dma_address|dma_pos); dma_pos++; } } } }