Пример #1
0
func (m *MBC5) Write(addr types.Word, value byte) {
	switch {
	case addr >= 0x0000 && addr <= 0x1FFF:
		if m.hasRAM {
			if r := value & 0x0F; r == 0x0A {
				m.ramEnabled = true
			} else {
				m.ramEnabled = false
			}
		}
	case addr >= 0x2000 && addr <= 0x2FFF:
		//lower 8 bits of rom bank are set here
		m.ROMBLower = types.Word(value)
		m.switchROMBank(int(m.ROMBLower | m.ROMBHigher<<8))
	case addr >= 0x3000 && addr <= 0x3FFF:
		//lowest bit of this value allows you to select banks > 256
		m.ROMBHigher = types.Word(value & 0x01)
		m.switchROMBank(int(m.ROMBLower | m.ROMBHigher<<8))
	case addr >= 0x4000 && addr <= 0x5FFF:
		m.switchRAMBank(int(value & 0x03))
	case addr >= 0xA000 && addr <= 0xBFFF:
		if m.hasRAM && m.ramEnabled {
			m.ramBanks[m.selectedRAMBank][addr-0xA000] = value
		}
	}
}
Пример #2
0
func (g *GPU) RenderBackgroundScanline() {
	//find where in the tile map we are related to the current scan line + scroll Y (wraps around)
	screenYAdjusted := int(g.ly) + int(g.scrollY)
	var initialTilemapOffset types.Word = g.bgTilemap + types.Word(screenYAdjusted)%256/8*32
	var initialLineOffset types.Word = types.Word(g.scrollX) / 8 % 32

	//find where in the tile we are
	initialTileX := int(g.scrollX) % 8
	initialTileY := screenYAdjusted % 8

	//screen will always draw from X = 0
	g.DrawScanline(initialTilemapOffset, initialLineOffset, 0, initialTileX, initialTileY)
}
Пример #3
0
func (mmu *GbcMMU) doInstantDMATransfer(startAddress, destinationAddr types.Word, blocks, blockSize int) {
	length := types.Word(blockSize * blocks)
	var i types.Word = 0x0000
	for ; i < length; i++ {
		data := mmu.ReadByte(startAddress + i)
		mmu.WriteByte(destinationAddr+i, data)
	}
}
Пример #4
0
func ToMemoryAddress(s string) (types.Word, error) {
	if len(s) > 4 {
		return 0x0, errors.New("Please enter an address between 0000 and FFFF")
	}

	result, err := strconv.ParseInt(s, 16, 64)

	return types.Word(result), err
}
Пример #5
0
//This area deals with registers (some only applicable to CGB hardware)
func (mmu *GbcMMU) WriteByteToRegister(addr types.Word, value byte) {
	switch addr {
	case DMG_STATUS_REG:
		mmu.dmgStatusRegister = value
	case CGB_DOUBLE_SPEED_PREP_REG:
		if mmu.RunningColorGBHardware == false {
			log.Printf("%s: WARNING -> Cannot write to %s in non-CGB mode! ROM may have unexpected behaviour (ROM is probably unsupported in non-CGB mode)", PREFIX, CGB_WRAM_BANK_SELECT)
		} else {
			mmu.cgbDoubleSpeedPreparationRegister = value
		}
	case CGB_INFRARED_PORT_REG:
		log.Printf("%s: Attempting to write 0x%X to infrared port register (%s), this is currently unsupported", PREFIX, value, addr)
	//Color GB Working RAM Bank Selection
	case CGB_WRAM_BANK_SELECT:
		if mmu.RunningColorGBHardware == false {
			log.Printf("%s: WARNING -> Cannot write to %s in non-CGB mode! ROM may have unexpected behaviour (ROM is probably unsupported in non-CGB mode)", PREFIX, CGB_WRAM_BANK_SELECT)
		} else {
			mmu.cgbWramBankSelectedRegister = value
		}
	case CGB_HDMA_SOURCE_HIGH_REG:
		mmu.hdmaTransferInfo.Source = (mmu.hdmaTransferInfo.Source & 0x00FF) | types.Word(value)<<8
	case CGB_HDMA_SOURCE_LOW_REG:
		mmu.hdmaTransferInfo.Source = (mmu.hdmaTransferInfo.Source & 0xFF00) | types.Word(value)
	case CGB_HDMA_DEST_HIGH_REG:
		mmu.hdmaTransferInfo.Destination = (mmu.hdmaTransferInfo.Destination & 0x00FF) | types.Word(value)<<8
	case CGB_HDMA_DEST_LOW_REG:
		mmu.hdmaTransferInfo.Destination = (mmu.hdmaTransferInfo.Destination & 0xFF00) | types.Word(value)
	case CGB_HDMA_REG:
		if mmu.RunningColorGBHardware == false {
			log.Printf("%s: WARNING -> Cannot write to %s in non-CGB mode! ROM may have unexpected behaviour (ROM is probably unsupported in non-CGB mode)", PREFIX, CGB_WRAM_BANK_SELECT)
		} else {
			if value&0x80 == 0x00 {
				mmu.hdmaTransferInfo.Length = int(value&0x7F) + 1
				mmu.hdmaTransferInfo.Running = true
				mmu.doInstantDMATransfer(mmu.hdmaTransferInfo.Source, mmu.hdmaTransferInfo.Destination, mmu.hdmaTransferInfo.Length, 16)
			} else {
				log.Println("HDMA horizontal HBlank is unsupported at the moment ")
			}
		}
	default:
		//unknown register, who cares?
		mmu.emptySpace[addr-0xFF4D] = value
	}
}
Пример #6
0
//method to calculate the tilenumber within the tilemap
func (g *GPU) calculateTileNo(tilemapOffset types.Word, lineOffset types.Word) int {
	tileId := int(g.Read(types.Word(tilemapOffset + lineOffset)))

	//if tile data is 0 then it is signed
	if g.tileDataSelect == TILEDATA0 {
		if tileId < 128 {
			tileId += 256
		}
	}
	return tileId
}
Пример #7
0
func (g *GPU) DumpTilemap(tileMapAddr types.Word, tileDataSigned bool) [256][256]types.RGB {
	fmt.Print("Dumping Tilemap ", tileMapAddr)
	if tileDataSigned {
		fmt.Println(" (signed)")
	} else {
		fmt.Println(" (unsigned)")
	}

	var result [256][256]types.RGB
	var tileMapAddrOffset types.Word = tileMapAddr
	var rx int = 0
	var ry int = 0

	for lineX := 0; lineX < 32; lineX++ {
		for tileY := 0; tileY < 8; tileY++ {
			for lineY := 0; lineY < 32; lineY++ {
				tileId := int(g.Read(tileMapAddrOffset + types.Word(lineY)))
				if tileDataSigned {
					if tileId < 128 {
						tileId += 256
					}
				}
				tile := g.tiledata[0][tileId]
				for tileX := 0; tileX < 8; tileX++ {
					cr := GBColours[tile[tileY][tileX]]
					result[rx][ry] = cr
					rx++
				}
			}
			rx = 0
			ry++
		}
		tileMapAddrOffset += types.Word(32)
	}
	return result
}
Пример #8
0
func (g *GPU) RenderWindowScanline() {
	screenYAdjusted := g.ly - int(g.windowY)

	if (g.windowX >= 0 && g.windowX < 167) && (g.windowY >= 0 && g.windowY < 144) && screenYAdjusted >= 0 {
		var initialTilemapOffset types.Word = g.windowTilemap + types.Word(screenYAdjusted)/8*32
		var initialLineOffset types.Word = 0
		var screenXAdjusted int = int((g.windowX - 7) % 255)

		//find where in the tile we are
		initialTileX := screenXAdjusted % 8
		initialTileY := screenYAdjusted % 8

		g.DrawScanline(initialTilemapOffset, initialLineOffset, screenXAdjusted, initialTileX, initialTileY)
	}
}
Пример #9
0
func (mmu *GbcMMU) WriteByte(addr types.Word, value byte) {
	//Check peripherals first
	if p, ok := mmu.peripheralIOMap[addr]; ok {
		p.Write(addr, value)
		return
	}

	switch {
	case addr >= 0x0000 && addr <= 0x9FFF:
		mmu.cartridge.MBC.Write(addr, value)
	//Cartridge External RAM
	case addr >= 0xA000 && addr <= 0xBFFF:
		mmu.cartridge.MBC.Write(addr, value)
	//GB Internal RAM
	case addr >= 0xC000 && addr <= 0xDFFF:
		mmu.WriteToWorkingRAM(addr, value)
		//copy value to shadow if within shadow range
		if addr >= 0xC000 && addr <= 0xDDFF {
			mmu.internalRAMShadow[addr&(0xDDFF-0xC000)] = mmu.ReadByte(addr)
		}
	case addr == 0xFF01 || addr == 0xFF02:
		//serial cable communication
		mmu.serialTmp = ZERO
	//INTERRUPT FLAG
	case addr == 0xFF0F:
		mmu.interruptsFlag = value
	//DMA transfer
	case addr == 0xFF46:
		var startAddr types.Word = types.Word(value) << 8
		var oamAddr types.Word = 0xFE00
		//transfer 10 blocks to OAM
		mmu.doInstantDMATransfer(startAddr, oamAddr, 10, 16)
	//Empty but "unusable for I/O"
	case addr > 0xFF4C && addr <= 0xFF7F:
		mmu.WriteByteToRegister(addr, value)
	//Zero page RAM
	case addr >= 0xFF80 && addr <= 0xFFFF:
		if addr == 0xFFFF {
			mmu.interruptsEnabled = value
		} else {
			mmu.zeroPageRAM[addr&(0xFFFF-0xFF80)] = value
		}
	default:
		//log.Printf("%s: WARNING - Attempting to write 0x%X to address %s, this is invalid/unimplemented", PREFIX, value, addr)
	}
}
Пример #10
0
//CGB has additional attributes in bank 1 for each background tile
func (g *GPU) getCGBBackgroundTileAttrs(tilemapOffset types.Word, lineOffset types.Word) (int, *CGBBackgroundTileAttrs) {
	if g.RunningColorGBHardware {
		var currentSelectedBankTmp byte = g.cgbVramBankSelectionRegister

		//tile number data always comes from bank 0
		g.cgbVramBankSelectionRegister = 0
		var tileNo int = g.calculateTileNo(tilemapOffset, lineOffset)

		//tile attribute data always comes from bank 1
		g.cgbVramBankSelectionRegister = 1
		var attributeData byte = g.Read(types.Word(tilemapOffset + lineOffset))

		//revert bank selection register to what it was set to previously
		g.cgbVramBankSelectionRegister = currentSelectedBankTmp

		return tileNo, NewCGBBackgroundTileAttrs(attributeData)
	} else {
		panic("Cannot call this function, not in color gb mode!")
	}

	return -1, nil
}
Пример #11
0
func (m *MockMMU) ReadWord(address types.Word) types.Word {
	a, b := m.memory[address], m.memory[address+1]
	return (types.Word(a) << 8) ^ types.Word(b)
}
Пример #12
0
func (mmu *GbcMMU) ReadWord(addr types.Word) types.Word {
	var b1 byte = mmu.ReadByte(addr)
	var b2 byte = mmu.ReadByte(addr + 1)
	return types.Word(utils.JoinBytes(b1, b2))
}