MCUME/MCUME_esp32/espnes/main/mapper.c

376 wiersze
11 KiB
C

/* MoarNES source - mapper.c
This open-source software is (c)2010-2013 Mike Chambers, and is released
under the terms of the GNU GPL v2 license.
This code handles the many video and system mapping hardware found in most
game cartridge hardware. It doesn't handle them all by any means, but most
major mappers are supported.
*/
#include <stdio.h>
#include "moarnes.h"
#include "emuapi.h"
extern uint16_t lastop;
uint16_t lastchange = 0;
struct map9_s *map9;
struct map4_s *map4;
struct map1_s *map1;
void *mappermemory = NULL; //this gets allocated, and a mapper struct shares it's pointer. it's for easier state saving.
uint32_t mappersize = 0;
extern struct cart_s cartridge;
extern struct PPU_s *PPU;
//extern bool running;
//extern bool paused;
void PRGswap(struct cart_s *cart, uint16_t banknum, uint16_t newbank, uint16_t banksize) {
uint16_t tmpstart, tmplen, tmpcur, tmpcur2;
tmpstart = (newbank*banksize)>>10;
tmplen = banksize>>10;
tmpcur2 = (banknum*banksize)>>10;
for (tmpcur=0; tmpcur<tmplen; tmpcur++) {
cart->PRGbank[tmpcur2] = &cart->PRGfull[(uint32_t)tmpstart << 10];
cart->PRGblock[tmpcur2++] = tmpstart++;
}
}
void CHRswap(struct cart_s *cart, uint16_t banknum, uint16_t newbank, uint16_t banksize) {
uint16_t tmpstart, tmplen, tmpcur, tmpcur2;
tmpstart = (newbank*banksize)>>10;
tmplen = banksize>>10;
tmpcur2 = (banknum*banksize)>>10;
for (tmpcur=0; tmpcur<tmplen; tmpcur++) {
cart->CHRbank[tmpcur2] = &cart->CHRfull[(uint32_t)tmpstart << 10];
cart->CHRblock[tmpcur2++] = tmpstart++;
}
}
extern uint8_t *VRAM;
bool mapperinit(struct cart_s *cart) {
//uint8_t msgdata[256];
mappersize = 0;
if (mappermemory != NULL) free(mappermemory);
mappermemory = NULL;
memset(VRAM, 0, 16384);
switch (cart->mapper) {
case 0:
if (cart->PRGcount == 16) {
PRGswap(cart, 0, 0, 16384);
PRGswap(cart, 1, 0, 16384);
} else {
PRGswap(cart, 0, 0, 32768);
}
CHRswap(cart, 0, 0, 8192);
break;
case 1: //MMC1
mappermemory = emu_Malloc(sizeof(struct map1_s));
memset(mappermemory, 0, sizeof(struct map1_s));
mappersize = sizeof(struct map1_s);
map1 = mappermemory;
PRGswap(cart, 0, 0, 16384);
PRGswap(cart, 1, (cart->PRGcount>>4)-1, 16384);
CHRswap(cart, 0, 0, 8192);
write6502(0x8000, 12);
break;
case 2: //UxROM
PRGswap(cart, 0, 0, 16384);
PRGswap(cart, 1, (cart->PRGcount>>4)-1, 16384);
CHRswap(cart, 0, 0, 8192);
break;
case 3: //CNROM
if (cart->PRGcount == 16) {
PRGswap(cart, 0, 0, 16384);
PRGswap(cart, 1, 0, 16384);
} else {
PRGswap(cart, 0, 0, 32768);
}
CHRswap(cart, 0, 0, 8192);
break;
case 4: //MMC3
mappermemory = emu_Malloc(sizeof(struct map4_s));
memset(mappermemory, 0, sizeof(struct map4_s));
mappersize = sizeof(struct map4_s);
map4 = mappermemory;
PRGswap(cart, 0, 0, 16384);
PRGswap(cart, 1, (cart->PRGcount >> 4) - 1, 16384);
CHRswap(cart, 0, 0, 8192);
map4->irqenable = 0;
map4->irqcounter = 255;
map4->irqlatch = 255;
PPU->bgtable = 0x0000;
PPU->sprtable = 0x1000;
break;
case 7: //AxROM
PRGswap(cart, 0, 0, 32768);
CHRswap(cart, 0, 0, 8192);
cart->CHRcount = 0;
PPU->ntmap[0] = 0x2000;
PPU->ntmap[1] = 0x2000;
PPU->ntmap[2] = 0x2000;
PPU->ntmap[3] = 0x2000;
break;
case 9: //MMC2
case 10: //MMC4
mappermemory = emu_Malloc(sizeof(struct map9_s));
memset(mappermemory, 0, sizeof(struct map9_s));
mappersize = sizeof(struct map9_s);
map9 = mappermemory;
PRGswap(cart, 0, 0, 8192);
PRGswap(cart, 1, (cart->PRGcount>>3)-3, 8192);
PRGswap(cart, 2, (cart->PRGcount>>3)-2, 8192);
PRGswap(cart, 3, (cart->PRGcount>>3)-1, 8192);
map9->latch1 = 0xFE;
map9->latch2 = 0xFE;
break;
case 11: //color dreams
PRGswap(cart, 0, 0, 32768);
CHRswap(cart, 0, 0, 8192);
break;
case 13: //CPROM
PRGswap(cart, 0, 0, 32768);
CHRswap(cart, 0, 0, 4096);
CHRswap(cart, 1, 0, 4096);
break;
default:
//sprintf((int8_t *)msgdata, "Sorry, mapper %u is not yet supported.", cart->mapper);
//msgbox(msgdata, MB_ICONERROR | MB_OK);
//running = false;
//paused = false;
return(false);
}
return(true);
}
void map4irqdecrement() {
if (map4->irqcounter > 0) {
map4->irqcounter--;
} else {
if (map4->irqenable)
irqCPU();
map4->irqcounter = map4->irqlatch;
}
}
//uint8_t map1reg[4] = { 0, 0, 0, 0 };
//uint8_t map1bitpos = 0, map1accum = 0;
void map1calc() {
switch (map1->map1reg[0]&3) {
case 0:
PPU->ntmap[0] = 0x2000;
PPU->ntmap[1] = 0x2000;
PPU->ntmap[2] = 0x2000;
PPU->ntmap[3] = 0x2000; break;
case 1:
PPU->ntmap[0] = 0x2400;
PPU->ntmap[1] = 0x2400;
PPU->ntmap[2] = 0x2400;
PPU->ntmap[3] = 0x2400; break;
case 2:
PPU->ntmap[0] = 0x2000;
PPU->ntmap[1] = 0x2400;
PPU->ntmap[2] = 0x2000;
PPU->ntmap[3] = 0x2400; break;
case 3:
PPU->ntmap[0] = 0x2000;
PPU->ntmap[1] = 0x2000;
PPU->ntmap[2] = 0x2400;
PPU->ntmap[3] = 0x2400; break;
}
if (map1->map1reg[0]&8) {
if (map1->map1reg[0]&4) { PRGswap(&cartridge, 0, map1->map1reg[3]&0xF, 16384); PRGswap(&cartridge, 1, (cartridge.PRGcount>>4)-1, 16384); }
else { PRGswap(&cartridge, 0, 0, 16384); PRGswap(&cartridge, 1, map1->map1reg[3]&0xF, 16384); }
} else {
PRGswap(&cartridge, 0, (map1->map1reg[3]&0xF)>>1, 32768);
}
if (map1->map1reg[0]&16) {
CHRswap(&cartridge, 0, map1->map1reg[1], 4096);
CHRswap(&cartridge, 1, map1->map1reg[2], 4096);
} else {
CHRswap(&cartridge, 0, map1->map1reg[1]>>1, 8192);
}
}
uint8_t mapperwrite(uint16_t addr, uint8_t value) {
switch (cartridge.mapper) {
case 1: //MMC1
if (value&128) {
map1->map1reg[0] = (map1->map1reg[0]&0xF3)+0xC; //bits 2, 3 set - others unchanged
map1->map1bitpos = 0; map1->map1accum = 0;
return(1);
}
map1->map1accum |= (value&1) << map1->map1bitpos;
if (map1->map1bitpos==4) {
if (addr>=0xE000) {
map1->map1reg[3] = map1->map1accum;
} else if (addr>=0xC000) {
map1->map1reg[2] = map1->map1accum;
} else if (addr>=0xA000) {
map1->map1reg[1] = map1->map1accum;
} else map1->map1reg[0] = map1->map1accum;
map1calc();
map1->map1bitpos = 0; map1->map1accum = 0;
return(1);
}
map1->map1bitpos = (map1->map1bitpos + 1) % 5;
break;
case 2: //UxROM
PRGswap(&cartridge, 0, value, 16384);
return(1);
case 3: //CNROM
CHRswap(&cartridge, 0, value & 3, 8192);
return(1);
case 4: //MMC3
if ((addr >= 0x8000) && (addr < 0xA000)) {
if (addr & 1) {
switch (map4->command) {
case 0: //select two 1 KB VROM pages at PPU $0000
CHRswap(&cartridge, ((0<<10)^map4->chraddrselect)>>10, value, 1024);
CHRswap(&cartridge, ((1<<10)^map4->chraddrselect)>>10, value+1, 1024);
break;
case 1: //select two 1 KB VROM pages at PPU $0800
CHRswap(&cartridge, ((2<<10)^map4->chraddrselect)>>10, value, 1024);
CHRswap(&cartridge, ((3<<10)^map4->chraddrselect)>>10, value+1, 1024);
break;
case 2: //select 1 KB VROM page at PPU $1000
CHRswap(&cartridge, ((4<<10)^map4->chraddrselect)>>10, value, 1024);
break;
case 3: //select 1 KB VROM page at PPU $1400
CHRswap(&cartridge, ((5<<10)^map4->chraddrselect)>>10, value, 1024);
break;
case 4: //select 1 KB VROM page at PPU $1800
CHRswap(&cartridge, ((6<<10)^map4->chraddrselect)>>10, value, 1024);
break;
case 5: //select 1 KB VROM page at PPU $1C00
CHRswap(&cartridge, ((7<<10)^map4->chraddrselect)>>10, value, 1024);
break;
case 6: //select first switchable ROM page
map4->prgswitch1 = value & ((cartridge.PRGcount>>3)-1);
break;
case 7: //select second switchable ROM page
map4->prgswitch2 = value & ((cartridge.PRGcount>>3)-1);
break;
}
if ((map4->command == 6) || (map4->command == 7)) {
if (map4->prgaddr) {
PRGswap(&cartridge, 0, (cartridge.PRGcount>>3)-2, 8192);
PRGswap(&cartridge, 1, map4->prgswitch2, 8192);
PRGswap(&cartridge, 2, map4->prgswitch1, 8192);
PRGswap(&cartridge, 3, (cartridge.PRGcount>>3)-1, 8192);
} else {
PRGswap(&cartridge, 0, map4->prgswitch1, 8192);
PRGswap(&cartridge, 1, map4->prgswitch2, 8192);
PRGswap(&cartridge, 2, (cartridge.PRGcount>>3)-2, 8192);
PRGswap(&cartridge, 3, (cartridge.PRGcount>>3)-1, 8192);
}
return(1);
}
} else {
map4->command = value & 7;
map4->prgaddr = value & 0x40;
if (value & 0x80) map4->chraddrselect = 0x1000;
else map4->chraddrselect = 0x0000;
return(1);
}
} else if ((addr >= 0xA000) && (addr < 0xC000)) {
if (addr & 1) {
//if (value & 0x80)
} else {
cartridge.mirroring = value & 1;
if (cartridge.mirroring) {
PPU->ntmap[0] = 0x2000;
PPU->ntmap[1] = 0x2000;
PPU->ntmap[2] = 0x2400;
PPU->ntmap[3] = 0x2400;
} else {
PPU->ntmap[0] = 0x2000;
PPU->ntmap[1] = 0x2400;
PPU->ntmap[2] = 0x2000;
PPU->ntmap[3] = 0x2400;
}
}
} else if ((addr >= 0xC000) && (addr < 0xE000)) {
if (addr & 1) map4->irqcounter = 0;
else map4->irqlatch = value;
} else {
if (addr & 1) map4->irqenable = 1;
else map4->irqenable = 0;
}
return(1);
case 7: //AxROM
PRGswap(&cartridge, 0, value & 0x0F, 32768);
if (value & 0x10) {
PPU->ntmap[0] = 0x2400;
PPU->ntmap[1] = 0x2400;
PPU->ntmap[2] = 0x2400;
PPU->ntmap[3] = 0x2400;
} else {
PPU->ntmap[0] = 0x2000;
PPU->ntmap[1] = 0x2000;
PPU->ntmap[2] = 0x2000;
PPU->ntmap[3] = 0x2000;
}
return(1);
case 9: //MMC2
case 10: //MMC4
if ((addr >= 0xA000) && (addr < 0xB000)) {
PRGswap(&cartridge, 0, value & 0x0F, 8192);
} else if ((addr >= 0xB000) && (addr < 0xC000)) {
map9->latch0_fd = value;
if (map9->latch1 == 0xFD) CHRswap(&cartridge, 0, map9->latch0_fd, 4096);
} else if ((addr >= 0xC000) && (addr < 0xD000)) {
map9->latch0_fe = value;
if (map9->latch1 == 0xFE) CHRswap(&cartridge, 0, map9->latch0_fe, 4096);
} else if ((addr >= 0xD000) && (addr < 0xE000)) {
map9->latch1_fd = value;
if (map9->latch2 == 0xFD) CHRswap(&cartridge, 1, map9->latch1_fd, 4096);
} else if ((addr >= 0xE000) && (addr < 0xF000)) {
map9->latch1_fe = value;
if (map9->latch2 == 0xFE) CHRswap(&cartridge, 1, map9->latch1_fe, 4096);
} else if (addr >= 0xF000) {
if (value & 1) { //horizontal
PPU->ntmap[0] = 0x2000;
PPU->ntmap[1] = 0x2000;
PPU->ntmap[2] = 0x2400;
PPU->ntmap[3] = 0x2400;
} else { //vertical
PPU->ntmap[0] = 0x2000;
PPU->ntmap[1] = 0x2400;
PPU->ntmap[2] = 0x2000;
PPU->ntmap[3] = 0x2400;
}
}
break;
case 11: //color dreams
PRGswap(&cartridge, 0, value & 3, 32768);
CHRswap(&cartridge, 0, value >> 4, 8192);
break;
case 13: //CPROM
CHRswap(&cartridge, 1, value & 3, 4096);
break;
}
return(0);
}