⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mem.c

📁 日本的手持pda源码.wince下使用,完全开源
💻 C
字号:


#include <stdlib.h>

#include "defs.h"
#include "hw.h"
#include "regs.h"
#include "mem.h"
#include "rtc.h"
#include "lcd.h"
#include "fastmem.h"
#include "cpu.h"

struct mbc mbc;
struct rom rom;
struct ram ram;


void mem_init()
{
	memset (&mbc, 0, sizeof(mbc));
	memset (&rom, 0, sizeof(rom));
	memset (&ram, 0, sizeof(ram));
}


/*
 * In order to make reads and writes efficient, we keep tables
 * (indexed by the high nibble of the address) specifying which
 * regions can be read/written without a function call. For such
 * ranges, the pointer in the map table points to the base of the
 * region in host system memory. For ranges that require special
 * processing, the pointer is NULL.
 *
 * mem_updatemap is called whenever bank changes or other operations
 * make the old maps potentially invalid.
 */

/* constant mapping */
void mem_map_const() 
{
	byte **map;
	
	map = mbc.rmap;
	map[0x0] = map[0x1] = map[0x2] = map[0x3] = rom.bank[0];
	map[0xc] = ram.ibank[0] - 0xC000;
	map[0xe] = ram.ibank[0] - 0xE000;
	map[0xf] = NULL;
	
	map = mbc.wmap;
	map[0x0] = map[0x1] = map[0x2] = map[0x3] = NULL;
	map[0x4] = map[0x5] = map[0x6] = map[0x7] = NULL;
	map[0x8] = map[0x9] = NULL;
	map[0xc] = ram.ibank[0] - 0xC000;
	map[0xe] = ram.ibank[0] - 0xE000;
	map[0xf] = NULL;
}

INLINE mem_updatemap_rombank()
{
	mbc.rombank &= (mbc.romsize - 1);
	mbc.rmap[0x4] = mbc.rmap[0x5] = 
		mbc.rmap[0x6] = mbc.rmap[0x7] = rom.bank[mbc.rombank] - 0x4000;
}

INLINE mem_updatemap_vbank()
{
	mbc.rmap[0x8] = mbc.rmap[0x9] = lcd.vbank[R_VBK & 1] - 0x8000;
}

INLINE mem_updatemap_sbank()
{
	mbc.rambank &= (mbc.ramsize - 1);
	if (mbc.enableram && !(rtc.sel&8))
		mbc.rmap[0xa] = mbc.rmap[0xb] = mbc.wmap[0xa] = mbc.wmap[0xb] = ram.sbank[mbc.rambank] - 0xA000;
	else 
		mbc.rmap[0xa] = mbc.rmap[0xb] = mbc.wmap[0xa] = mbc.wmap[0xb] = 0;
}

INLINE mem_updatemap_ibank()
{
	int n = R_SVBK & 0x07;
	mbc.rmap[0xd] = mbc.wmap[0xd] = ram.ibank[n ? n : 1] - 0xD000;
}

/* dynamic mapping */
void mem_updatemap()
{
	mem_updatemap_rombank();
	mem_updatemap_vbank();
	mem_updatemap_sbank();
	mem_updatemap_ibank();
}

/*
 * ioreg_write handles output to io registers in the FF00-FF7F,FFFF
 * range. It takes the register number (low byte of the address) and a
 * byte value to be written.
 */

INLINE void mem_write_hi(byte r, byte b)
{
	if (!hw.cgb)
	{
		switch (r)
		{
		case RI_VBK:
		case RI_BCPS:
		case RI_OCPS:
		case RI_BCPD:
		case RI_OCPD:
		case RI_SVBK:
		case RI_KEY1:
		case RI_HDMA1:
		case RI_HDMA2:
		case RI_HDMA3:
		case RI_HDMA4:
		case RI_HDMA5:
			return;
		}
	}
	
	switch(r)
	{
	case RI_TAC:
		cpu.tac_speed = ((-b) & 3) << 1;
		cpu.tac_start = (b & 0x04);
		break;
	case RI_TIMA:
	case RI_TMA:
	case RI_SCY:
	case RI_SCX:
	case RI_WY:
	case RI_WX:
		REG(r) = b;
		break;
	case RI_BGP:
		if (R_BGP == b) break;
		pal_write_dmg(0, 0, b);
		pal_write_dmg(8, 1, b);
		R_BGP = b;
		break;
	case RI_OBP0:
		if (R_OBP0 == b) break;
		pal_write_dmg(64, 2, b);
		R_OBP0 = b;
		break;
	case RI_OBP1:
		if (R_OBP1 == b) break;
		pal_write_dmg(72, 3, b);
		R_OBP1 = b;
		break;
	case RI_IF:
	case RI_IE:
		REG(r) = b & 0x1F;
		break;
	case RI_P1:
		REG(r) = b;
		pad_refresh();
		break;
	case RI_SC:
		/* FIXME - this is a hack for stupid roms that probe serial */
		if ((b & 0x81) == 0x81)
		{
			R_SB = 0xff;
			hw_interrupt(IF_SERIAL, IF_SERIAL);
		}
		R_SC = b; /* & 0x7f; */
		break;
	case RI_DIV:
		REG(r) = 0;
		break;
	case RI_LCDC:
		lcdc_change(b);
		break;
	case RI_STAT:
		stat_change(b);
		break;
	case RI_LY:
		ly_change(b);
		break;
	case RI_LYC:
		REG(r) = b;
		break;
	case RI_VBK:
		REG(r) = b | 0xFE;
		mem_updatemap_vbank();
		break;
	case RI_BCPS:
		R_BCPS = b & 0xBF;
		R_BCPD = lcd.pal[b & 0x3F];
		break;
	case RI_OCPS:
		R_OCPS = b & 0xBF;
		R_OCPD = lcd.pal[64 + (b & 0x3F)];
		break;
	case RI_BCPD:
		R_BCPD = b;
		pal_write(R_BCPS & 0x3F, b);
		if (R_BCPS & 0x80) R_BCPS = (R_BCPS+1) & 0xBF;
		break;
	case RI_OCPD:
		R_OCPD = b;
		pal_write(64 + (R_OCPS & 0x3F), b);
		if (R_OCPS & 0x80) R_OCPS = (R_OCPS+1) & 0xBF;
		break;
	case RI_SVBK:
		REG(r) = b & 0x07;
		mem_updatemap_ibank();
		break;
	case RI_DMA:
		hw_dma(b);
		break;
	case RI_KEY1:
		REG(r) = (REG(r) & 0x80) | (b & 0x01);
		break;
	case RI_HDMA1:
		REG(r) = b;
		break;
	case RI_HDMA2:
		REG(r) = b & 0xF0;
		break;
	case RI_HDMA3:
		REG(r) = b & 0x1F;
		break;
	case RI_HDMA4:
		REG(r) = b & 0xF0;
		break;
	case RI_HDMA5:
		hw_hdma_cmd(b);
		break;
	default:
		/* return writehi(a & 0xFF, b); */
		if (r >= 0x10 && r <= 0x3F)
		{
			sound_write(r, b);
			break;
		}
		// 0xFF or stack
		REG(r) = b;
		break;
	}
}


INLINE byte mem_read_hi(byte r)
{
	switch(r)
	{
	case RI_SC:
		r = R_SC;
		R_SC &= 0x7f;
		return r;
	case RI_DIV:
		div_advance();
		return REG(r);
	case RI_TIMA:
	case RI_TMA:
	case RI_P1:
	case RI_SB:
	case RI_TAC:
	case RI_LCDC:
	case RI_SCY:
	case RI_SCX:
	case RI_LY:
	case RI_LYC:
	case RI_BGP:
	case RI_OBP0:
	case RI_OBP1:
	case RI_WY:
	case RI_WX:
	case RI_IE:
	case RI_IF:
		return REG(r);
	case RI_STAT:
		return R_STAT | ((R_LY == R_LYC) ? 4 : 0);
	case RI_VBK:
	case RI_BCPS:
	case RI_OCPS:
	case RI_BCPD:
	case RI_OCPD:
	case RI_SVBK:
	case RI_KEY1:
	case RI_HDMA1:
	case RI_HDMA2:
	case RI_HDMA3:
	case RI_HDMA4:
	case RI_HDMA5:
		if (hw.cgb) return REG(r);
	default:
		if (r >= 0x10 && r <= 0x3F)
			return sound_read(r);
		// 0xFF or stack
		return REG(r);
	}
}

/*
 * Memory bank controllers typically intercept write attempts to
 * 0000-7FFF, using the address and byte written as instructions to
 * change rom or sram banks, control special hardware, etc.
 *
 * mbc_write takes an address (which should be in the proper range)
 * and a byte value written to the address.
 */

INLINE void mbc_write(int a, byte b)
{
	byte ha = (a>>12);

	/* printf("mbc %d: rom bank %02X -[%04X:%02X]-> ", mbc.type, mbc.rombank, a, b); */
	switch (mbc.type)
	{
	case MBC_MBC1:
		ha &= 0xE;
		switch (ha)
		{
		case 0x0:
			mbc.enableram = ((b & 0x0F) == 0x0A);
			mem_updatemap_sbank();
			break;
		case 0x2:
			if ((b & 0x1F) == 0) b = 0x01;
			mbc.rombank = (mbc.rombank & 0x60) | (b & 0x1F);
			mem_updatemap_rombank();
			break;
		case 0x4:
			if (mbc.model)
			{
				mbc.rambank = b & 0x03;
				mem_updatemap_sbank();
				break;
			}
			mbc.rombank = (mbc.rombank & 0x1F) | ((int)(b&3)<<5);
			mem_updatemap_rombank();
			break;
		case 0x6:
			mbc.model = b & 0x1;
			break;
		}
		break;
	case MBC_MBC2: /* is this at all right? */
		if ((a & 0x0100) == 0x0000)
		{
			mbc.enableram = ((b & 0x0F) == 0x0A);
			mem_updatemap_sbank();
			break;
		}
		if ((a & 0xE100) == 0x2100)
		{
			mbc.rombank = b & 0x0F;
			mem_updatemap_rombank();
			break;
		}
		break;
	case MBC_MBC3:
		ha &= 0xE;
		switch (ha)
		{
		case 0x0:
			mbc.enableram = ((b & 0x0F) == 0x0A);
			mem_updatemap_sbank();
			break;
		case 0x2:
			if ((b & 0x7F) == 0) b = 0x01;
			mbc.rombank = b & 0x7F;
			mem_updatemap_rombank();
			break;
		case 0x4:
			rtc.sel = b & 0x0f;
			mbc.rambank = b & 0xf;
			mem_updatemap_sbank();
			break;
		case 0x6:
			rtc_latch(b);
			break;
		}
		break;
	case MBC_RUMBLE:
		ha &= 0xF;
		switch (ha)
		{
		case 0x4:
		case 0x5:
			/* FIXME - save high bit as rumble state */
			/* mask off high bit */
			b &= 0x7;
			break;
		}
		/* fall thru */
	case MBC_MBC5:
		ha &= 0xF;
		switch (ha)
		{
		case 0x0:
		case 0x1:
			mbc.enableram = ((b & 0x0F) == 0x0A);
			mem_updatemap_sbank();
			break;
		case 0x2:
			if ((b & 0xFF) == 0) b = 0x01;
			mbc.rombank = (mbc.rombank & 0x100) | (b & 0xFF);
			mem_updatemap_rombank();
			break;
		case 0x3:
			mbc.rombank = (mbc.rombank & 0xFF) | ((int)(b&1)<<8);
			mem_updatemap_rombank();
			break;
		case 0x4:
		case 0x5:
			mbc.rambank = b & 0x0f;
			mem_updatemap_sbank();
			break;
		}
		break;
	case MBC_HUC1: /* FIXME - this is all guesswork -- is it right??? */
		ha &= 0xE;
		switch (ha)
		{
		case 0x0:
			mbc.enableram = ((b & 0x0F) == 0x0A);
			mem_updatemap_sbank();
			break;
		case 0x2:
			if ((b & 0x1F) == 0) b = 0x01;
			mbc.rombank = (mbc.rombank & 0x60) | (b & 0x1F);
			mem_updatemap_rombank();
			break;
		case 0x4:
			if (mbc.model)
			{
				mbc.rambank = b & 0x03;
				mem_updatemap_sbank();
				break;
			}
			mbc.rombank = (mbc.rombank & 0x1F) | ((int)(b&3)<<5);
			mem_updatemap_rombank();
			break;
		case 0x6:
			mbc.model = b & 0x1;
			break;
		}
		break;
	case MBC_HUC3:
		ha &= 0xE;
		switch (ha)
		{
		case 0x0:
			mbc.enableram = ((b & 0x0F) == 0x0A);
			mem_updatemap_sbank();
			break;
		case 0x2:
			b &= 0x7F;
			mbc.rombank = b ? b : 1;
			mem_updatemap_rombank();
			break;
		case 0x4:
			rtc.sel = b & 0x0f;
			mbc.rambank = b & 0x03;
			mem_updatemap_sbank();
			break;
		case 0x6:
			rtc_latch(b);
			break;
		}
		break;
	}
}

/*
 * mem_write is the basic write function. Although it should only be
 * called when the write map contains a NULL for the requested address
 * region, it accepts writes to any address.
 */

void mem_write(int a, byte b)
{
	byte ha = (a >> 12);
	/* printf("write to 0x%04X: 0x%02X\n", a, b); */
	switch (ha)
	{
	case 0x0:
	case 0x1:
	case 0x2:
	case 0x3:
	case 0x4:
	case 0x5:
	case 0x6:
	case 0x7:
		mbc_write(a, b);
		break;
	case 0x8:
	case 0x9:
		/* if ((R_STAT & 0x03) == 0x03) break; */
		vram_write(a & 0x1FFF, b);
		break;
	case 0xA:
	case 0xB:
		if (!mbc.enableram) break;
		if (rtc.sel&8)
		{
			rtc_write(b);
			break;
		}
		ram.sbank[mbc.rambank][a & 0x1FFF] = b;
		break;
	case 0xE:
	case 0xF:
		if (a >= 0xFF00)
		{
			mem_write_hi(a & 0xFF, b);
			break;
		}
		if (a < 0xFE00)
		{
			mem_write(a & 0xDFFF, b);
			break;
		}
		if (a < 0xFEA0)lcd.oam.mem[a & 0xFF] = b;
		break;
	}
}


/*
 * mem_read is the basic read function...not useful for much anymore
 * with the read map, but it's still necessary for the final messy
 * region.
 */

byte mem_read(int a)
{
	byte ha = (a >> 12);
	/* printf("read %04x\n", a); */
	switch (ha)
	{
	case 0xA:
	case 0xB:
		if (!mbc.enableram && mbc.type == MBC_HUC3)
			return 0x01;
		if (!mbc.enableram)
			return 0xFF;
		if (rtc.sel&8)
			return rtc.regs[rtc.sel&7];
		return ram.sbank[mbc.rambank][a & 0x1FFF];
	case 0xE:
	case 0xF:
		if (a >= 0xFF00) return mem_read_hi(a & 0xFF);
		if (a < 0xFE00) return readb(a & 0xDFFF);
		/* if (R_STAT & 0x02) return 0xFF; */
		if (a < 0xFEA0) return lcd.oam.mem[a & 0xFF];
		return 0xFF;
	}
	return 0xff; /* not reached */
}

void mbc_reset()
{
	mbc.rombank = 1;
	mbc.rambank = 0;
	mbc.enableram = 0;
	mem_map_const();
	mem_updatemap();
}







⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -