gameboy wormboy manboy gameworm gameman wormgame mangame manworm
Dependencies: mbed SDFileSystem2
mem.cpp@17:c9afe1a7b423, 2019-01-13 (annotated)
- Committer:
- dicarloj
- Date:
- Sun Jan 13 19:00:10 2019 +0000
- Revision:
- 17:c9afe1a7b423
a
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
dicarloj | 17:c9afe1a7b423 | 1 | #define NDEBUG |
dicarloj | 17:c9afe1a7b423 | 2 | #include <assert.h> |
dicarloj | 17:c9afe1a7b423 | 3 | #include <stdlib.h> |
dicarloj | 17:c9afe1a7b423 | 4 | #include <mbed.h> |
dicarloj | 17:c9afe1a7b423 | 5 | |
dicarloj | 17:c9afe1a7b423 | 6 | #include "mem.h" |
dicarloj | 17:c9afe1a7b423 | 7 | #include "platform.h" |
dicarloj | 17:c9afe1a7b423 | 8 | |
dicarloj | 17:c9afe1a7b423 | 9 | #define DANGER_MODE |
dicarloj | 17:c9afe1a7b423 | 10 | |
dicarloj | 17:c9afe1a7b423 | 11 | MemState globalMemState; |
dicarloj | 17:c9afe1a7b423 | 12 | |
dicarloj | 17:c9afe1a7b423 | 13 | void CartInfo::print() { |
dicarloj | 17:c9afe1a7b423 | 14 | printf("Gameboy Cartridge\n" |
dicarloj | 17:c9afe1a7b423 | 15 | "\ttitle: %s\n" |
dicarloj | 17:c9afe1a7b423 | 16 | "\tisColor: 0x%x\n" |
dicarloj | 17:c9afe1a7b423 | 17 | "\tSGB: 0x%x\n" |
dicarloj | 17:c9afe1a7b423 | 18 | "\tcartType: 0x%x\n" |
dicarloj | 17:c9afe1a7b423 | 19 | "\tromSize: 0x%x\n" |
dicarloj | 17:c9afe1a7b423 | 20 | "\tramSize: 0x%x\n" |
dicarloj | 17:c9afe1a7b423 | 21 | "\tnotJapan: 0x%x\n", |
dicarloj | 17:c9afe1a7b423 | 22 | title, isColor, SGB, (u8)cartType, (u8)romSize, (u8)ramSize, notJapan); |
dicarloj | 17:c9afe1a7b423 | 23 | } |
dicarloj | 17:c9afe1a7b423 | 24 | |
dicarloj | 17:c9afe1a7b423 | 25 | // number of banks for given cartridge types |
dicarloj | 17:c9afe1a7b423 | 26 | static const u8 romSizeIDToNBanks[7] = {2,4,8,16,32,64,128}; |
dicarloj | 17:c9afe1a7b423 | 27 | static const u8 ramSizeIDToNBanks[5] = {0,1,1,4,4}; |
dicarloj | 17:c9afe1a7b423 | 28 | static u8* fileData = nullptr; |
dicarloj | 17:c9afe1a7b423 | 29 | |
dicarloj | 17:c9afe1a7b423 | 30 | void saveGame() { |
dicarloj | 17:c9afe1a7b423 | 31 | FileLoadData fld; |
dicarloj | 17:c9afe1a7b423 | 32 | fld.size = 0x2000 * globalMemState.nRamBanks; |
dicarloj | 17:c9afe1a7b423 | 33 | fld.data = globalMemState.mappedRamAllocation; |
dicarloj | 17:c9afe1a7b423 | 34 | saveFile("savegame.gam", fld); |
dicarloj | 17:c9afe1a7b423 | 35 | } |
dicarloj | 17:c9afe1a7b423 | 36 | |
dicarloj | 17:c9afe1a7b423 | 37 | void loadGame() { |
dicarloj | 17:c9afe1a7b423 | 38 | FileLoadData fld = loadFile("savegame.gam"); |
dicarloj | 17:c9afe1a7b423 | 39 | memcpy(globalMemState.mappedRamAllocation, fld.data, 0x2000 * globalMemState.nRamBanks); |
dicarloj | 17:c9afe1a7b423 | 40 | } |
dicarloj | 17:c9afe1a7b423 | 41 | |
dicarloj | 17:c9afe1a7b423 | 42 | |
dicarloj | 17:c9afe1a7b423 | 43 | |
dicarloj | 17:c9afe1a7b423 | 44 | |
dicarloj | 17:c9afe1a7b423 | 45 | void initMem(FileLoadData file) { |
dicarloj | 17:c9afe1a7b423 | 46 | CartInfo* cartInfo = (CartInfo*)(file.data + CART_INFO_ADDR); |
dicarloj | 17:c9afe1a7b423 | 47 | cartInfo->print(); |
dicarloj | 17:c9afe1a7b423 | 48 | fileData = file.data; |
dicarloj | 17:c9afe1a7b423 | 49 | printf("ROM size: 0x%x bytes\n", file.size); |
dicarloj | 17:c9afe1a7b423 | 50 | |
dicarloj | 17:c9afe1a7b423 | 51 | |
dicarloj | 17:c9afe1a7b423 | 52 | globalMemState.inBios = true; // start in BIOS mode |
dicarloj | 17:c9afe1a7b423 | 53 | globalMemState.rom0 = file.data; // ROM-bank 0 is the bottom of the cartridge |
dicarloj | 17:c9afe1a7b423 | 54 | |
dicarloj | 17:c9afe1a7b423 | 55 | // initialize everything to zero |
dicarloj | 17:c9afe1a7b423 | 56 | globalMemState.mappedRom = nullptr; |
dicarloj | 17:c9afe1a7b423 | 57 | globalMemState.nRamBanks = 0; |
dicarloj | 17:c9afe1a7b423 | 58 | globalMemState.nRomBanks = 0; |
dicarloj | 17:c9afe1a7b423 | 59 | globalMemState.vram = nullptr; |
dicarloj | 17:c9afe1a7b423 | 60 | globalMemState.mappedRam = nullptr; |
dicarloj | 17:c9afe1a7b423 | 61 | globalMemState.disabledMappedRam = nullptr; |
dicarloj | 17:c9afe1a7b423 | 62 | globalMemState.mappedRamAllocation = nullptr; |
dicarloj | 17:c9afe1a7b423 | 63 | globalMemState.internalRam = nullptr; |
dicarloj | 17:c9afe1a7b423 | 64 | globalMemState.upperRam = nullptr; |
dicarloj | 17:c9afe1a7b423 | 65 | |
dicarloj | 17:c9afe1a7b423 | 66 | switch(cartInfo->cartType) { |
dicarloj | 17:c9afe1a7b423 | 67 | case ROM_ONLY: |
dicarloj | 17:c9afe1a7b423 | 68 | globalMemState.mappedRom = file.data + 0x4000; // maps in upper ROM by default |
dicarloj | 17:c9afe1a7b423 | 69 | break; |
dicarloj | 17:c9afe1a7b423 | 70 | |
dicarloj | 17:c9afe1a7b423 | 71 | case ROM_MBC1: |
dicarloj | 17:c9afe1a7b423 | 72 | globalMemState.mappedRom = file.data + 0x4000; // maps in upper ROM by default |
dicarloj | 17:c9afe1a7b423 | 73 | globalMemState.mbcType = 1; |
dicarloj | 17:c9afe1a7b423 | 74 | if((u8)cartInfo->romSize < 7) { |
dicarloj | 17:c9afe1a7b423 | 75 | globalMemState.nRomBanks = romSizeIDToNBanks[(u8)cartInfo->romSize]; // has ROM banks |
dicarloj | 17:c9afe1a7b423 | 76 | } else { |
dicarloj | 17:c9afe1a7b423 | 77 | printf("unknown number of rom banks\n"); |
dicarloj | 17:c9afe1a7b423 | 78 | assert(false); |
dicarloj | 17:c9afe1a7b423 | 79 | } |
dicarloj | 17:c9afe1a7b423 | 80 | break; |
dicarloj | 17:c9afe1a7b423 | 81 | |
dicarloj | 17:c9afe1a7b423 | 82 | case ROM_MBC1_RAM: |
dicarloj | 17:c9afe1a7b423 | 83 | globalMemState.mappedRom = file.data + 0x4000; // maps in upper ROM by default |
dicarloj | 17:c9afe1a7b423 | 84 | globalMemState.mbcType = 1; |
dicarloj | 17:c9afe1a7b423 | 85 | if((u8)cartInfo->romSize < 7) { |
dicarloj | 17:c9afe1a7b423 | 86 | globalMemState.nRomBanks = romSizeIDToNBanks[(u8)cartInfo->romSize]; // has ROM banks |
dicarloj | 17:c9afe1a7b423 | 87 | } else { |
dicarloj | 17:c9afe1a7b423 | 88 | printf("unknown number of rom banks\n"); |
dicarloj | 17:c9afe1a7b423 | 89 | assert(false); |
dicarloj | 17:c9afe1a7b423 | 90 | } |
dicarloj | 17:c9afe1a7b423 | 91 | |
dicarloj | 17:c9afe1a7b423 | 92 | if((u8)cartInfo->ramSize < 5) { |
dicarloj | 17:c9afe1a7b423 | 93 | globalMemState.nRamBanks = ramSizeIDToNBanks[(u8)cartInfo->ramSize]; // has RAM banks |
dicarloj | 17:c9afe1a7b423 | 94 | } else { |
dicarloj | 17:c9afe1a7b423 | 95 | printf("unknown number of ram banks\n"); |
dicarloj | 17:c9afe1a7b423 | 96 | assert(false); |
dicarloj | 17:c9afe1a7b423 | 97 | } |
dicarloj | 17:c9afe1a7b423 | 98 | break; |
dicarloj | 17:c9afe1a7b423 | 99 | |
dicarloj | 17:c9afe1a7b423 | 100 | case ROM_MBC3_RAM_BATT: |
dicarloj | 17:c9afe1a7b423 | 101 | case ROM_MBC3_TIMER_RAM_BATT: |
dicarloj | 17:c9afe1a7b423 | 102 | globalMemState.mappedRom = file.data + 0x4000; // maps in upper ROM by default |
dicarloj | 17:c9afe1a7b423 | 103 | globalMemState.mbcType = 3; |
dicarloj | 17:c9afe1a7b423 | 104 | if((u8)cartInfo->romSize < 7) { |
dicarloj | 17:c9afe1a7b423 | 105 | globalMemState.nRomBanks = romSizeIDToNBanks[(u8)cartInfo->romSize]; // has ROM banks |
dicarloj | 17:c9afe1a7b423 | 106 | } else { |
dicarloj | 17:c9afe1a7b423 | 107 | printf("unknown number of rom banks\n"); |
dicarloj | 17:c9afe1a7b423 | 108 | assert(false); |
dicarloj | 17:c9afe1a7b423 | 109 | } |
dicarloj | 17:c9afe1a7b423 | 110 | |
dicarloj | 17:c9afe1a7b423 | 111 | if((u8)cartInfo->ramSize < 5) { |
dicarloj | 17:c9afe1a7b423 | 112 | globalMemState.nRamBanks = ramSizeIDToNBanks[(u8)cartInfo->ramSize]; // has RAM banks |
dicarloj | 17:c9afe1a7b423 | 113 | } else { |
dicarloj | 17:c9afe1a7b423 | 114 | printf("unknown number of ram banks\n"); |
dicarloj | 17:c9afe1a7b423 | 115 | } |
dicarloj | 17:c9afe1a7b423 | 116 | break; |
dicarloj | 17:c9afe1a7b423 | 117 | default: |
dicarloj | 17:c9afe1a7b423 | 118 | printf("unknown cart type 0x%x\n", (u8)cartInfo->cartType); |
dicarloj | 17:c9afe1a7b423 | 119 | assert(false); |
dicarloj | 17:c9afe1a7b423 | 120 | break; |
dicarloj | 17:c9afe1a7b423 | 121 | } |
dicarloj | 17:c9afe1a7b423 | 122 | |
dicarloj | 17:c9afe1a7b423 | 123 | printf("mbc%d\n", globalMemState.mbcType); |
dicarloj | 17:c9afe1a7b423 | 124 | printf("rom-banks: %d\n", globalMemState.nRomBanks); |
dicarloj | 17:c9afe1a7b423 | 125 | printf("ram-banks: %d\n", globalMemState.nRamBanks); |
dicarloj | 17:c9afe1a7b423 | 126 | |
dicarloj | 17:c9afe1a7b423 | 127 | // allocate cartridge RAM (8 KB * # of banks) |
dicarloj | 17:c9afe1a7b423 | 128 | if(globalMemState.nRamBanks) { |
dicarloj | 17:c9afe1a7b423 | 129 | globalMemState.mappedRamAllocation = (u8*)malloc(0x2000 * globalMemState.nRamBanks); |
dicarloj | 17:c9afe1a7b423 | 130 | memset((void*)globalMemState.mappedRamAllocation, 0, 0x2000 * globalMemState.nRamBanks); |
dicarloj | 17:c9afe1a7b423 | 131 | globalMemState.disabledMappedRam = globalMemState.mappedRamAllocation; |
dicarloj | 17:c9afe1a7b423 | 132 | } else { |
dicarloj | 17:c9afe1a7b423 | 133 | |
dicarloj | 17:c9afe1a7b423 | 134 | } |
dicarloj | 17:c9afe1a7b423 | 135 | |
dicarloj | 17:c9afe1a7b423 | 136 | // allocate memories: |
dicarloj | 17:c9afe1a7b423 | 137 | // internal RAM |
dicarloj | 17:c9afe1a7b423 | 138 | globalMemState.internalRam = (u8*)badalloc_check(0x2000, "internal_ram"); |
dicarloj | 17:c9afe1a7b423 | 139 | globalMemState.vram = (u8*)badalloc_check(0x2000, "vram"); |
dicarloj | 17:c9afe1a7b423 | 140 | globalMemState.upperRam = (u8*)badalloc_check(0x80, "upper-regs"); |
dicarloj | 17:c9afe1a7b423 | 141 | globalMemState.ioRegs = (u8*)badalloc_check(0x80, "io-regs"); |
dicarloj | 17:c9afe1a7b423 | 142 | |
dicarloj | 17:c9afe1a7b423 | 143 | printf("[initRam] ioRegs: 0x%x\n", globalMemState.ioRegs); |
dicarloj | 17:c9afe1a7b423 | 144 | |
dicarloj | 17:c9afe1a7b423 | 145 | // clear RAMs |
dicarloj | 17:c9afe1a7b423 | 146 | memset(globalMemState.internalRam, 0, 0x2000); |
dicarloj | 17:c9afe1a7b423 | 147 | memset(globalMemState.vram, 0, 0x2000); |
dicarloj | 17:c9afe1a7b423 | 148 | memset(globalMemState.upperRam, 0, 0x80); |
dicarloj | 17:c9afe1a7b423 | 149 | memset(globalMemState.ioRegs, 0, 0x80); |
dicarloj | 17:c9afe1a7b423 | 150 | |
dicarloj | 17:c9afe1a7b423 | 151 | // setup i/o regs and friends |
dicarloj | 17:c9afe1a7b423 | 152 | u8* io = globalMemState.ioRegs; |
dicarloj | 17:c9afe1a7b423 | 153 | io[IO_TIMA] = 0; // reset TIMER COUNT to 0 |
dicarloj | 17:c9afe1a7b423 | 154 | io[IO_TMA] = 0; // TIMER RELOAD |
dicarloj | 17:c9afe1a7b423 | 155 | io[IO_TAC] = 0; // TIMER STOP |
dicarloj | 17:c9afe1a7b423 | 156 | io[IO_NR10] = 0x80; |
dicarloj | 17:c9afe1a7b423 | 157 | io[IO_NR11] = 0xbf; |
dicarloj | 17:c9afe1a7b423 | 158 | io[IO_NR12] = 0xf3; |
dicarloj | 17:c9afe1a7b423 | 159 | io[IO_NR14] = 0xbf; |
dicarloj | 17:c9afe1a7b423 | 160 | io[IO_NR21] = 0x3f; |
dicarloj | 17:c9afe1a7b423 | 161 | io[IO_NR22] = 0x00; |
dicarloj | 17:c9afe1a7b423 | 162 | io[IO_NR24] = 0xbf; |
dicarloj | 17:c9afe1a7b423 | 163 | io[IO_NR30] = 0x7f; |
dicarloj | 17:c9afe1a7b423 | 164 | io[IO_NR31] = 0xff; |
dicarloj | 17:c9afe1a7b423 | 165 | io[IO_NR32] = 0x9f; |
dicarloj | 17:c9afe1a7b423 | 166 | io[IO_NR34] = 0xbf; |
dicarloj | 17:c9afe1a7b423 | 167 | io[IO_NR41] = 0xff; |
dicarloj | 17:c9afe1a7b423 | 168 | io[IO_NR42] = 0x00; |
dicarloj | 17:c9afe1a7b423 | 169 | io[IO_NR43] = 0x00; |
dicarloj | 17:c9afe1a7b423 | 170 | io[IO_NR44] = 0xbf; |
dicarloj | 17:c9afe1a7b423 | 171 | io[IO_NR50] = 0x77; |
dicarloj | 17:c9afe1a7b423 | 172 | io[IO_NR51] = 0xf3; |
dicarloj | 17:c9afe1a7b423 | 173 | io[IO_NR52] = 0xf1; |
dicarloj | 17:c9afe1a7b423 | 174 | io[IO_LCDC] = 0x91; |
dicarloj | 17:c9afe1a7b423 | 175 | io[IO_SCROLLY] = 0x00; |
dicarloj | 17:c9afe1a7b423 | 176 | io[IO_SCROLLX] = 0x00; |
dicarloj | 17:c9afe1a7b423 | 177 | io[IO_LYC] = 0x00; |
dicarloj | 17:c9afe1a7b423 | 178 | io[IO_BGP] = 0xfc; |
dicarloj | 17:c9afe1a7b423 | 179 | io[IO_OBP0] = 0xff; |
dicarloj | 17:c9afe1a7b423 | 180 | io[IO_OBP1] = 0xff; |
dicarloj | 17:c9afe1a7b423 | 181 | io[IO_WINY] = 0x00; |
dicarloj | 17:c9afe1a7b423 | 182 | io[IO_WINX] = 0x00; |
dicarloj | 17:c9afe1a7b423 | 183 | |
dicarloj | 17:c9afe1a7b423 | 184 | // turn off interrupts |
dicarloj | 17:c9afe1a7b423 | 185 | globalMemState.upperRam[0x7f] = 0; |
dicarloj | 17:c9afe1a7b423 | 186 | } |
dicarloj | 17:c9afe1a7b423 | 187 | |
dicarloj | 17:c9afe1a7b423 | 188 | |
dicarloj | 17:c9afe1a7b423 | 189 | // boot ROM |
dicarloj | 17:c9afe1a7b423 | 190 | static const u8 bios[256] = {0x31, 0xFE, 0xFF, // LD, SP, $fffe 0 |
dicarloj | 17:c9afe1a7b423 | 191 | 0xAF, // XOR A 3 |
dicarloj | 17:c9afe1a7b423 | 192 | 0x21, 0xFF, 0x9F, // LD HL, $9fff 4 |
dicarloj | 17:c9afe1a7b423 | 193 | 0x32, // LD (HL--), A 7 |
dicarloj | 17:c9afe1a7b423 | 194 | 0xCB, 0x7C, // BIT 7, H 8 |
dicarloj | 17:c9afe1a7b423 | 195 | 0x20, 0xFB, // JR NZ 7 a |
dicarloj | 17:c9afe1a7b423 | 196 | 0x21, 0x26, 0xFF, // LD HL, $ff26 c |
dicarloj | 17:c9afe1a7b423 | 197 | 0x0E, 0x11, // LD c,$11 f |
dicarloj | 17:c9afe1a7b423 | 198 | 0x3E, 0x80, // LD a,$80 11 |
dicarloj | 17:c9afe1a7b423 | 199 | 0x32, // LD (HL--), A 13 |
dicarloj | 17:c9afe1a7b423 | 200 | 0xE2, // LD($FF00+C),A 14 |
dicarloj | 17:c9afe1a7b423 | 201 | 0x0C, // INC C 15 |
dicarloj | 17:c9afe1a7b423 | 202 | 0x3E, 0xF3, // LD A, $f3 16 |
dicarloj | 17:c9afe1a7b423 | 203 | 0xE2, // LD (HL--), A 18 |
dicarloj | 17:c9afe1a7b423 | 204 | 0x32, // LD($FF00+C),A 19 |
dicarloj | 17:c9afe1a7b423 | 205 | 0x3E, 0x77, // LD A,$77 1a |
dicarloj | 17:c9afe1a7b423 | 206 | 0x77, 0x3E, 0xFC, 0xE0, |
dicarloj | 17:c9afe1a7b423 | 207 | 0x47, 0x11, 0x04, 0x01, 0x21, 0x10, 0x80, 0x1A, 0xCD, 0x95, 0x00, 0xCD, 0x96, 0x00, 0x13, 0x7B, |
dicarloj | 17:c9afe1a7b423 | 208 | 0xFE, 0x34, 0x20, 0xF3, 0x11, 0xD8, 0x00, 0x06, 0x08, 0x1A, 0x13, 0x22, 0x23, 0x05, 0x20, 0xF9, |
dicarloj | 17:c9afe1a7b423 | 209 | 0x3E, 0x19, 0xEA, 0x10, 0x99, 0x21, 0x2F, 0x99, 0x0E, 0x0C, 0x3D, 0x28, 0x08, 0x32, 0x0D, 0x20, |
dicarloj | 17:c9afe1a7b423 | 210 | 0xF9, 0x2E, 0x0F, 0x18, 0xF3, 0x67, 0x3E, 0x64, 0x57, 0xE0, 0x42, 0x3E, 0x91, 0xE0, 0x40, 0x04, |
dicarloj | 17:c9afe1a7b423 | 211 | 0x1E, 0x02, 0x0E, 0x0C, 0xF0, 0x44, 0xFE, 0x90, 0x20, 0xFA, 0x0D, 0x20, 0xF7, 0x1D, 0x20, 0xF2, |
dicarloj | 17:c9afe1a7b423 | 212 | 0x0E, 0x13, 0x24, 0x7C, 0x1E, 0x83, 0xFE, 0x62, 0x28, 0x06, 0x1E, 0xC1, 0xFE, 0x64, 0x20, 0x06, |
dicarloj | 17:c9afe1a7b423 | 213 | 0x7B, 0xE2, 0x0C, 0x3E, 0x87, 0xF2, 0xF0, 0x42, 0x90, 0xE0, 0x42, 0x15, 0x20, 0xD2, 0x05, 0x20, |
dicarloj | 17:c9afe1a7b423 | 214 | 0x4F, 0x16, 0x20, 0x18, 0xCB, 0x4F, 0x06, 0x04, 0xC5, 0xCB, 0x11, 0x17, 0xC1, 0xCB, 0x11, 0x17, |
dicarloj | 17:c9afe1a7b423 | 215 | 0x05, 0x20, 0xF5, 0x22, 0x23, 0x22, 0x23, 0xC9, 0xCE, 0xED, 0x66, 0x66, 0xCC, 0x0D, 0x00, 0x0B, |
dicarloj | 17:c9afe1a7b423 | 216 | 0x03, 0x73, 0x00, 0x83, 0x00, 0x0C, 0x00, 0x0D, 0x00, 0x08, 0x11, 0x1F, 0x88, 0x89, 0x00, 0x0E, |
dicarloj | 17:c9afe1a7b423 | 217 | 0xDC, 0xCC, 0x6E, 0xE6, 0xDD, 0xDD, 0xD9, 0x99, 0xBB, 0xBB, 0x67, 0x63, 0x6E, 0x0E, 0xEC, 0xCC, |
dicarloj | 17:c9afe1a7b423 | 218 | 0xDD, 0xDC, 0x99, 0x9F, 0xBB, 0xB9, 0x33, 0x3E, 0x3c, 0x42, 0xB9, 0xA5, 0xB9, 0xA5, 0x42, 0x4C, |
dicarloj | 17:c9afe1a7b423 | 219 | 0x21, 0x04, 0x01, 0x11, 0xA8, 0x00, 0x1A, 0x13, 0xBE, 0x20, 0xFE, 0x23, 0x7D, 0xFE, 0x34, 0x20, |
dicarloj | 17:c9afe1a7b423 | 220 | 0xF5, 0x06, 0x19, 0x78, 0x86, 0x23, 0x05, 0x20, 0xFB, 0x86, 0x20, 0xFE, 0x3E, 0x01, 0xE0, 0x50}; |
dicarloj | 17:c9afe1a7b423 | 221 | |
dicarloj | 17:c9afe1a7b423 | 222 | // handler for MBC0 switch |
dicarloj | 17:c9afe1a7b423 | 223 | void mbc0Handler(u16 addr, u8 value) { |
dicarloj | 17:c9afe1a7b423 | 224 | |
dicarloj | 17:c9afe1a7b423 | 225 | // it looks like tetris tries to select ROM 1 for banked ROM, so we need to allow this: |
dicarloj | 17:c9afe1a7b423 | 226 | if(addr >= 0x2000 && addr < 0x3fff) { |
dicarloj | 17:c9afe1a7b423 | 227 | if(value == 0 || value == 1) { |
dicarloj | 17:c9afe1a7b423 | 228 | // nothing to do! |
dicarloj | 17:c9afe1a7b423 | 229 | } else { |
dicarloj | 17:c9afe1a7b423 | 230 | assert(false); |
dicarloj | 17:c9afe1a7b423 | 231 | } |
dicarloj | 17:c9afe1a7b423 | 232 | } else { |
dicarloj | 17:c9afe1a7b423 | 233 | assert(false); |
dicarloj | 17:c9afe1a7b423 | 234 | } |
dicarloj | 17:c9afe1a7b423 | 235 | |
dicarloj | 17:c9afe1a7b423 | 236 | } |
dicarloj | 17:c9afe1a7b423 | 237 | |
dicarloj | 17:c9afe1a7b423 | 238 | // handler for MBC1 switch (doesn't handle everything yet...) |
dicarloj | 17:c9afe1a7b423 | 239 | void mbc1Handler(u16 addr, u8 value) { |
dicarloj | 17:c9afe1a7b423 | 240 | if(addr >= 0x2000 && addr < 0x3fff) { |
dicarloj | 17:c9afe1a7b423 | 241 | // ROM bank switch |
dicarloj | 17:c9afe1a7b423 | 242 | if(value >= globalMemState.nRomBanks) { |
dicarloj | 17:c9afe1a7b423 | 243 | printf("\trequested rom bank %d when there are only %d banks!\n", value, globalMemState.nRomBanks); |
dicarloj | 17:c9afe1a7b423 | 244 | assert(false); |
dicarloj | 17:c9afe1a7b423 | 245 | } |
dicarloj | 17:c9afe1a7b423 | 246 | |
dicarloj | 17:c9afe1a7b423 | 247 | if(value == 0) value = 1; |
dicarloj | 17:c9afe1a7b423 | 248 | if(value == 0x21) value = 0x20; |
dicarloj | 17:c9afe1a7b423 | 249 | if(value == 0x41) value = 0x40; |
dicarloj | 17:c9afe1a7b423 | 250 | globalMemState.mappedRom = fileData + 0x4000 * value; |
dicarloj | 17:c9afe1a7b423 | 251 | } else if(addr >= 0 && addr < 0x1fff) { |
dicarloj | 17:c9afe1a7b423 | 252 | // enable RAM |
dicarloj | 17:c9afe1a7b423 | 253 | if(value == 0) { |
dicarloj | 17:c9afe1a7b423 | 254 | globalMemState.disabledMappedRam = globalMemState.mappedRam; |
dicarloj | 17:c9afe1a7b423 | 255 | globalMemState.mappedRam = nullptr; |
dicarloj | 17:c9afe1a7b423 | 256 | } else if(value == 0xa) { |
dicarloj | 17:c9afe1a7b423 | 257 | globalMemState.mappedRam = globalMemState.disabledMappedRam; |
dicarloj | 17:c9afe1a7b423 | 258 | } else { |
dicarloj | 17:c9afe1a7b423 | 259 | assert(false); |
dicarloj | 17:c9afe1a7b423 | 260 | } |
dicarloj | 17:c9afe1a7b423 | 261 | } else { |
dicarloj | 17:c9afe1a7b423 | 262 | assert(false); |
dicarloj | 17:c9afe1a7b423 | 263 | } |
dicarloj | 17:c9afe1a7b423 | 264 | |
dicarloj | 17:c9afe1a7b423 | 265 | } |
dicarloj | 17:c9afe1a7b423 | 266 | |
dicarloj | 17:c9afe1a7b423 | 267 | // handler for MBC2 switch (doesn't handle anything yet...) |
dicarloj | 17:c9afe1a7b423 | 268 | void mbc2Handler(u16 addr, u8 value) { |
dicarloj | 17:c9afe1a7b423 | 269 | assert(false); |
dicarloj | 17:c9afe1a7b423 | 270 | } |
dicarloj | 17:c9afe1a7b423 | 271 | |
dicarloj | 17:c9afe1a7b423 | 272 | // handler for MBC3 switch (doesn't handle anything yet...) |
dicarloj | 17:c9afe1a7b423 | 273 | void mbc3Handler(u16 addr, u8 value) { |
dicarloj | 17:c9afe1a7b423 | 274 | |
dicarloj | 17:c9afe1a7b423 | 275 | if(addr >= 0x2000 && addr < 0x3fff) { |
dicarloj | 17:c9afe1a7b423 | 276 | // ROM bank switch |
dicarloj | 17:c9afe1a7b423 | 277 | if(value >= globalMemState.nRomBanks) { |
dicarloj | 17:c9afe1a7b423 | 278 | printf("\trequested rom bank %d when there are only %d banks!\n", value, globalMemState.nRomBanks); |
dicarloj | 17:c9afe1a7b423 | 279 | assert(false); |
dicarloj | 17:c9afe1a7b423 | 280 | } |
dicarloj | 17:c9afe1a7b423 | 281 | |
dicarloj | 17:c9afe1a7b423 | 282 | if(value == 0) value = 1; |
dicarloj | 17:c9afe1a7b423 | 283 | globalMemState.mappedRom = fileData + 0x4000 * value; |
dicarloj | 17:c9afe1a7b423 | 284 | } else if(addr >= 0 && addr < 0x1fff) { |
dicarloj | 17:c9afe1a7b423 | 285 | // RAM enable/disable |
dicarloj | 17:c9afe1a7b423 | 286 | if(value == 0) { |
dicarloj | 17:c9afe1a7b423 | 287 | globalMemState.disabledMappedRam = globalMemState.mappedRam; |
dicarloj | 17:c9afe1a7b423 | 288 | globalMemState.mappedRam = nullptr; |
dicarloj | 17:c9afe1a7b423 | 289 | } else if(value == 0xa) { |
dicarloj | 17:c9afe1a7b423 | 290 | globalMemState.mappedRam = globalMemState.disabledMappedRam; |
dicarloj | 17:c9afe1a7b423 | 291 | } else { |
dicarloj | 17:c9afe1a7b423 | 292 | //assert(false); |
dicarloj | 17:c9afe1a7b423 | 293 | } |
dicarloj | 17:c9afe1a7b423 | 294 | } else if(addr >= 0x4000 && addr < 0x5fff) { |
dicarloj | 17:c9afe1a7b423 | 295 | // RAM bank switch |
dicarloj | 17:c9afe1a7b423 | 296 | if(value < globalMemState.nRamBanks) { |
dicarloj | 17:c9afe1a7b423 | 297 | globalMemState.mappedRam = globalMemState.mappedRamAllocation + 0x2000 * value; |
dicarloj | 17:c9afe1a7b423 | 298 | } else { |
dicarloj | 17:c9afe1a7b423 | 299 | //assert(false); |
dicarloj | 17:c9afe1a7b423 | 300 | } |
dicarloj | 17:c9afe1a7b423 | 301 | } else if(addr == 0x6000) { |
dicarloj | 17:c9afe1a7b423 | 302 | // ?? RTC latch nonsense |
dicarloj | 17:c9afe1a7b423 | 303 | } else { |
dicarloj | 17:c9afe1a7b423 | 304 | assert(false); |
dicarloj | 17:c9afe1a7b423 | 305 | } |
dicarloj | 17:c9afe1a7b423 | 306 | } |
dicarloj | 17:c9afe1a7b423 | 307 | |
dicarloj | 17:c9afe1a7b423 | 308 | // handler for all MBC switches |
dicarloj | 17:c9afe1a7b423 | 309 | void mbcHandler(u16 addr, u8 value) { |
dicarloj | 17:c9afe1a7b423 | 310 | switch(globalMemState.mbcType) { |
dicarloj | 17:c9afe1a7b423 | 311 | case 0: |
dicarloj | 17:c9afe1a7b423 | 312 | mbc0Handler(addr, value); |
dicarloj | 17:c9afe1a7b423 | 313 | break; |
dicarloj | 17:c9afe1a7b423 | 314 | case 1: |
dicarloj | 17:c9afe1a7b423 | 315 | mbc1Handler(addr, value); |
dicarloj | 17:c9afe1a7b423 | 316 | break; |
dicarloj | 17:c9afe1a7b423 | 317 | case 2: |
dicarloj | 17:c9afe1a7b423 | 318 | mbc2Handler(addr, value); |
dicarloj | 17:c9afe1a7b423 | 319 | break; |
dicarloj | 17:c9afe1a7b423 | 320 | case 3: |
dicarloj | 17:c9afe1a7b423 | 321 | mbc3Handler(addr, value); |
dicarloj | 17:c9afe1a7b423 | 322 | break; |
dicarloj | 17:c9afe1a7b423 | 323 | default: |
dicarloj | 17:c9afe1a7b423 | 324 | assert(false); |
dicarloj | 17:c9afe1a7b423 | 325 | break; |
dicarloj | 17:c9afe1a7b423 | 326 | } |
dicarloj | 17:c9afe1a7b423 | 327 | } |
dicarloj | 17:c9afe1a7b423 | 328 | |
dicarloj | 17:c9afe1a7b423 | 329 | // read a u16 from game memory |
dicarloj | 17:c9afe1a7b423 | 330 | u16 readU16(u16 addr) { |
dicarloj | 17:c9afe1a7b423 | 331 | return (u16)readByte(addr) + ((u16)(readByte(addr+(u16)1)) << 8); |
dicarloj | 17:c9afe1a7b423 | 332 | } |
dicarloj | 17:c9afe1a7b423 | 333 | |
dicarloj | 17:c9afe1a7b423 | 334 | // write a u16 to game memory |
dicarloj | 17:c9afe1a7b423 | 335 | void writeU16(u16 mem, u16 addr) { |
dicarloj | 17:c9afe1a7b423 | 336 | writeByte((u8)(mem & 0xff), addr); |
dicarloj | 17:c9afe1a7b423 | 337 | writeByte((u8)(mem >> 8), addr + (u16)1); |
dicarloj | 17:c9afe1a7b423 | 338 | } |
dicarloj | 17:c9afe1a7b423 | 339 | |
dicarloj | 17:c9afe1a7b423 | 340 | // read byte from memory |
dicarloj | 17:c9afe1a7b423 | 341 | u8 readByte(u16 addr) { |
dicarloj | 17:c9afe1a7b423 | 342 | switch(addr & 0xf000) { |
dicarloj | 17:c9afe1a7b423 | 343 | case 0x0000: // either BIOS or ROM 0: |
dicarloj | 17:c9afe1a7b423 | 344 | if(globalMemState.inBios) { |
dicarloj | 17:c9afe1a7b423 | 345 | if(addr < 0x100) { |
dicarloj | 17:c9afe1a7b423 | 346 | return bios[addr]; |
dicarloj | 17:c9afe1a7b423 | 347 | } else if(addr == 0x100) { |
dicarloj | 17:c9afe1a7b423 | 348 | printf("EXIT BIOS ERROR\n"); |
dicarloj | 17:c9afe1a7b423 | 349 | assert(false); |
dicarloj | 17:c9afe1a7b423 | 350 | } else { |
dicarloj | 17:c9afe1a7b423 | 351 | return globalMemState.rom0[addr]; // todo <- change this for stm32 |
dicarloj | 17:c9afe1a7b423 | 352 | } |
dicarloj | 17:c9afe1a7b423 | 353 | } else { |
dicarloj | 17:c9afe1a7b423 | 354 | return globalMemState.rom0[addr]; // todo <- change this for stm32 |
dicarloj | 17:c9afe1a7b423 | 355 | } |
dicarloj | 17:c9afe1a7b423 | 356 | |
dicarloj | 17:c9afe1a7b423 | 357 | case 0x1000: // ROM 0 |
dicarloj | 17:c9afe1a7b423 | 358 | case 0x2000: // ROM 0 |
dicarloj | 17:c9afe1a7b423 | 359 | case 0x3000: // ROM 0 |
dicarloj | 17:c9afe1a7b423 | 360 | return globalMemState.rom0[addr]; // todo <- change this for stm32 |
dicarloj | 17:c9afe1a7b423 | 361 | |
dicarloj | 17:c9afe1a7b423 | 362 | case 0x4000: // banked ROM |
dicarloj | 17:c9afe1a7b423 | 363 | case 0x5000: |
dicarloj | 17:c9afe1a7b423 | 364 | case 0x6000: |
dicarloj | 17:c9afe1a7b423 | 365 | case 0x7000: |
dicarloj | 17:c9afe1a7b423 | 366 | return globalMemState.mappedRom[addr & 0x3fff]; // todo <- change this for stm32 |
dicarloj | 17:c9afe1a7b423 | 367 | |
dicarloj | 17:c9afe1a7b423 | 368 | case 0x8000: // VRAM |
dicarloj | 17:c9afe1a7b423 | 369 | case 0x9000: |
dicarloj | 17:c9afe1a7b423 | 370 | return globalMemState.vram[addr & 0x1fff]; |
dicarloj | 17:c9afe1a7b423 | 371 | |
dicarloj | 17:c9afe1a7b423 | 372 | case 0xa000: // mapped RAM |
dicarloj | 17:c9afe1a7b423 | 373 | case 0xb000: |
dicarloj | 17:c9afe1a7b423 | 374 | if(!globalMemState.mappedRam) { |
dicarloj | 17:c9afe1a7b423 | 375 | #ifndef DANGER_MODE |
dicarloj | 17:c9afe1a7b423 | 376 | assert(false); |
dicarloj | 17:c9afe1a7b423 | 377 | #endif |
dicarloj | 17:c9afe1a7b423 | 378 | return 0xff; |
dicarloj | 17:c9afe1a7b423 | 379 | } |
dicarloj | 17:c9afe1a7b423 | 380 | return globalMemState.mappedRam[addr & 0x1fff]; |
dicarloj | 17:c9afe1a7b423 | 381 | |
dicarloj | 17:c9afe1a7b423 | 382 | case 0xc000: // internal RAM |
dicarloj | 17:c9afe1a7b423 | 383 | case 0xd000: |
dicarloj | 17:c9afe1a7b423 | 384 | return globalMemState.internalRam[addr & 0x1fff]; |
dicarloj | 17:c9afe1a7b423 | 385 | |
dicarloj | 17:c9afe1a7b423 | 386 | case 0xe000: // interal RAM copy |
dicarloj | 17:c9afe1a7b423 | 387 | return globalMemState.internalRam[addr & 0x1fff]; |
dicarloj | 17:c9afe1a7b423 | 388 | |
dicarloj | 17:c9afe1a7b423 | 389 | case 0xf000: // either internal RAM copy or I/O or top-ram |
dicarloj | 17:c9afe1a7b423 | 390 | switch(addr & 0x0f00) { |
dicarloj | 17:c9afe1a7b423 | 391 | case 0x000: |
dicarloj | 17:c9afe1a7b423 | 392 | case 0x100: |
dicarloj | 17:c9afe1a7b423 | 393 | case 0x200: |
dicarloj | 17:c9afe1a7b423 | 394 | case 0x300: |
dicarloj | 17:c9afe1a7b423 | 395 | case 0x400: |
dicarloj | 17:c9afe1a7b423 | 396 | case 0x500: |
dicarloj | 17:c9afe1a7b423 | 397 | case 0x600: |
dicarloj | 17:c9afe1a7b423 | 398 | case 0x700: |
dicarloj | 17:c9afe1a7b423 | 399 | case 0x800: |
dicarloj | 17:c9afe1a7b423 | 400 | case 0x900: |
dicarloj | 17:c9afe1a7b423 | 401 | case 0xa00: |
dicarloj | 17:c9afe1a7b423 | 402 | case 0xb00: |
dicarloj | 17:c9afe1a7b423 | 403 | case 0xc00: |
dicarloj | 17:c9afe1a7b423 | 404 | case 0xd00: |
dicarloj | 17:c9afe1a7b423 | 405 | case 0xe00: |
dicarloj | 17:c9afe1a7b423 | 406 | return globalMemState.internalRam[addr & 0x1fff]; |
dicarloj | 17:c9afe1a7b423 | 407 | |
dicarloj | 17:c9afe1a7b423 | 408 | |
dicarloj | 17:c9afe1a7b423 | 409 | case 0xf00: |
dicarloj | 17:c9afe1a7b423 | 410 | if(addr >= 0xff80) { |
dicarloj | 17:c9afe1a7b423 | 411 | return globalMemState.upperRam[addr & 0x7f]; |
dicarloj | 17:c9afe1a7b423 | 412 | } else { |
dicarloj | 17:c9afe1a7b423 | 413 | u8 lowAddr = (u8)(addr & 0xff); |
dicarloj | 17:c9afe1a7b423 | 414 | switch(lowAddr) { |
dicarloj | 17:c9afe1a7b423 | 415 | case IO_LY: |
dicarloj | 17:c9afe1a7b423 | 416 | case IO_SCROLLX: |
dicarloj | 17:c9afe1a7b423 | 417 | case IO_SCROLLY: |
dicarloj | 17:c9afe1a7b423 | 418 | case IO_NR10: // nyi |
dicarloj | 17:c9afe1a7b423 | 419 | case IO_NR11: // nyi |
dicarloj | 17:c9afe1a7b423 | 420 | case IO_NR12: // nyi |
dicarloj | 17:c9afe1a7b423 | 421 | case IO_NR13: // nyi |
dicarloj | 17:c9afe1a7b423 | 422 | case IO_NR14: // nyi |
dicarloj | 17:c9afe1a7b423 | 423 | case IO_NR21: // nyi |
dicarloj | 17:c9afe1a7b423 | 424 | case IO_NR22: // nyi |
dicarloj | 17:c9afe1a7b423 | 425 | case IO_NR23: // nyi |
dicarloj | 17:c9afe1a7b423 | 426 | case IO_NR24: // nyi |
dicarloj | 17:c9afe1a7b423 | 427 | case IO_NR30: // nyi |
dicarloj | 17:c9afe1a7b423 | 428 | case IO_NR31: // nyi |
dicarloj | 17:c9afe1a7b423 | 429 | case IO_NR32: // nyi |
dicarloj | 17:c9afe1a7b423 | 430 | case IO_NR33: // nyi |
dicarloj | 17:c9afe1a7b423 | 431 | case IO_NR34: // nyi |
dicarloj | 17:c9afe1a7b423 | 432 | case IO_NR41: // nyi |
dicarloj | 17:c9afe1a7b423 | 433 | case IO_NR42: // nyi |
dicarloj | 17:c9afe1a7b423 | 434 | case IO_NR43: // nyi |
dicarloj | 17:c9afe1a7b423 | 435 | case IO_NR44: // nyi |
dicarloj | 17:c9afe1a7b423 | 436 | case IO_NR50: // nyi |
dicarloj | 17:c9afe1a7b423 | 437 | case IO_NR51: // nyi |
dicarloj | 17:c9afe1a7b423 | 438 | case IO_NR52: // nyi |
dicarloj | 17:c9afe1a7b423 | 439 | case IO_STAT: // nyi |
dicarloj | 17:c9afe1a7b423 | 440 | case IO_WAVE_PATTERN: // nyi |
dicarloj | 17:c9afe1a7b423 | 441 | case IO_LCDC: // nyi |
dicarloj | 17:c9afe1a7b423 | 442 | case IO_BGP: |
dicarloj | 17:c9afe1a7b423 | 443 | case IO_OBP0: |
dicarloj | 17:c9afe1a7b423 | 444 | case IO_OBP1: |
dicarloj | 17:c9afe1a7b423 | 445 | case IO_SERIAL_SB: |
dicarloj | 17:c9afe1a7b423 | 446 | case IO_SERIAL_SC: |
dicarloj | 17:c9afe1a7b423 | 447 | case IO_DIV: |
dicarloj | 17:c9afe1a7b423 | 448 | case IO_TIMA: |
dicarloj | 17:c9afe1a7b423 | 449 | case IO_TMA: |
dicarloj | 17:c9afe1a7b423 | 450 | case IO_TAC: |
dicarloj | 17:c9afe1a7b423 | 451 | case IO_WINY: |
dicarloj | 17:c9afe1a7b423 | 452 | case IO_WINX: |
dicarloj | 17:c9afe1a7b423 | 453 | return globalMemState.ioRegs[lowAddr]; |
dicarloj | 17:c9afe1a7b423 | 454 | break; |
dicarloj | 17:c9afe1a7b423 | 455 | |
dicarloj | 17:c9afe1a7b423 | 456 | case IO_IF: |
dicarloj | 17:c9afe1a7b423 | 457 | printf("read if: 0x%x\n", globalMemState.ioRegs[lowAddr]); |
dicarloj | 17:c9afe1a7b423 | 458 | printf("timer value: 0x%x\n", globalMemState.ioRegs[IO_TIMA]); |
dicarloj | 17:c9afe1a7b423 | 459 | return globalMemState.ioRegs[lowAddr]; |
dicarloj | 17:c9afe1a7b423 | 460 | break; |
dicarloj | 17:c9afe1a7b423 | 461 | |
dicarloj | 17:c9afe1a7b423 | 462 | |
dicarloj | 17:c9afe1a7b423 | 463 | case IO_P1: |
dicarloj | 17:c9afe1a7b423 | 464 | { |
dicarloj | 17:c9afe1a7b423 | 465 | u8 regP1 = globalMemState.ioRegs[IO_P1]; |
dicarloj | 17:c9afe1a7b423 | 466 | //printf("ireg: 0x%x\n", regP1); |
dicarloj | 17:c9afe1a7b423 | 467 | u8 joypad_data = 0; |
dicarloj | 17:c9afe1a7b423 | 468 | if(regP1 & 0x10) { |
dicarloj | 17:c9afe1a7b423 | 469 | if(keyboard.a) joypad_data += 0x1; |
dicarloj | 17:c9afe1a7b423 | 470 | if(keyboard.b) joypad_data += 0x2; |
dicarloj | 17:c9afe1a7b423 | 471 | if(keyboard.select) joypad_data += 0x4; |
dicarloj | 17:c9afe1a7b423 | 472 | if(keyboard.start) joypad_data += 0x8; |
dicarloj | 17:c9afe1a7b423 | 473 | } |
dicarloj | 17:c9afe1a7b423 | 474 | if(regP1 & 0x20) { |
dicarloj | 17:c9afe1a7b423 | 475 | if(keyboard.r) joypad_data += 0x1; |
dicarloj | 17:c9afe1a7b423 | 476 | if(keyboard.l) joypad_data += 0x2; |
dicarloj | 17:c9afe1a7b423 | 477 | if(keyboard.u) joypad_data += 0x4; |
dicarloj | 17:c9afe1a7b423 | 478 | if(keyboard.d) joypad_data += 0x8; |
dicarloj | 17:c9afe1a7b423 | 479 | } |
dicarloj | 17:c9afe1a7b423 | 480 | |
dicarloj | 17:c9afe1a7b423 | 481 | regP1 = (regP1 & 0xf0); |
dicarloj | 17:c9afe1a7b423 | 482 | joypad_data = ~joypad_data; |
dicarloj | 17:c9afe1a7b423 | 483 | joypad_data = regP1 + (joypad_data & 0xf); |
dicarloj | 17:c9afe1a7b423 | 484 | //globalMemState.ioRegs[IO_P1] = joypad_data; |
dicarloj | 17:c9afe1a7b423 | 485 | //printf("jpd: 0x%x\n", joypad_data); |
dicarloj | 17:c9afe1a7b423 | 486 | return joypad_data; |
dicarloj | 17:c9afe1a7b423 | 487 | } |
dicarloj | 17:c9afe1a7b423 | 488 | |
dicarloj | 17:c9afe1a7b423 | 489 | break; |
dicarloj | 17:c9afe1a7b423 | 490 | |
dicarloj | 17:c9afe1a7b423 | 491 | case IO_GBCSPEED: |
dicarloj | 17:c9afe1a7b423 | 492 | return 0xff; |
dicarloj | 17:c9afe1a7b423 | 493 | |
dicarloj | 17:c9afe1a7b423 | 494 | case IO_LYC: |
dicarloj | 17:c9afe1a7b423 | 495 | case IO_DMA: |
dicarloj | 17:c9afe1a7b423 | 496 | |
dicarloj | 17:c9afe1a7b423 | 497 | printf("unhandled I/O read @ 0x%x\n", addr); |
dicarloj | 17:c9afe1a7b423 | 498 | #ifndef DANGER_MODE |
dicarloj | 17:c9afe1a7b423 | 499 | assert(false); |
dicarloj | 17:c9afe1a7b423 | 500 | #endif |
dicarloj | 17:c9afe1a7b423 | 501 | break; |
dicarloj | 17:c9afe1a7b423 | 502 | default: |
dicarloj | 17:c9afe1a7b423 | 503 | printf("unknown I/O read @ 0x%x\n", addr); |
dicarloj | 17:c9afe1a7b423 | 504 | #ifndef DANGER_MODE |
dicarloj | 17:c9afe1a7b423 | 505 | assert(false); |
dicarloj | 17:c9afe1a7b423 | 506 | #endif |
dicarloj | 17:c9afe1a7b423 | 507 | break; |
dicarloj | 17:c9afe1a7b423 | 508 | } |
dicarloj | 17:c9afe1a7b423 | 509 | |
dicarloj | 17:c9afe1a7b423 | 510 | } |
dicarloj | 17:c9afe1a7b423 | 511 | default: |
dicarloj | 17:c9afe1a7b423 | 512 | #ifndef DANGER_MODE |
dicarloj | 17:c9afe1a7b423 | 513 | assert(false); |
dicarloj | 17:c9afe1a7b423 | 514 | #endif |
dicarloj | 17:c9afe1a7b423 | 515 | break; |
dicarloj | 17:c9afe1a7b423 | 516 | |
dicarloj | 17:c9afe1a7b423 | 517 | } |
dicarloj | 17:c9afe1a7b423 | 518 | break; |
dicarloj | 17:c9afe1a7b423 | 519 | |
dicarloj | 17:c9afe1a7b423 | 520 | default: |
dicarloj | 17:c9afe1a7b423 | 521 | #ifndef DANGER_MODE |
dicarloj | 17:c9afe1a7b423 | 522 | assert(false); |
dicarloj | 17:c9afe1a7b423 | 523 | #endif |
dicarloj | 17:c9afe1a7b423 | 524 | break; |
dicarloj | 17:c9afe1a7b423 | 525 | } |
dicarloj | 17:c9afe1a7b423 | 526 | assert(false); |
dicarloj | 17:c9afe1a7b423 | 527 | return 0xff; |
dicarloj | 17:c9afe1a7b423 | 528 | } |
dicarloj | 17:c9afe1a7b423 | 529 | |
dicarloj | 17:c9afe1a7b423 | 530 | |
dicarloj | 17:c9afe1a7b423 | 531 | void writeByte(u8 byte, u16 addr) { |
dicarloj | 17:c9afe1a7b423 | 532 | switch(addr & 0xf000) { |
dicarloj | 17:c9afe1a7b423 | 533 | case 0x0000: // ROM 0, but possibly the BIOS area |
dicarloj | 17:c9afe1a7b423 | 534 | if(globalMemState.inBios) { |
dicarloj | 17:c9afe1a7b423 | 535 | printf("ERROR: tried to write into ROM0 or BIOS (@ 0x%04x) during BIOS!\n", addr); |
dicarloj | 17:c9afe1a7b423 | 536 | #ifndef DANGER_MODE |
dicarloj | 17:c9afe1a7b423 | 537 | assert(false); |
dicarloj | 17:c9afe1a7b423 | 538 | #endif |
dicarloj | 17:c9afe1a7b423 | 539 | } else { |
dicarloj | 17:c9afe1a7b423 | 540 | mbcHandler(addr, byte); |
dicarloj | 17:c9afe1a7b423 | 541 | } |
dicarloj | 17:c9afe1a7b423 | 542 | break; |
dicarloj | 17:c9afe1a7b423 | 543 | |
dicarloj | 17:c9afe1a7b423 | 544 | |
dicarloj | 17:c9afe1a7b423 | 545 | case 0x1000: // ROM 0 |
dicarloj | 17:c9afe1a7b423 | 546 | case 0x2000: // ROM 0 |
dicarloj | 17:c9afe1a7b423 | 547 | case 0x3000: // ROM 0 |
dicarloj | 17:c9afe1a7b423 | 548 | case 0x4000: // ROM 1 |
dicarloj | 17:c9afe1a7b423 | 549 | case 0x5000: // ROM 1 |
dicarloj | 17:c9afe1a7b423 | 550 | case 0x6000: // ROM 1 |
dicarloj | 17:c9afe1a7b423 | 551 | case 0x7000: // ROM 1 |
dicarloj | 17:c9afe1a7b423 | 552 | mbcHandler(addr, byte); |
dicarloj | 17:c9afe1a7b423 | 553 | break; |
dicarloj | 17:c9afe1a7b423 | 554 | |
dicarloj | 17:c9afe1a7b423 | 555 | case 0x8000: // VRAM |
dicarloj | 17:c9afe1a7b423 | 556 | case 0x9000: |
dicarloj | 17:c9afe1a7b423 | 557 | globalMemState.vram[addr & 0x1fff] = byte; |
dicarloj | 17:c9afe1a7b423 | 558 | break; |
dicarloj | 17:c9afe1a7b423 | 559 | |
dicarloj | 17:c9afe1a7b423 | 560 | case 0xa000: // mapped RAM |
dicarloj | 17:c9afe1a7b423 | 561 | case 0xb000: |
dicarloj | 17:c9afe1a7b423 | 562 | if(!globalMemState.mappedRam) { |
dicarloj | 17:c9afe1a7b423 | 563 | //printf("write to unmapped ram @ 0x%x value 0x%x\n", addr, byte); |
dicarloj | 17:c9afe1a7b423 | 564 | //#ifndef DANGER_MODE |
dicarloj | 17:c9afe1a7b423 | 565 | // assert(false); |
dicarloj | 17:c9afe1a7b423 | 566 | //#endif |
dicarloj | 17:c9afe1a7b423 | 567 | break; |
dicarloj | 17:c9afe1a7b423 | 568 | } |
dicarloj | 17:c9afe1a7b423 | 569 | globalMemState.mappedRam[addr & 0x1fff] = byte; |
dicarloj | 17:c9afe1a7b423 | 570 | break; |
dicarloj | 17:c9afe1a7b423 | 571 | |
dicarloj | 17:c9afe1a7b423 | 572 | case 0xc000: // internal RAM |
dicarloj | 17:c9afe1a7b423 | 573 | case 0xd000: |
dicarloj | 17:c9afe1a7b423 | 574 | globalMemState.internalRam[addr & 0x1fff] = byte; |
dicarloj | 17:c9afe1a7b423 | 575 | break; |
dicarloj | 17:c9afe1a7b423 | 576 | |
dicarloj | 17:c9afe1a7b423 | 577 | case 0xe000: // interal RAM copy |
dicarloj | 17:c9afe1a7b423 | 578 | globalMemState.internalRam[addr & 0x1fff] = byte; |
dicarloj | 17:c9afe1a7b423 | 579 | break; |
dicarloj | 17:c9afe1a7b423 | 580 | |
dicarloj | 17:c9afe1a7b423 | 581 | case 0xf000: // either internal RAM copy or I/O or top-ram |
dicarloj | 17:c9afe1a7b423 | 582 | switch(addr & 0x0f00) { |
dicarloj | 17:c9afe1a7b423 | 583 | case 0x000: |
dicarloj | 17:c9afe1a7b423 | 584 | case 0x100: |
dicarloj | 17:c9afe1a7b423 | 585 | case 0x200: |
dicarloj | 17:c9afe1a7b423 | 586 | case 0x300: |
dicarloj | 17:c9afe1a7b423 | 587 | case 0x400: |
dicarloj | 17:c9afe1a7b423 | 588 | case 0x500: |
dicarloj | 17:c9afe1a7b423 | 589 | case 0x600: |
dicarloj | 17:c9afe1a7b423 | 590 | case 0x700: |
dicarloj | 17:c9afe1a7b423 | 591 | case 0x800: |
dicarloj | 17:c9afe1a7b423 | 592 | case 0x900: |
dicarloj | 17:c9afe1a7b423 | 593 | case 0xa00: |
dicarloj | 17:c9afe1a7b423 | 594 | case 0xb00: |
dicarloj | 17:c9afe1a7b423 | 595 | case 0xc00: |
dicarloj | 17:c9afe1a7b423 | 596 | case 0xd00: |
dicarloj | 17:c9afe1a7b423 | 597 | case 0xe00: |
dicarloj | 17:c9afe1a7b423 | 598 | globalMemState.internalRam[addr & 0x1fff] = byte; |
dicarloj | 17:c9afe1a7b423 | 599 | break; |
dicarloj | 17:c9afe1a7b423 | 600 | |
dicarloj | 17:c9afe1a7b423 | 601 | |
dicarloj | 17:c9afe1a7b423 | 602 | case 0xf00: |
dicarloj | 17:c9afe1a7b423 | 603 | if(addr >= 0xff80) { |
dicarloj | 17:c9afe1a7b423 | 604 | globalMemState.upperRam[addr & 0x7f] = byte; |
dicarloj | 17:c9afe1a7b423 | 605 | break; |
dicarloj | 17:c9afe1a7b423 | 606 | } else { |
dicarloj | 17:c9afe1a7b423 | 607 | u16 maskedAddress = addr & 0x7f; |
dicarloj | 17:c9afe1a7b423 | 608 | globalMemState.ioRegs[maskedAddress] = byte; |
dicarloj | 17:c9afe1a7b423 | 609 | u8 lowAddr = (u8)(addr & 0xff); |
dicarloj | 17:c9afe1a7b423 | 610 | switch(lowAddr) { |
dicarloj | 17:c9afe1a7b423 | 611 | |
dicarloj | 17:c9afe1a7b423 | 612 | case IO_NR10: |
dicarloj | 17:c9afe1a7b423 | 613 | case IO_NR11: |
dicarloj | 17:c9afe1a7b423 | 614 | case IO_NR12: |
dicarloj | 17:c9afe1a7b423 | 615 | case IO_NR13: |
dicarloj | 17:c9afe1a7b423 | 616 | case IO_NR14: |
dicarloj | 17:c9afe1a7b423 | 617 | case IO_NR21: |
dicarloj | 17:c9afe1a7b423 | 618 | case IO_NR22: |
dicarloj | 17:c9afe1a7b423 | 619 | case IO_NR23: |
dicarloj | 17:c9afe1a7b423 | 620 | case IO_NR24: |
dicarloj | 17:c9afe1a7b423 | 621 | case IO_NR30: |
dicarloj | 17:c9afe1a7b423 | 622 | case IO_NR31: |
dicarloj | 17:c9afe1a7b423 | 623 | case IO_NR32: |
dicarloj | 17:c9afe1a7b423 | 624 | case IO_NR33: |
dicarloj | 17:c9afe1a7b423 | 625 | case IO_NR34: |
dicarloj | 17:c9afe1a7b423 | 626 | case IO_NR41: |
dicarloj | 17:c9afe1a7b423 | 627 | case IO_NR42: |
dicarloj | 17:c9afe1a7b423 | 628 | case IO_NR43: |
dicarloj | 17:c9afe1a7b423 | 629 | case IO_NR44: |
dicarloj | 17:c9afe1a7b423 | 630 | case IO_NR50: |
dicarloj | 17:c9afe1a7b423 | 631 | case IO_NR51: |
dicarloj | 17:c9afe1a7b423 | 632 | case IO_NR52: |
dicarloj | 17:c9afe1a7b423 | 633 | case IO_WAVE_PATTERN: |
dicarloj | 17:c9afe1a7b423 | 634 | case 0x31: |
dicarloj | 17:c9afe1a7b423 | 635 | case 0x32: |
dicarloj | 17:c9afe1a7b423 | 636 | case 0x33: |
dicarloj | 17:c9afe1a7b423 | 637 | case 0x34: |
dicarloj | 17:c9afe1a7b423 | 638 | case 0x35: |
dicarloj | 17:c9afe1a7b423 | 639 | case 0x36: |
dicarloj | 17:c9afe1a7b423 | 640 | case 0x37: |
dicarloj | 17:c9afe1a7b423 | 641 | case 0x38: |
dicarloj | 17:c9afe1a7b423 | 642 | case 0x39: |
dicarloj | 17:c9afe1a7b423 | 643 | case 0x3a: |
dicarloj | 17:c9afe1a7b423 | 644 | case 0x3b: |
dicarloj | 17:c9afe1a7b423 | 645 | case 0x3c: |
dicarloj | 17:c9afe1a7b423 | 646 | case 0x3d: |
dicarloj | 17:c9afe1a7b423 | 647 | case 0x3e: |
dicarloj | 17:c9afe1a7b423 | 648 | case 0x3f: |
dicarloj | 17:c9afe1a7b423 | 649 | case IO_BGP: |
dicarloj | 17:c9afe1a7b423 | 650 | case IO_SCROLLX: |
dicarloj | 17:c9afe1a7b423 | 651 | case IO_SCROLLY: |
dicarloj | 17:c9afe1a7b423 | 652 | case IO_LCDC: |
dicarloj | 17:c9afe1a7b423 | 653 | case IO_STAT: |
dicarloj | 17:c9afe1a7b423 | 654 | case IO_OBP0: |
dicarloj | 17:c9afe1a7b423 | 655 | case IO_OBP1: |
dicarloj | 17:c9afe1a7b423 | 656 | case IO_P1: |
dicarloj | 17:c9afe1a7b423 | 657 | case IO_IF: |
dicarloj | 17:c9afe1a7b423 | 658 | case IO_TAC: |
dicarloj | 17:c9afe1a7b423 | 659 | case IO_TIMA: |
dicarloj | 17:c9afe1a7b423 | 660 | case IO_TMA: |
dicarloj | 17:c9afe1a7b423 | 661 | case IO_SERIAL_SB: |
dicarloj | 17:c9afe1a7b423 | 662 | case IO_SERIAL_SC: |
dicarloj | 17:c9afe1a7b423 | 663 | case IO_WINY: |
dicarloj | 17:c9afe1a7b423 | 664 | case IO_WINX: |
dicarloj | 17:c9afe1a7b423 | 665 | case IO_LYC: |
dicarloj | 17:c9afe1a7b423 | 666 | break; |
dicarloj | 17:c9afe1a7b423 | 667 | |
dicarloj | 17:c9afe1a7b423 | 668 | case IO_EXIT_BIOS: |
dicarloj | 17:c9afe1a7b423 | 669 | if(globalMemState.inBios) { |
dicarloj | 17:c9afe1a7b423 | 670 | printf("EXIT BIOS by write 0x%x to 0x%x", byte, addr); |
dicarloj | 17:c9afe1a7b423 | 671 | globalMemState.inBios = false; |
dicarloj | 17:c9afe1a7b423 | 672 | break; |
dicarloj | 17:c9afe1a7b423 | 673 | } else { |
dicarloj | 17:c9afe1a7b423 | 674 | printf("tried to write to 0xff50 when not in bios?\n"); |
dicarloj | 17:c9afe1a7b423 | 675 | break; |
dicarloj | 17:c9afe1a7b423 | 676 | } |
dicarloj | 17:c9afe1a7b423 | 677 | break; |
dicarloj | 17:c9afe1a7b423 | 678 | |
dicarloj | 17:c9afe1a7b423 | 679 | case IO_DMA: |
dicarloj | 17:c9afe1a7b423 | 680 | { |
dicarloj | 17:c9afe1a7b423 | 681 | u16 dmaAddr = ((u16)byte) << 8; |
dicarloj | 17:c9afe1a7b423 | 682 | for(u16 i = 0; i < 160; i++) { |
dicarloj | 17:c9afe1a7b423 | 683 | writeByte(readByte(dmaAddr + i), (u16)0xfe00 + i); |
dicarloj | 17:c9afe1a7b423 | 684 | } |
dicarloj | 17:c9afe1a7b423 | 685 | break; |
dicarloj | 17:c9afe1a7b423 | 686 | } |
dicarloj | 17:c9afe1a7b423 | 687 | |
dicarloj | 17:c9afe1a7b423 | 688 | case 0x7f: |
dicarloj | 17:c9afe1a7b423 | 689 | printf("OOPS\n"); |
dicarloj | 17:c9afe1a7b423 | 690 | break; |
dicarloj | 17:c9afe1a7b423 | 691 | |
dicarloj | 17:c9afe1a7b423 | 692 | |
dicarloj | 17:c9afe1a7b423 | 693 | case IO_LY: |
dicarloj | 17:c9afe1a7b423 | 694 | printf("unhandled I/O write @ 0x%x\n", addr); |
dicarloj | 17:c9afe1a7b423 | 695 | #ifndef DANGER_MODE |
dicarloj | 17:c9afe1a7b423 | 696 | assert(false); |
dicarloj | 17:c9afe1a7b423 | 697 | #endif |
dicarloj | 17:c9afe1a7b423 | 698 | break; |
dicarloj | 17:c9afe1a7b423 | 699 | default: |
dicarloj | 17:c9afe1a7b423 | 700 | printf("unknown I/O write @ 0x%x\n", addr); |
dicarloj | 17:c9afe1a7b423 | 701 | #ifndef DANGER_MODE |
dicarloj | 17:c9afe1a7b423 | 702 | assert(false); |
dicarloj | 17:c9afe1a7b423 | 703 | #endif |
dicarloj | 17:c9afe1a7b423 | 704 | break; |
dicarloj | 17:c9afe1a7b423 | 705 | } |
dicarloj | 17:c9afe1a7b423 | 706 | break; |
dicarloj | 17:c9afe1a7b423 | 707 | } |
dicarloj | 17:c9afe1a7b423 | 708 | default: |
dicarloj | 17:c9afe1a7b423 | 709 | #ifndef DANGER_MODE |
dicarloj | 17:c9afe1a7b423 | 710 | assert(false); |
dicarloj | 17:c9afe1a7b423 | 711 | #endif |
dicarloj | 17:c9afe1a7b423 | 712 | break; |
dicarloj | 17:c9afe1a7b423 | 713 | } |
dicarloj | 17:c9afe1a7b423 | 714 | break; |
dicarloj | 17:c9afe1a7b423 | 715 | default: |
dicarloj | 17:c9afe1a7b423 | 716 | #ifndef DANGER_MODE |
dicarloj | 17:c9afe1a7b423 | 717 | assert(false); |
dicarloj | 17:c9afe1a7b423 | 718 | #endif |
dicarloj | 17:c9afe1a7b423 | 719 | break; |
dicarloj | 17:c9afe1a7b423 | 720 | } |
dicarloj | 17:c9afe1a7b423 | 721 | } |