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

📄 pgbmemory.java

📁 一个用java写成的gb模拟器的源代码。
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
/**
 * this source file released under the GNU Public Licence.
 * see the accompanying copyright.txt for more information.
 * Copyright (C) 2000-2001 Ben Mazur
 * modified by retroK, XTale and baka0815 2004 http://aepgb.aep-emu.de/
 */

/**
 * PgbMemory controls the entire memory map of the Gameboy.
 * 
 * It also contains some executing code, mostly in cycle(),
 * which is responsible for controlling the hardware and
 * setting the interrupt flag each CPU cycle.
 * 
 * Also, DMA functions are handled here and SGB calls are
 * interpreted here and then (usually) passed on to the
 * video hardware.
 */
public final class PgbMemory {
	public PgbCart cart;
	public PgbVideo video;
	public PgbJoypad joy;
	public PgbNetplay net;

	// by retroK
	public SoundChip soundChip;
	boolean soundOn;
	byte soundIO[];
	// end retroK

	public static final byte INT_JOYPAD = 0x10;
	public static final byte INT_SERIAL = 0x08;
	public static final byte INT_TIMER = 0x04;
	public static final byte INT_LCD = 0x02;
	public static final byte INT_VBLANK = 0x01;

	protected byte[] hiRAM;
	protected byte[] loRAM;

	public byte IF;
	public byte IE;

	public int tima;
	public int tma;
	public byte tac;

	protected boolean timerOn;
	protected int timeCounter;
	protected int timeLimit;

	public int div;

	// how many cycles left until something happens?
	public int cycles;
	public int cyclesLeft;
	public int cyclesSkipped;

	// Super Gameboy stuff
	protected int sgbBitCounter;
	protected int sgbPacketCounter;
	protected byte[] sgbBuffer;
	protected boolean sgbListening;

	protected int sgbCommand;
	protected int sgbPackets;

	// gameboy color
	byte gbcRAM;
	int loRAMOffset;
	byte gbcSpeed;

	byte rHDMA1;
	byte rHDMA2;
	byte rHDMA3;
	byte rHDMA4;

	int hdmaSrc;
	int hdmaDst;
	boolean hdmaDone;
	byte hdmaLastMode;
	int hdmaStop;

	public PgbMemory(
		PgbCart cart,
		PgbVideo video,
		PgbJoypad joy,
		PgbNetplay net) {
		this.cart = cart;
		this.video = video;
		this.joy = joy;
		this.net = net;

		hiRAM = new byte[0x80];
		loRAM = new byte[0x8000];

		sgbBuffer = new byte[0x80]; // max 8 packets for now

		// by retroK add sound
		soundOn = true;
		soundChip = new SoundChip();
		soundIO = new byte[64];
		// end by retroK

		reset();
	}

	// by retroK:
	public void soundPlay() {
		soundChip.outputSound();
	}

	public int unsign(byte b) {
		return (b & 0xff);
	}
	
	public void reset() {
		tima = 0;
		tma = 0;
		tac = 0;

		timerOn = false;
		timeCounter = 0;
		timeLimit = 0;

		div = 0xAF * 0x100;

		IF = 1;
		IE = 0;

		sgbBitCounter = 0;
		sgbPacketCounter = 0;
		sgbListening = false;
		sgbPackets = 1;

		gbcRAM = (byte) 0x00;
		loRAMOffset = 0xC000;

		gbcSpeed = (byte) 0x7E;

		cycles = 0;
		cyclesLeft = Integer.MAX_VALUE;
		recalcCyclesLeft();

		hdmaDone = true;
		hdmaLastMode = PgbVideo.STAT_HBLANK;

		// by retroK: reset sound
		soundIO[16] = -128;
		soundIO[17] = -65;
		soundIO[18] = -13;
		soundIO[20] = -65;
		soundIO[22] = 63;
		soundIO[23] = 0;
		soundIO[25] = -65;
		soundIO[26] = 127;
		soundIO[27] = -1;
		soundIO[28] = -97;
		soundIO[30] = -65;
		soundIO[32] = -1;
		soundIO[33] = 0;
		soundIO[34] = 0;
		soundIO[35] = -65;
		soundIO[36] = 119;
		soundIO[37] = -13;
		soundIO[38] = -15;
	}

	/**
	 * Recaclulates the number of cycles left.  Called
	 * when the timer, LCDC, LCY, or serial control is
	 * changed.
	 */
	public void recalcCyclesLeft() {
		cyclesLeft = Integer.MAX_VALUE;
		// check cycles until timer
		if (timerOn && (timeLimit - timeCounter) < cyclesLeft) {
			cyclesLeft = (timeLimit - timeCounter);
		}
		// check cycles until next video mode switch
		if (video.lcd_on && video.cyclesLeft() < cyclesLeft) {
			cyclesLeft = video.cyclesLeft();
		}
		// check cycles until next serial check
		if (net.cyclesLeft() < cyclesLeft) {
			cyclesLeft = net.cyclesLeft();
		}
		// of course, this can't guess when a joystick
		// interrupt will occur.
	}

	/**
	 * Advances the state of the hardware as though the number
	 * of cpu cycles specified had passed and sets the interrupt
	 * register appropriately.
	 * 
	 * @param cv the number of cpu cycles to advance.
	 */
	public final void cycle(int cv) {
		cycles += cv;
		if (cycles > cyclesLeft) {
			// divider register (is this right at all?)
			// (does anything really use the divider register?)
			div -= cyclesLeft;
			if (div < 0) {
				div = 0xFF * 0x100;
			}
			// timer (does timer run w/o timer interrupt enabled?)
			if (timerOn) { // yes?
				timeCounter += cyclesLeft;
				if (timeCounter >= timeLimit) {
					timeCounter = 0;
					tima++;
				}
				if (tima > 255) {
					tima = tma;
					IF |= INT_TIMER;
				}
			}
			// netplay cycle
			/*if(true || (IE & INT_SERIAL) == INT_SERIAL)*/ {
				IF |= net.cycle(cyclesLeft);
			}
			// video cycle
			if (video.lcd_on) {
				IF |= video.cycle(cyclesLeft, this);
			}
			// hdma transfer
			if (!hdmaDone) {
				if (hdmaLastMode != PgbVideo.STAT_HBLANK
					&& (byte) (video.getStat() & 0x03) == PgbVideo.STAT_HBLANK) {
					// transfer 16 bytes
					write(hdmaDst++, read(hdmaSrc++));
					write(hdmaDst++, read(hdmaSrc++));
					write(hdmaDst++, read(hdmaSrc++));
					write(hdmaDst++, read(hdmaSrc++));
					write(hdmaDst++, read(hdmaSrc++));
					write(hdmaDst++, read(hdmaSrc++));
					write(hdmaDst++, read(hdmaSrc++));
					write(hdmaDst++, read(hdmaSrc++));
					write(hdmaDst++, read(hdmaSrc++));
					write(hdmaDst++, read(hdmaSrc++));
					write(hdmaDst++, read(hdmaSrc++));
					write(hdmaDst++, read(hdmaSrc++));
					write(hdmaDst++, read(hdmaSrc++));
					write(hdmaDst++, read(hdmaSrc++));
					write(hdmaDst++, read(hdmaSrc++));
					write(hdmaDst++, read(hdmaSrc++));
					if (hdmaDst >= hdmaStop) {
						hdmaDone = true;
					}
				}
				// eat up the rest of the hblank
				//IF |= video.cycle(video.cycles);
				hdmaLastMode = (byte) (video.getStat() & 0x03);
			}

			cycles -= cyclesLeft;
			recalcCyclesLeft();
		}
	}

	/**
	 * Set the timer control.
	 */
	public void setTac(byte tac) {
		timerOn = (tac & 0x04) == 0x04;
		timeCounter = 0;

		switch (tac & 0x03) {
			case 0 :
				timeLimit = 1024;
				break;
			case 1 :
				timeLimit = 16;
				break;
			case 2 :
				timeLimit = 64;
				break;
			case 3 :
				timeLimit = 256;
				break;
		}
		//recalcCyclesLeft();
	}

	/**
	 * Reads (signed) bytes from GB memory.
	 * 
	 * @param address the gameboy memory address to read from.
	 */
	public final byte read(int address) {
		switch (address) {
		// Joypad Register (R/W)
		case 0xFF00 :
			return joy.read();
			// Serial Transfer Data (R/W)
		case 0xFF01 :
			return net.getSerialData();
			// SIO control  (R/W)
		case 0xFF02 :
			return net.getSerialControl();
			// empty GB registers?
		case 0xFF03 :
			return 0;
			// Divider Register (R/W)
		case 0xFF04 :
			// System.out.println("read Divider Register:" + (byte)(div / 0x100));
			return (byte) (div / 0x100);
			// Timer counter (R/W)
		case 0xFF05 :
			//System.out.println("read Timer counter:" + tima);
			return (byte) tima;
			// Timer Modulo (R/W)
		case 0xFF06 :
			return (byte) tma;
			// Timer Control
		case 0xFF07 :
			return (byte) tac;
			// Interrupt Flag (R/W)
		case 0xFF0F :
			return IF;
			// LCD Control (R/W)
		case 0xFF40 :
			return video.getLcdc();
			// LCDC Status   (R/W)
		case 0xFF41 :
			return video.getStat();
			// Scroll Y   (R/W)
		case 0xFF42 :
			return (byte) video.scy;
			// Scroll X   (R/W)
		case 0xFF43 :
			return (byte) video.scx;
			// LCDC Y-Coordinate (R)
		case 0xFF44 :
			return (byte) video.ly;
			// LY Compare  (R/W)
		case 0xFF45 :
			return (byte) video.lyc;
			// BG & Window Palette Data  (R/W)
		case 0xFF47 :
			return (byte) video.bgpal;
			// Object Palette 0 Data (R/W)
		case 0xFF48 :
			return (byte) video.objpal0;
			// Object Palette 1 Data (R/W)
		case 0xFF49 :
			return (byte) video.objpal1;
			// Window Y Position  (R/W)
		case 0xFF4A :
			return (byte) video.wy;
			// Window X Position  (R/W)
		case 0xFF4B :
			return (byte) video.wx;
			// GBC CPU Speed (R/W)
		case 0xFF4D :
			return gbcGetSpeed();
			// GBC VRAM bank
		case 0xFF4F :
			//System.out.println("read GBC VRAM bank:" + Integer.toHexString(address));
			return video.gbcGetVram();
			// GBC rHDMA5 (DMA Mode / Control)
		case 0xFF55 :
			//System.out.println("read GBC rHDMA5 (DMA Mode / Control):" + Integer.toHexString(getHDMAControl() & 0xFF));
			return getHDMAControl();
			// GBC IR port (R/W)
		case 0xFF56 :
			return net.getIR();
			// Color BG Palette Index (W)
		case 0xFF68 :
			return video.gbcGetBgpi();
			// Color BG Palette Data (W)
		case 0xFF69 :
			return video.gbcGetBgpd();
			// Color OBJ Palette Index (W)
		case 0xFF6A :
			return video.gbcGetObpi();
			// Color OBJ Palette Data (W)
		case 0xFF6B :
			return video.gbcGetObpd();
			//GBC RamBaml
		case 0xFF70:
			return gbcGetRamBank();
			//whats this?
		case 0xFF7F:
			return 0;
			// Interrupt Enable (R/W)
		case 0xFFFF:
				return IE;
	}
		// cart ROM
		if (address < 0x8000) {
			return cart.read(address);
		}
		// VRAM
		if (address < 0xA000) {
			return video.read(address);
		}
		// cart RAM
		if (address < 0xC000) {
			return cart.read(address);
		}
		// internal (low) RAM bank 0
		if (address < 0xD000) {
			return loRAM[address - 0xC000];
		}
		// internal (low) RAM bank 1+
		if (address < 0xE000) {
			return loRAM[address - loRAMOffset];
		}
		// echo RAM
		if (address < 0xFE00) {
			return loRAM[address - 0xE000];
		}
		// Object Attribute Memory (OAM)
		if (address < 0xFEA0) {
			return video.read(address);
		}
		
		// empty GB registers? //XXX bis FF80 IO register?
		if (address < 0xFF0F) {
			return 0;
		}
		// added by retroK sound:
		if (address < 0xFF40) {
			//some games look for this satus register, just set them correctly before returning value
			if ((address & 0xff) == 38) {
				if (soundChip.channel1.getLength() <= 0) soundIO[38] &= ~ 0x01; else soundIO[38] |= 0x01; 
				if (soundChip.channel2.getLength() <= 0) soundIO[38] &= ~ 0x02; else soundIO[38] |= 0x02;
				if (soundChip.channel3.getLength() <= 0) soundIO[38] &= ~ 0x04; else soundIO[38] |= 0x04;
				if (soundChip.channel4.getLength() <= 0) soundIO[38] &= ~ 0x08; else soundIO[38] |= 0x08;
			}
			return soundIO[address & 0xff];
		}

⌨️ 快捷键说明

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