Exemplo n.º 1
0
void CPU::WriteByte(ushort address, uchar data)
{
	// writing to cartridge ROM; swaps ROM banks
	if (address < 0x8000)
	{
		cartridge->WriteToMemory(address, data);
	}

	// writing to cartridge RAM
	else if (address >= 0xA000 && address < 0xC000)
	{
		ushort adjustedAddress = address - 0xA000;
		cartridge->WriteToRAM(adjustedAddress, data);
	}

	// writing to ECHO; also write to RAM
	else if (address >= 0xE000 && address < 0xFE00)
	{
		memory->WriteByte(address, data);
		memory->WriteByte(address - 0x2000, data);
	}

	// restricted
	else if (address >= 0xFEA0 && address < 0xFEFF)
	{
		// do nothing
	}

	// writing to TMC
	else if (address == TMC)
	{
		memory->WriteByte(address, data);
		SetClockFrequency();
	}

	// writing to DIV
	else if (address == 0xFF04)
	{
		memory->WriteByte(address, 0);
	}

	// writing to scanline register
	else if (address == 0xFF44)
	{
		memory->WriteByte(address, 0);
	}

	// writing to DMA trigger
	else if (address == 0xff46)
	{
		DMATransfer(data);
	}

	else
	{
		memory->WriteByte(address, data);
	}
}
Exemplo n.º 2
0
void MMU::WriteByte(unsigned _int16 address, uint8 value){
	switch (address & 0xF000){
		//TODO: support for (MBC5), not that its used much anyway
	case 0x0000:
	case 0x1000:
		switch (type){
		//(MBC1)Enable RAM Bank if XXXX1010_2 (0x0A) is written, disable if anything else is written
		//(MBC2)Toggle cart RAM if the LSB of the upper address byte is 0 and same test as MBC1
		case MBC2:
			if ((address & 0x10u) > 0){
				break;
			}//if 0, just fall through
		//(MBC3)Same as MBC1, also enables read/writes to clock registers on cart
		case MBC1:
		case MBC3:
		case MBC5:
			if ((value & 0xFu) == 0xAu)
				ramWriteEnable = true;
			else
				ramWriteEnable = false;
			break;
		}
		break;
	case 0x2000:
		//(MBC5)Lower 8 bits of ROM bank number
		//(MBC5)Unlike others, writing 0 actually gives rom bank 0
		if (type == MBC5){
			currentROMBank &= ~(0xFF);
			currentROMBank |= (value);
		}
	case 0x3000:
		switch (type){
		//(MBC1)Switch bank to XXXBBBBB_2, where X=don't care (0x00-0x1F)
		//(MBC1)Values of B=1 and B=0 are functionally equivalent, bank#0 is accessible from 0x0000-0x3FFF
		//(MBC1)Values of 0x20, 0x40, and 0x60 will result in 0x21, 0x41, 0x61 respectively
		case MBC1:
			currentROMBank &= 0xE0u;	//set lower 5 bits to 0;
			currentROMBank |= (value & 0x1F);
			if (currentROMBank == 0 || currentROMBank == 0x20u || currentROMBank == 0x40u || currentRAMBank == 0x60u)
				currentROMBank++;
			std::cout << std::hex << "Switch to " << currentROMBank << std::endl;
			break;
		//(MBC2)Switch ROM bank to XXXXBBBB_2, where X=don't care
		//(MBC2)Address must have the LSB of the upper address byte = 1 (X1XX,X3XX,X5XX,etc.)
		case MBC2:
			currentROMBank &= 0xF0u;
			currentROMBank |= (value & 0xFu);
			if (currentROMBank == 0)
				currentROMBank++;
			break;
		//(MBC3)Writing a value of XBBBBBBB_2 selects the appropriate ROM bank (value of 0 is a value of 1 again)
		case MBC3:
			currentROMBank &= 0x80u;
			currentROMBank |= (value & 0x7Fu);
			if (currentROMBank == 0)
				currentROMBank++;
			break;
		//(MBC5) Write the MSB (bit 9) of the rom bank from the LSB of value
		case MBC5:
			currentROMBank &= ~(0x100u);
			currentROMBank |= (value & 0x01u);
		}
		break;
	case 0x4000:
	case 0x5000:
		switch (type){
		//(MBC1)If in 4/32 Mode, switch RAM bank XXXXXXBB_2 (0x00-0x03)
		//(MBC1)If in 16/8 Mode, set the two most significant ROM address lines to XXXXXXBB_2 (Bits 5 and 6)
		case MBC1:
			if (type == romSwitch){
				currentROMBank &= 0x1Fu; //turn off bits 5 and 6
				currentROMBank |= ((value & 0x03) << 5);
				if (currentROMBank == 0 || currentROMBank == 0x20u || currentROMBank == 0x40u || currentRAMBank == 0x60u)
					currentROMBank++;
				std::cout << std::hex << "Switch to " << currentROMBank << std::endl;
			}
			else{	//RAM switching
				currentRAMBank = (value & 0x03u);
			}
		case MBC2:
			break;
		//(MBC3)If a value of 0x00-0x03 is written, select that RAM bank
		//(MBC3)If a value of 0x08-0x0C is written, select that RTC register
		case MBC3:
			if (value <= 0x03u){
				currentRAMBank = value & 0x03u;
			}
			else if (value >= 0x08u && value <= 0x0cu){
				currentRTCRegister = getRTCReg(value);
			}
		case MBC5:
			currentRAMBank = (value & 0x0Fu);
		}
		break;
	case 0x6000:
	case 0x7000:
		switch (type){
		//(MBC1)Switch to memory mode specified by XXXXXXXB_2, where X= don't care
		//(MBC1)B=0 -> 16Mb ROM/8Kb RAM, B=1 -> 4Mb ROM/32Kb RAM
		case MBC1:
			if ((value & 0x01u) == 0){
				mode = romSwitch;
			}
			else{
				mode = ramSwitch;
				currentRAMBank = 0;	//no ram switching
			}
		case MBC5:
		case MBC2:
			break;
		//(MBC3)Latch clock data if 0x00 then 0x01 is written (write current time to RTC registers)
		case MBC3:
			if (value == 0x00u){
				RTCLatchPossible = true;
			}
			if (RTCLatchPossible && (value == 0x01u)){
				//TODO: RTC Latch here
				RTCLatchPossible = false;
			}
		}
		break;
	case 0x8000:
	case 0x9000:
		vram[address & 0x1FFFu] = value;
		break;
	case 0xA000:
	case 0xB000:
		if (eram == nullptr)
			break;
		//(MBC2) only addressable from 0xA000 to 0xA1FF
		//(MBC2) only write lower 4 bits of value (512 x 4bit values)
		if (!ramWriteEnable)
			break;
		if (type == MBC2){
			if (address <= 0xA1FFu){
				eram[address & 0x1FFFu] = value & 0x0001u;
			}
		}
		else
			eram[address & 0x1FFFu] = value;
		break;
	case 0xC000:
	case 0xD000:
	case 0xE000:
		wram[address & 0x1FFFu] = value;
		break;
	case 0xF000:
		switch (address & 0x0F00u)
		{
			// Echo RAM
		case 0x000: case 0x100: case 0x200: case 0x300:
		case 0x400: case 0x500: case 0x600: case 0x700:
		case 0x800: case 0x900: case 0xA00: case 0xB00:
		case 0xC00: case 0xD00:
			wram[address & 0x1FFFu] = value;
			break;

			// OAM
		case 0xE00:
			if ((address & 0xFF)<0xA0)	//anything after A0 should be 0s
				oam[address & 0xFFu] = value;
			break;

			// Zeropage RAM, I/O
		case 0xF00:
			if (address > 0xFF7F)
				zram[address & 0x7Fu] = value;
			else{
				if (address == 0xFF00u){	//change which column of keys we are looking at
					keyColumn = value & 0x30u;
				}
				else if (address == 0xFF04u){	//writes to the DIV register reset the DIV timer
					io[0x04] = 0;
				}
				else if (address == 0xFF07){
					uint8 currentTMC = io[0x07];
					uint8 newTMC = value;
					io[0x07] = value;

					if ((currentTMC & 0x03) != (newTMC & 0x03)){	//clock frequency has changed, so reset the counter for it
						switch (newTMC & 0x03){
						case 0x0u:
							c->timerPeriod = 1024;
							break;
						case 0x1u:
							c->timerPeriod = 16;
							break;
						case 0x2u:
							c->timerPeriod = 64;
							break;
						case 0x3u:
							c->timerPeriod = 256;
							break;
						}
					}
				}
				else if (address == 0xFF44){
					io[0x44] = 0;
				}
				else if (address == 0xFF46){
					DMATransfer(value);
				}
				else{
					io[address & 0x7Fu] = value;
				}
			}
		}
		break;
	}
}