Yet Another SEGA GAME GEAR Emulator その1

ところで、SC-3000が遊べるならば、マークIII以降も遊びたいものです。例によって改造したら動くんじゃないかと言う試みです。

まずは、現状のeSC-3000で動かないメガロム対応から着手してみます。

f:id:tanam:20130824195440p:image:w360

memory.cpp

/*
	SEGA GAME GEAR Emulator 'yaGAME GEAR'

	Author : tanam
	Date   : 2013.08.24-

	[ memory ]
*/

#include "memory.h"
#include "../../fileio.h"

void MEMORY::sms_mapper_w(uint32 addr, uint32 data)
{
    /* Calculate ROM page index */
    uint8 page = (data % pages);

    /* Save frame control register data */
    fcr[addr] = data;

    switch(addr)
    {
        case 0:
            if(data & 8)
            {
                save = 1;
                /* Page in ROM */
                cpu_readmap[4]  = &sram[(data & 4) ? 0x4000 : 0x0000];
                cpu_readmap[5]  = &sram[(data & 4) ? 0x6000 : 0x2000];
                cpu_writemap[4] = &sram[(data & 4) ? 0x4000 : 0x0000];
                cpu_writemap[5] = &sram[(data & 4) ? 0x6000 : 0x2000];
            }
            else
            {
                /* Page in RAM */
                cpu_readmap[4]  = &cart[((fcr[3] % pages) << 14) + 0x0000];
                cpu_readmap[5]  = &cart[((fcr[3] % pages) << 14) + 0x2000];
                cpu_writemap[4] = ram + 0x8000;
                cpu_writemap[5] = ram + 0xA000;
            }
            break;

        case 1:
            cpu_readmap[0] = &cart[(page << 14) + 0x0000];
            cpu_readmap[1] = &cart[(page << 14) + 0x2000];
            break;

        case 2:
            cpu_readmap[2] = &cart[(page << 14) + 0x0000];
            cpu_readmap[3] = &cart[(page << 14) + 0x2000];
            break;

        case 3:
            if(!(fcr[0] & 0x08))
            {
                cpu_readmap[4] = &cart[(page << 14) + 0x0000];
                cpu_readmap[5] = &cart[(page << 14) + 0x2000];
            }
            break;
    }
}

void MEMORY::initialize()
{
	cart=NULL;

	memset(ram, 0, sizeof(ram));
	memset(rdmy, 0xff, sizeof(rdmy));
    memset(sram, 0, sizeof(sram));

	// set memory map
    cpu_readmap[0] = ram;
    cpu_readmap[1] = ram + 0x2000;
    cpu_readmap[2] = ram + 0x4000;
    cpu_readmap[3] = ram + 0x6000;
    cpu_readmap[4] = ram + 0x8000;
    cpu_readmap[5] = ram + 0xA000;
    cpu_readmap[6] = ram + 0xC000;
    cpu_readmap[7] = ram + 0xE000;

    cpu_writemap[0] = ram;         
    cpu_writemap[1] = ram + 0x2000;
    cpu_writemap[2] = ram + 0x4000;         
    cpu_writemap[3] = ram + 0x6000;
    cpu_writemap[4] = ram + 0x8000;         
    cpu_writemap[5] = ram + 0xA000;
    cpu_writemap[6] = ram + 0xC000;           
    cpu_writemap[7] = ram + 0xE000;

    fcr[0] = 0x00;
    fcr[1] = 0x00;
    fcr[2] = 0x01;
    fcr[3] = 0x00;
	
	inserted = false;
}

void MEMORY::write_data8(uint32 addr, uint32 data)
{
    cpu_writemap[(addr >> 13)][(addr & 0x1FFF)] = data;
	if (pages < 4) return;
    if (addr >= 0xFFFC) sms_mapper_w(addr & 3, data);
}

uint32 MEMORY::read_data8(uint32 addr)
{
    return cpu_readmap[(addr >> 13)][(addr & 0x1FFF)];
}

void MEMORY::write_signal(int id, uint32 data, uint32 mask)
{
	// from PIO-P6
	if(data & mask) {
	    cpu_readmap[0] = ram;
		cpu_readmap[1] = ram + 0x2000;
	    cpu_readmap[2] = ram + 0x4000;
        cpu_readmap[3] = ram + 0x6000;
        cpu_readmap[4] = ram + 0x8000;
	    cpu_writemap[0] = ram;           
		cpu_writemap[1] = ram + 0x2000;
	    cpu_writemap[2] = ram + 0x4000;
        cpu_writemap[3] = ram + 0x6000;
        cpu_writemap[4] = ram + 0x8000;
	}
	else {
		// ROM
	    cpu_readmap[0] = cart;
		cpu_readmap[1] = rdmy;
	    cpu_readmap[2] = ram + 0x4000;
        cpu_readmap[3] = ram + 0x6000;
        cpu_readmap[4] = ram + 0x8000;
	    cpu_writemap[0] = ram;
		cpu_writemap[1] = ram + 0x2000;
	    cpu_writemap[2] = ram + 0x4000;
        cpu_writemap[3] = ram + 0x6000;
        cpu_writemap[4] = ram + 0x8000;
	}
}

void MEMORY::open_cart(_TCHAR* file_path)
{
	FILEIO* fio = new FILEIO();
	
	if(fio->Fopen(file_path, FILEIO_READ_BINARY)) {
		fio->Fseek(0, FILEIO_SEEK_END);
		size=fio->Ftell();
		pages = (size / 0x4000);
		fio->Fseek(0, FILEIO_SEEK_SET);
		if (cart) free(cart);
		cart=(uint8 *)malloc(size);
		fio->Fread(cart, size, 1);
		fio->Fclose();

		inserted = true;
	}
	delete fio;
	
	// set memory map
    cpu_readmap[0] = cart;
	if (size>0x2000) cpu_readmap[1] = cart + 0x2000;
	else cpu_readmap[1] = rdmy;
    if (size>0x4000) cpu_readmap[2] = cart + 0x4000;
	else cpu_readmap[2] = rdmy;
    if (size>0x6000) cpu_readmap[3] = cart + 0x6000;
    else cpu_readmap[3] = rdmy;
    if (size>0x8000) cpu_readmap[4] = cart + 0x8000;
    else cpu_readmap[4] = ram + 0x8000;
    if (size>0xA000) cpu_readmap[5] = cart + 0xA000;
    else cpu_readmap[5] = ram + 0xA000;
    cpu_readmap[6] = ram + 0xC000;
    cpu_readmap[7] = ram + 0xE000;
    cpu_writemap[0] = ram;         
    cpu_writemap[1] = ram + 0x2000;
    cpu_writemap[2] = ram + 0x4000;         
    cpu_writemap[3] = ram + 0x6000;
    cpu_writemap[4] = ram + 0x8000;         
    cpu_writemap[5] = ram + 0xA000;
    cpu_writemap[6] = ram + 0xC000;           
    cpu_writemap[7] = ram + 0xE000;

    fcr[0] = 0x00;
    fcr[1] = 0x00;
    fcr[2] = 0x01;
    fcr[3] = 0x00;	
}

void MEMORY::close_cart()
{
	if (cart) free(cart);	
	initialize();	
}

memory.h

/*
	SEGA GAME GEAR Emulator 'yaGAME GEAR'

	Author : tanam
	Date   : 2013.08.24-

	[ memory ]
*/

#ifndef _MEMORY_H_
#define _MEMORY_H_

#include "../vm.h"
#include "../../emu.h"
#include "../device.h"

#define SIG_MEMORY_SEL	0

class MEMORY : public DEVICE
{
private:
	// memory
	uint8 *cart;
    uint32 size;
    uint8 pages;
	uint8 ram[0x10000];	
	uint8 rdmy[0x2000];
	uint8 sram[0x8000];
	uint8 *cpu_readmap[8];
	uint8 *cpu_writemap[8];
    uint8 fcr[4];
    uint8 save;
	
	bool inserted;
	void sms_mapper_w(uint32 addr, uint32 data);
	
public:
	MEMORY(VM* parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu) {}
	~MEMORY() {}
	
	// common functions
	void initialize();
	void write_data8(uint32 addr, uint32 data);
	uint32 read_data8(uint32 addr);
	void write_data16(uint32 addr, uint32 data) {
		write_data8(addr, data & 0xff); write_data8(addr + 1, data >> 8);
	}
	uint32 read_data16(uint32 addr) {
		return read_data8(addr) | (read_data8(addr + 1) << 8);
	}
	void write_signal(int id, uint32 data, uint32 mask);
	
	// unique functions
	void open_cart(_TCHAR* file_path);
	void close_cart();
	bool cart_inserted() {
		return inserted;
	}
};

#endif