home *** CD-ROM | disk | FTP | other *** search
- /*
- * gbe - gameboy emulator
- * Copyright (C) 1999 Chuck Mason, Steven Fuller
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- *
- * Chuck Mason <chuckjr@sinclair.net>
- * Steven Fuller <relnev@atdot.org>
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h> /* 092299 */
- #include <time.h> /* 092299 */
-
- #include "rom.h"
- #include "mem.h"
- #include "regs.h"
- #include "joypad.h"
- #include "cpu.h"
- #include "vram.h" /* 092299 */
-
- unsigned char *gameboy_memory[16]; /* 0-F */
- unsigned char *video_ram = (char *)NULL; /* Mapped to 8 & 9 */
- unsigned char *internal_ram = (char *)NULL; /* Mapped to B and C */
- unsigned char *bank_sixteen = (char *)NULL; /* Mapped to F */
- unsigned char *sprite_oam = (char *)NULL; /* Mapped to FE00 */
- unsigned short int bkg_palettes[8][4]; /* 8 Palettes of 4 Colors Each */
- unsigned short int obj_palettes[8][4]; /* " */
-
- unsigned char mbc1_ram_bank_enable = 0; /* Default is disabled */
- unsigned char mbc1_address_line = 0;
- unsigned short int mbc5_rom_select = 0;
-
- void install_memory(char bank, void *fromwhere)
- {
- gameboy_memory[(int)bank] = fromwhere;
- }
-
- void memory_select_wram_bank(unsigned char bank, unsigned char where)
- {
- char *ptr;
-
- if(!color_gameboy) /* Useless on regular GB */
- return;
-
- if(bank == 0)
- bank = 1;
-
- ptr = internal_ram + (bank * 0x1000);
-
- install_memory(where, ptr);
- }
-
- void memory_select_vram_bank(unsigned char bank, unsigned char where)
- {
- char *ptr;
-
- if(!color_gameboy)
- return;
-
- if(bank > 2)
- return; /* uh oh? */
-
- ptr = video_ram + (bank * 0x2000);
-
- install_memory(where, ptr);
- install_memory(where + 1, ptr + 0x1000);
- }
-
-
- int initialize_memory()
- {
- int i;
-
- for(i = 0; i < 16; i++)
- gameboy_memory[i] = (char *)NULL;
-
- if(!color_gameboy)
- video_ram = (char *)malloc(0x2000); /* 8 Kilobyte Video Ram */
- else
- video_ram = (char *)malloc(0x4000); /* 16 Kilobyte Video Ram */
-
- if(!video_ram)
- return 0;
- else {
- if(!color_gameboy)
- memset(video_ram, 0, 0x2000);
- else
- memset(video_ram, 0, 0x4000);
- }
-
-
- if(!color_gameboy)
- internal_ram = (char *)malloc(0x2000);
- else
- internal_ram = (char *)malloc(0x8000);
-
- if(!internal_ram)
- return 0;
- else {
- if(!color_gameboy)
- memset(internal_ram, 0, 0x2000);
- else
- memset(internal_ram, 0, 0x8000);
- }
-
- bank_sixteen = (char *)malloc(0x1000);
-
- if(!bank_sixteen)
- return 0;
- else
- memset(bank_sixteen, 0, 0x1000);
-
- install_memory(8, video_ram + 0x0000);
- install_memory(9, video_ram + 0x1000);
-
- install_memory(0x0A, NULL); /* 8 Kilobyte Switchable RAM */
- install_memory(0x0B, NULL);
-
- install_memory(0x0C, internal_ram + 0x0000); /* This is ok for both GB and GBC */
- install_memory(0x0D, internal_ram + 0x1000);
- install_memory(0x0E, internal_ram + 0x0000); /* Echo of Internal Ram */
-
- install_memory(0x0F, bank_sixteen);
-
- sprite_oam = &gameboy_memory[0xF][0xE00];
-
- srand(time(NULL));
- return 1;
- }
-
- void free_memory()
- {
- if(video_ram) {
- free(video_ram);
- install_memory(8, NULL);
- install_memory(9, NULL);
- video_ram = (char *)NULL;
- }
- if(internal_ram) {
- free(internal_ram);
- install_memory(0x0C, NULL);
- install_memory(0x0D, NULL);
- install_memory(0x0E, NULL);
- internal_ram = (char *)NULL;
- }
- if(bank_sixteen) {
- free(bank_sixteen);
- install_memory(0xF, NULL);
- bank_sixteen = (char *)NULL;
- }
- sprite_oam = (char *)NULL;
- }
-
-
- unsigned char memory_read_byte(unsigned short int address)
- {
- unsigned char bank;
- unsigned short int where = 0;
-
- bank = (address & 0xF000) >> 12;
-
- if(bank == 0xF) {
- where = address & 0x0FFF;
-
- #ifdef MEM_DEBUG
- printf("READ: ");
- #endif
- if(where == 0xFFF) {
- #ifdef MEM_DEBUG
- printf("Interrupt Enable Register\n");
- #endif
- return IENABLE;
- } else if(where >= 0xF80) {
- #ifdef MEM_DEBUG
- printf("Internal RAM\n");
- #endif
- return gameboy_memory[bank][where];
- } else if(where >= 0xF4C) {
- #ifdef MEM_DEBUG
- printf("READ: Empty area???\n");
- #endif
- return gameboy_memory[bank][where];
- } else if(where >= 0xF00) {
- #ifdef MEM_DEBUG
- printf("I/O Port $%02X\n", where & 0xFF);
- #endif
- if(where == 0xF00) {
- if(!(JOYPAD & 0x20)) { /* Low bits */
- return ~(0xC0 | ((current_joypad & 0xF0) >> 4)) | 0x10;
- } else if(!(JOYPAD & 0x10)) {
- return ~(0xC0 | (current_joypad & 0x0F)) | 0x20;
- } else if(!(JOYPAD & 0x30)) { /* Weird? Reset then read? Odd! */
- return 0xFF;
- } else
- return 0;
- } else if(where == 0xF41) {
- unsigned char ret;
- ret = LCDSTAT & 0xFC;
- if(CURLINE >= 144)
- ret |= 0x01;
- else if((ret & 0x08))
- ret &= ~0x03;
- return ret;
- }
-
- return gameboy_memory[bank][where];
- } else if(where >= 0xEA0) {
- #ifdef MEM_DEBUG
- printf("Empty area 2???\n");
- #endif
- return gameboy_memory[bank][where];
- } else if(where >= 0xE00) {
- #ifdef MEM_DEBUG
- printf("Sprite OAM\n");
- #endif
- return gameboy_memory[bank][where];
- } else { /* Where < 0xE00 */
- #ifdef MEM_DEBUG
- printf("0xF%03X\n", where);
- #endif
- return gameboy_memory[0x0D][where];
- }
- } else {
- if(bank == 0xA || bank == 0xB) {
- if((cartridge_type >= 1 && cartridge_type <= 3) && mbc1_ram_bank_enable == 0)
- return 0; /* ignore read... */
- }
-
- if((gameboy_memory[bank] != NULL) && (bank < 16))
- return gameboy_memory[bank][address & 0xFFF];
- }
- return 0;
- }
-
- unsigned short int memory_read_word(unsigned short int address)
- {
- return (memory_read_byte(address) | (memory_read_byte(address+1) << 8));
- }
-
- void memory_write_byte(unsigned short int address, unsigned char value)
- {
- unsigned char bank;
- unsigned short int where = 0;
-
- bank = (address & 0xF000) >> 12;
-
- if(bank == 0xF) {
- where = address & 0x0FFF;
-
- #ifdef MEM_DEBUG
- printf("WRITE (%02X): ", value);
- #endif
- if(where == 0xFFF) {
- #ifdef MEM_DEBUG
- printf("Interrupt Enable Register\n");
- #endif
- IENABLE = value;
- } else if(where >= 0xF80) {
- #ifdef MEM_DEBUG
- printf("Internal RAM\n");
- #endif
- gameboy_memory[bank][where] = value;
- } else if(where >= 0xF4C) {
- if(color_gameboy) {
- if(where == 0xF4F) {
- VBKREG = value & 0x01;
- memory_select_vram_bank(VBKREG, 0x08);
- } else if(where == 0xF70) {
- SVBKREG = value & 0x07;
- memory_select_wram_bank(SVBKREG, 0x0D);
- } else if(where == 0xF68) {
- BCPSREG = value & 0xBF;
- } else if(where == 0xF69) {
- unsigned char incpal;
- unsigned char pal;
- unsigned char col;
- unsigned char hl;
-
- incpal = (BCPSREG & 0x80) ? 1 : 0;
- pal = (BCPSREG & 0x38) >> 3;
- col = (BCPSREG & 0x06) >> 1;
- hl = (BCPSREG & 0x01);
-
- if(hl) { /* BBBBB0GG */
- bkg_palettes[pal][col] = (bkg_palettes[pal][col] & 0x00FF) | (value << 8);
- } else { /* GGGRRRRR */
- bkg_palettes[pal][col] = (bkg_palettes[pal][col] & 0xFF00) | value;
- }
- /*printf("bkg palette data: %X:%c:pal[%d][%d]\n", value, (hl) ? 'h' : 'l', pal, col);*/
- if(incpal) { /* Im sure this is possible by just incrementing the lower 6 bits! :( */
- if(hl) {
- hl = 0;
- if(col == 3) {
- col = 0;
- if(pal == 7)
- pal = 0;
- else
- pal++;
- } else
- col++;
- } else
- hl++;
- BCPSREG = 0x80 | hl | (col << 1) | (pal << 3);
- }
- } else if(where == 0xF6A) {
- OCPSREG = value & 0xBF;
- } else if(where == 0xF6B) {
- unsigned char incpal;
- unsigned char pal;
- unsigned char col;
- unsigned char hl;
-
- incpal = (OCPSREG & 0x80) ? 1 : 0;
- pal = (OCPSREG & 0x38) >> 3;
- col = (OCPSREG & 0x06) >> 1;
- hl = (OCPSREG & 0x01);
-
- if(hl) { /* 0BBBBBGG */
- obj_palettes[pal][col] = (obj_palettes[pal][col] & 0x00FF) | (value << 8);
- } else { /* GGGRRRRR */
- obj_palettes[pal][col] = (obj_palettes[pal][col] & 0xFF00) | value;
- }
-
- if(incpal) { /* Im sure this is possible by just incrementing the lower 6 bits! :( */
- if(hl) {
- hl = 0;
- if(col == 3) {
- col = 0;
- if(pal == 7)
- pal = 0;
- else
- pal++;
- } else
- col++;
- } else
- hl++;
- OCPSREG = 0x80 | hl | (col << 1) | (pal << 3);
- }
- } else if(where == 0xF55) {
- unsigned short int dest;
- unsigned short int src;
- unsigned short int cnt;
- unsigned short int cntr;
-
- src = (HDMA1REG << 8) | (HDMA2REG & 0xF0);
- dest = ((HDMA3REG & 0x1F) << 11) | ((HDMA4REG & 0xF0));
- printf("DMA5: %X From %X to %X\n", value, src, dest);
- cntr = ((value & 0x7F) + 1) * 16;
- for(cnt = 0; cnt < cntr; cnt++) {
- memory_write_byte(dest+cnt, memory_read_byte(src+cnt));
- }
- } else
- gameboy_memory[bank][where] = value;
- } else
- gameboy_memory[bank][where] = value;
- } else if(where >= 0xF00) {
- #ifdef MEM_DEBUG
- printf("I/O Port %02X\n", where & 0xFF);
- #endif
- if(where == 0xF40) {
- if((gameboy_memory[bank][where] & 0x80) && !(value & 0x80)) {
- if(CURLINE >= 144)
- gameboy_memory[bank][where] = value;
- } else {
- gameboy_memory[bank][where] = value;
- }
- } else if(where == 0xF44) {
- printf("wrote %d\n", value);
- CURLINE = 0;
- }
- else if(where == 0xF00) {
- gameboy_memory[bank][where] = value;
- } else if(where == 0xF07) {
- TIMECNT = 0;
- TIMEMOD = 0;
- TIMCONT = value;
- } else if(where == 0xF02) {
- gameboy_memory[bank][where] = value;
- } else if(where == 0xF46) {
- DMACONT = value;
- if(DMACONT < 0xE0)
- gameboy_do_dma();
- } else
- gameboy_memory[bank][where] = value;
- } else if(where >= 0xEA0) {
- #ifdef MEM_DEBUG
- printf("Empty area 2???\n");
- #endif
- gameboy_memory[bank][where] = value;
- } else if(where >= 0xE00) {
- #ifdef MEM_DEBUG
- printf("Sprite OAM\n");
- #endif
- gameboy_memory[bank][where] = value;
- } else {
- #ifdef MEM_DEBUG
- printf("0xF%03X\n", where);
- #endif
- gameboy_memory[bank][where] = value;
- }
- } else {
- if(bank < 8) {
- if(cartridge_type >= TYPE_ROM_MBC1 && cartridge_type <= TYPE_ROM_MBC1_RAM_BATTERY) {
- if(address >= 0x6000 && address < 0x8000) {
- if(value & 0x01) {
- cartridge_mbc1 = MBC1_4M_32K;
- mbc1_address_line = 0;
- } else {
- cartridge_mbc1 = MBC1_16M_8K;
- }
- } else if(address >= 0x2000 && address < 0x4000) {
- unsigned short int bank = (value & 0x1F);
-
- /*if(MBC1_16M_8K)
- bank |= (mbc1_address_line << 5);*/
-
- if(bank < 1)
- bank = 1;
-
- rom_select_bank(bank, 4);
- } else if(address >= 0x4000 && address < 0x6000) {
- switch(cartridge_mbc1) {
- case MBC1_16M_8K:
- mbc1_address_line = (value & 0x03);
- printf("address line = %d\n", mbc1_address_line);
- break; /* fallthrough */
- case MBC1_4M_32K:
- rom_select_ram_bank(value & 0x03);
- break;
- default:
- break;
- }
- } else if(address < 0x2000) {
- int res = value & 0x0F;
- if(res == 0x0A) {
- mbc1_ram_bank_enable = 1;
- } else {
- mbc1_ram_bank_enable = 0;
- }
- }
- } else if(cartridge_type == TYPE_ROM_MBC2 || cartridge_type == TYPE_ROM_MBC2_BATTERY) {
- unsigned char ual = (address & 0xFF00) >> 8; /* Upper Address Line */
-
- if(address >= 0x2000 && address < 0x3000) {
- if(ual & 0x01)
- rom_select_bank(value & 0x0F, 4);
- } else if(address < 0x2000) {
- if(ual & 0x01) {
- printf("ram bank %s\n", mbc1_ram_bank_enable ? "disabled" : "enabled");
- mbc1_ram_bank_enable = !mbc1_ram_bank_enable;
- }
- }
- } else if(cartridge_type >= TYPE_ROM_MBC3 && cartridge_type <= TYPE_ROM_MBC3_RAM_BATTERY) {
- if(address >= 0x2000 && address <= 0x3FFF) {
- rom_select_bank(value & 0x7F, 4);
- } else if(address >= 0x4000 && address <= 0x5FFF) {
- rom_select_ram_bank(value & 0x3);
- }
- } else if(cartridge_type >= TYPE_ROM_MBC5 && cartridge_type <= TYPE_ROM_MBC5_RAM_BATTERY) {
- if(address < 0x2000) {
- if(value == 0)
- mbc1_ram_bank_enable = 0;
- if(value == 0x0A)
- mbc1_ram_bank_enable = 1;
- } else if(address >= 0x2000 && address <= 0x2FFF) { /* lower 8 bits of rom select */
- mbc5_rom_select = (mbc5_rom_select & 0xFF00) | value;
- rom_select_bank(mbc5_rom_select, 4);
- } else if(address >= 0x3000 && address <= 0x3FFF) {
- mbc5_rom_select = (value & 0x01) << 8 | (mbc5_rom_select & 0x00FF);
- rom_select_bank(mbc5_rom_select, 4);
- } else if(address >= 0x4000 && address < 0x6000) {
- rom_select_ram_bank(value & 0x0F); /* gets a total of 15 banks */
- }
- }
-
- return;
- } else if(bank == 0xA || bank == 0xB) {
- /* mbc1 */
- if(cartridge_type >= 1 && cartridge_type <= 3 && mbc1_ram_bank_enable == 0)
- return; /* ignore write.. */
- if(cartridge_type == TYPE_ROM_MBC2 || (cartridge_type == TYPE_ROM_MBC2_BATTERY && mbc1_ram_bank_enable == 0))
- return; /* ignore write.. */
- if(cartridge_type >= TYPE_ROM_MBC5 && cartridge_type <= TYPE_ROM_MBC5_RAM_BATTERY && mbc1_ram_bank_enable == 0)
- return;
- if(gameboy_memory[bank])
- gameboy_memory[bank][address & 0xFFF] = value;
- }
- else if(gameboy_memory[bank])
- gameboy_memory[bank][address & 0xFFF] = value;
- }
- }
-
- void memory_write_word(unsigned short int address, unsigned short int value)
- {
- memory_write_byte(address, value & 0xFF);
- memory_write_byte(address + 1, (value & 0xFF00) >> 8);
- }
-