diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/APU.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/APU.cs index 5d76dd9..e0a0488 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/APU.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/APU.cs @@ -15,7 +15,7 @@ namespace VirtualNes.Core protected int[] lowpass_filter = new int[4]; protected QUEUE queue; protected QUEUE exqueue; - protected bool[] m_bMute = new bool[16]; + protected bool[] m_bMute = new bool[16]; public APU(NES parent) { @@ -43,6 +43,11 @@ namespace VirtualNes.Core { @internal.Sync(cycles); } + + internal byte Read(ushort addr) + { + return @internal.SyncRead(addr); + } } public struct QUEUEDATA diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_INTERNAL.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_INTERNAL.cs index ca1a0f3..5315c25 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_INTERNAL.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_INTERNAL.cs @@ -1,11 +1,26 @@ +using System; + namespace VirtualNes.Core { public class APU_INTERNAL : APU_INTERFACE { private NES nes; + // Frame Counter private int FrameCycle; + private int FrameCount; + private int FrameType; + private byte FrameIRQ; private byte FrameIRQoccur; + // Channels + private RECTANGLE ch0 = new RECTANGLE(); + private RECTANGLE ch1 = new RECTANGLE(); + private TRIANGLE ch2 = new TRIANGLE(); + private NOISE ch3 = new NOISE(); + private DPCM ch4 = new DPCM(); + + + public void SetParent(NES parent) { nes = parent; @@ -55,5 +70,37 @@ namespace VirtualNes.Core { throw new System.NotImplementedException(); } + + internal byte SyncRead(ushort addr) + { + byte data = (byte)(addr >> 8); + + if (addr == 0x4015) + { + data = 0; + if ((ch0.sync_enable != 0) && ch0.sync_len_count > 0) data |= (1 << 0); + if ((ch1.sync_enable != 0) && ch1.sync_len_count > 0) data |= (1 << 1); + if ((ch2.sync_enable != 0) && ch2.sync_len_count > 0) data |= (1 << 2); + if ((ch3.sync_enable != 0) && ch3.sync_len_count > 0) data |= (1 << 3); + if ((ch4.sync_enable != 0) && (ch4.sync_dmalength != 0)) data |= (1 << 4); + if (FrameIRQoccur != 0) data |= (1 << 6); + if (ch4.sync_irq_enable != 0) data |= (1 << 7); + FrameIRQoccur = 0; + + nes.cpu.ClrIRQ(CPU.IRQ_FRAMEIRQ); + } + if (addr == 0x4017) + { + if (FrameIRQoccur != 0) + { + data = 0; + } + else + { + data |= (1 << 6); + } + } + return data; + } } } diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/DPCM.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/DPCM.cs new file mode 100644 index 0000000..1f48eb1 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/DPCM.cs @@ -0,0 +1,35 @@ +using Codice.CM.Client.Differences; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace VirtualNes.Core +{ + public class DPCM + { + public byte[] reg = new byte[4]; + public byte enable; + public byte looping; + public byte cur_byte; + public byte dpcm_value; + + public int freq; + public int phaseacc; + public int output; + + ushort address, cache_addr; + public int dmalength, cache_dmalength; + public int dpcm_output_real, dpcm_output_fake, dpcm_output_old, dpcm_output_offset; + + // For sync + public byte[] sync_reg = new byte[4]; + public byte sync_enable; + public byte sync_looping; + public byte sync_irq_gen; + public byte sync_irq_enable; + public int sync_cycles, sync_cache_cycles; + public int sync_dmalength, sync_cache_dmalength; + } +} diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/DPCM.cs.meta b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/DPCM.cs.meta new file mode 100644 index 0000000..08b468c --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/DPCM.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e6289a516ac91b541b2b1807bb07e2b0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/NOISE.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/NOISE.cs new file mode 100644 index 0000000..709483d --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/NOISE.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace VirtualNes.Core +{ + public class NOISE + { + public byte[] reg = new byte[4]; // register + + public byte enable; // enable + public byte holdnote; // holdnote + public byte volume; // volume + public byte xor_tap; + public int shift_reg; + + // For Render + public int phaseacc; + public int freq; + public int len_count; + + public int nowvolume; + public int output; + + // For Envelope + public byte env_fixed; + public byte env_decay; + public byte env_count; + public byte dummy0; + public int env_vol; + + // For sync; + public byte[] sync_reg = new byte[4]; + public byte sync_output_enable; + public byte sync_enable; + public byte sync_holdnote; + public byte dummy1; + public int sync_len_count; + } +} diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/NOISE.cs.meta b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/NOISE.cs.meta new file mode 100644 index 0000000..69ea5b5 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/NOISE.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8680ce7dbdceb504dbda3b98dbdb1297 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/RECTANGLE.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/RECTANGLE.cs new file mode 100644 index 0000000..69abd8f --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/RECTANGLE.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace VirtualNes.Core +{ + public class RECTANGLE + { + public byte[] reg = new byte[4]; // register + + public byte enable; // enable + public byte holdnote; // holdnote + public byte volume; // volume + public byte complement; + + // For Render + public int phaseacc; + public int freq; + public int freqlimit; + public int adder; + public int duty; + public int len_count; + + public int nowvolume; + + // For Envelope + public byte env_fixed; + public byte env_decay; + public byte env_count; + public byte dummy0; + public int env_vol; + + // For Sweep + public byte swp_on; + public byte swp_inc; + public byte swp_shift; + public byte swp_decay; + public byte swp_count; + public byte[] dummy1 = new byte[3]; + + // For sync; + public byte[] sync_reg = new byte[4]; + public byte sync_output_enable; + public byte sync_enable; + public byte sync_holdnote; + public byte dummy2; + public int sync_len_count; + } +} diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/RECTANGLE.cs.meta b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/RECTANGLE.cs.meta new file mode 100644 index 0000000..9cbc24b --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/RECTANGLE.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6e50831f6c445fe489d7e1737269296e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/TRIANGLE.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/TRIANGLE.cs new file mode 100644 index 0000000..80f4c4a --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/TRIANGLE.cs @@ -0,0 +1,29 @@ +namespace VirtualNes.Core +{ + public class TRIANGLE + { + public byte[] reg = new byte[4]; + + public byte enable; + public byte holdnote; + public byte counter_start; + public byte dummy0; + + public int phaseacc; + public int freq; + public int len_count; + public int lin_count; + public int adder; + + public int nowvolume; + + // For sync; + public byte[] sync_reg = new byte[4]; + public byte sync_enable; + public byte sync_holdnote; + public byte sync_counter_start; + // public byte dummy1; + public int sync_len_count; + public int sync_lin_count; + } +} diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/TRIANGLE.cs.meta b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/TRIANGLE.cs.meta new file mode 100644 index 0000000..4cfe6b6 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/TRIANGLE.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4ed2788da33fe474facc1d7ce1b34d03 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CPU.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CPU.cs index ea35cfc..833748e 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CPU.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CPU.cs @@ -135,6 +135,13 @@ namespace VirtualNes.Core case 0x75: MR_ZX(ref DT, ref EA, ref R); ADC(ref WT, ref DT, ref R); ADD_CYCLE(4, ref exec_cycles); + break; + case 0x6D: + MR_AB(ref EA, ref DT, ref R);ADC(ref WT, ref DT, ref R); + ADD_CYCLE(4, ref exec_cycles); + break; + case 0x7D: + break; } } @@ -157,26 +164,51 @@ namespace VirtualNes.Core return MMU.CPU_MEM_BANK[addr >> 13][addr & 0x1FFF]; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal ushort OP6502W(ushort addr) + { + var bytePage = MMU.CPU_MEM_BANK[addr >> 13]; + + return BitConverter.ToUInt16(bytePage, addr & 0x1FFF); + } + + internal byte RD6502(ushort addr) + { + if (addr < 0x2000) + { + // RAM (Mirror $0800, $1000, $1800) + return MMU.RAM[addr & 0x07FF]; + } + else if (addr < 0x8000) + { + // Others + return nes.Read(addr); + } + else + { + // Dummy access + mapper.Read(addr, MMU.CPU_MEM_BANK[addr >> 13][addr & 0x1FFF]); + } + + // Quick bank read + return MMU.CPU_MEM_BANK[addr >> 13][addr & 0x1FFF]; + } + private void MR_IM(ref byte DT, ref R6502 R) { DT = OP6502(R.PC++); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] private void MR_ZP(ref ushort EA, ref byte DT, ref R6502 R) { EA = OP6502(R.PC++); DT = ZPRD(ref EA); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] private byte ZPRD(ref ushort A) { return MMU.RAM[A]; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] private void ADC(ref ushort WT, ref byte DT, ref R6502 R) { WT = (ushort)(R.A + DT + (R.P & C_FLAG)); @@ -187,7 +219,6 @@ namespace VirtualNes.Core SET_ZN_FLAG(R.A, ref R); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] private void TST_FLAG(bool F, byte V, ref R6502 R) { byte temp = (byte)~V; @@ -196,7 +227,6 @@ namespace VirtualNes.Core if (F) R.P |= V; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] private void SET_ZN_FLAG(byte A, ref R6502 R) { byte temp = unchecked((byte)(~(Z_FLAG | N_FLAG))); @@ -204,19 +234,30 @@ namespace VirtualNes.Core R.P |= ZN_Table[A]; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] private void ADD_CYCLE(int V, ref int exec_cycles) { exec_cycles += V; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] private void MR_ZX(ref byte DT, ref ushort EA, ref R6502 R) { DT = OP6502(R.PC++); EA = (ushort)(DT + R.X); DT = ZPRD(ref EA); } + + private void MR_AB(ref ushort EA, ref byte DT, ref R6502 R) + { + EA = OP6502W(R.PC); + R.PC += 2; + DT = RD6502(EA); + } + + internal void ClrIRQ(byte mask) + { + byte temp = (byte)~mask; + R.Int_Pending &= temp; + } } public enum StatusFlag6502 : int diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/MMU.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/MMU.cs index e4dab0e..fad8a8f 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/MMU.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/MMU.cs @@ -1,4 +1,5 @@ -using System; +using Codice.CM.Client.Differences; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -11,8 +12,34 @@ namespace VirtualNes // CPU 儊儌儕僶儞僋 public static byte[][] CPU_MEM_BANK = new byte[8][]; // 8K扨埵 + // PPU 儊儌儕僶儞僋 + public static byte[][] PPU_MEM_BANK = new byte[12][]; // 1K扨埵 + public static byte[] PPU_MEM_TYPE = new byte[12]; + public static int[] PPU_MEM_PAGE = new int[12]; // 僗僥乕僩僙乕僽梡 + public static byte[] CRAM_USED = new byte[16]; // 僗僥乕僩僙乕僽梡 + // NES儊儌儕 public static byte[] RAM = new byte[8 * 1024]; // NES撪憻RAM public static byte[] WARM = new byte[128 * 1024]; // 儚乕僋/僶僢僋傾僢僾RAM + public static byte[] DRAM = new byte[40 * 1024]; // 僨傿僗僋僔僗僥儉RAM + public static byte[] XRAM = new byte[8 * 1024]; // 僟儈乕僶儞僋 + public static byte[] ERAM = new byte[32 * 1024]; // 奼挘婡婍梡RAM + + public static byte[] CRAM = new byte[32 * 1024]; // 僉儍儔僋僞僷僞乕儞RAM + public static byte[] VRAM = new byte[4 * 1024]; // 僱乕儉僥乕僽儖/傾僩儕價儏乕僩RAM + + public static byte[] SPRAM = new byte[0x100]; // 僗僾儔僀僩RAM + public static byte[] BGPAL = new byte[0x10]; // BG僷儗僢僩 + public static byte[] SPPAL = new byte[0x10]; // SP僷儗僢僩 + // 儗僕僗僞 + public static byte[] CPUREG = new byte[0x18]; // Nes $4000-$4017 + public static byte[] PPUREG = new byte[0x04]; // Nes $2000-$2003 + + // PPU撪晹儗僕僗僞 + public static byte PPU56Toggle; // $2005-$2006 Toggle + public static byte PPU7_Temp; // $2007 read buffer + public static ushort loopy_t; // same as $2005/$2006 + public static ushort loopy_v; // same as $2005/$2006 + public static ushort loopy_x; // tile x offset } } diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper.cs index c190f75..132b313 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper.cs @@ -1,4 +1,5 @@ -using System; +using Codice.CM.Client.Differences; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -8,6 +9,85 @@ namespace VirtualNes.Core { public abstract class Mapper { - internal virtual void Clock(int cycles) { } + protected NES nes; + public Mapper(NES parent) + { + nes = parent; + } + + public virtual void Dispose() { } + + public abstract void Reset(); + + // $8000-$FFFF Memory write + public virtual void Write(ushort addr, byte data) { } + // $8000-$FFFF Memory read(Dummy) + public virtual void Read(ushort addr, byte data) { } + + // $4100-$7FFF Lower Memory read/write + public virtual byte ReadLow(ushort addr) + { + // $6000-$7FFF WRAM + if (addr >= 0x6000 && addr <= 0x7FFF) + { + return MMU.CPU_MEM_BANK[addr >> 13][addr & 0x1FFF]; + } + + return (byte)(addr >> 8); + } + public virtual void WriteLow(ushort addr, byte data) + { + if (addr >= 0x6000 && addr <= 0x7FFF) + { + MMU.CPU_MEM_BANK[addr >> 13][addr & 0x1FFF] = data; + } + } + + // $4018-$40FF Extention register read/write + public virtual byte ExRead(ushort addr) { return 0x00; } + public virtual void ExWrite(ushort addr, byte data) { } + + public virtual byte ExCmdRead(EXCMDRD cmd) { return 0x00; } + public virtual void ExCmdWrite(EXCMDWR cmd, byte data) { } + + // H sync/V sync/Clock sync + public virtual void HSync(int scanline) { } + public virtual void VSync() { } + public virtual void Clock(int cycles) { } + // PPU address bus latch + public virtual void PPU_Latch(ushort addr) { } + // PPU Character latch + public virtual void PPU_ChrLatch(ushort addr) { } + // PPU Extension character/palette + public virtual void PPU_ExtLatchX(int x) { } + public virtual void PPU_ExtLatch(ushort addr, ref byte chr_l, ref byte chr_h, ref byte attr) { } + // For State save + public virtual bool IsStateSave() { return false; } + public virtual void SaveState(byte[] p) { } + public virtual void LoadState(byte[] p) { } + + // Extension commands + // For ExCmdRead command + public enum EXCMDRD + { + EXCMDRD_NONE = 0, + EXCMDRD_DISKACCESS, + } + // For ExCmdWrite command + public enum EXCMDWR + { + EXCMDWR_NONE = 0, + EXCMDWR_DISKINSERT, + EXCMDWR_DISKEJECT, + } + + public static Mapper CreateMapper(NES parent, int no) + { + switch (no) + { + default: + throw new NotImplementedException($"Mapper#{no} is not Impl"); + } + } } } diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/NES.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/NES.cs index 9f59b77..9e569ab 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/NES.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/NES.cs @@ -358,6 +358,135 @@ namespace VirtualNes.Core { //todo : ʵTape (ĿǼ¼ҲPlay,ȼܵ) } + + internal byte Read(ushort addr) + { + switch (addr >> 13) + { + case 0x00: // $0000-$1FFF + return MMU.RAM[addr & 0x07FF]; + case 0x01: // $2000-$3FFF + return ppu.Read((ushort)(addr & 0xE007)); + case 0x02: // $4000-$5FFF + if (addr < 0x4100) + { + return ReadReg(addr); + } + else + { + return mapper.ReadLow(addr); + } + case 0x03: // $6000-$7FFF + return mapper.ReadLow(addr); + case 0x04: // $8000-$9FFF + case 0x05: // $A000-$BFFF + case 0x06: // $C000-$DFFF + case 0x07: // $E000-$FFFF + return MMU.CPU_MEM_BANK[addr >> 13][addr & 0x1FFF]; + } + + return 0x00; // Warning\h + } + + private byte ReadReg(ushort addr) + { + switch (addr & 0xFF) + { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + return apu.Read(addr); + case 0x15: + return apu.Read(addr); + case 0x14: + return (byte)(addr & 0xFF); + case 0x16: + if (rom.IsVSUNISYSTEM()) + { + return pad.Read(addr); + } + else + { + return (byte)(pad.Read(addr) | 0x40 | m_TapeOut); + } + case 0x17: + if (rom.IsVSUNISYSTEM()) + { + return pad.Read(addr); + } + else + { + return (byte)(pad.Read(addr) | apu.Read(addr)); + } + default: + return mapper.ExRead(addr); + } + } + + internal byte Barcode2() + { + byte ret = 0x00; + + if (!m_bBarcode2 || m_Barcode2seq < 0) + return ret; + + switch (m_Barcode2seq) + { + case 0: + m_Barcode2seq++; + m_Barcode2ptr = 0; + ret = 0x04; // d3 + break; + + case 1: + m_Barcode2seq++; + m_Barcode2bit = m_Barcode2data[m_Barcode2ptr]; + m_Barcode2cnt = 0; + ret = 0x04; // d3 + break; + + case 2: + ret = (byte)((m_Barcode2bit & 0x01) != 0 ? 0x00 : 0x04); // Bit rev. + m_Barcode2bit >>= 1; + if (++m_Barcode2cnt > 7) + { + m_Barcode2seq++; + } + break; + case 3: + if (++m_Barcode2ptr > 19) + { + m_bBarcode2 = false; + m_Barcode2seq = -1; + } + else + { + m_Barcode2seq = 1; + } + break; + default: + break; + } + + return ret; + } } } diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/PAD.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/PAD.cs index 0758a47..7dba9d2 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/PAD.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/PAD.cs @@ -4,18 +4,21 @@ namespace VirtualNes.Core { public class PAD { - protected NES nes; - protected int excontroller_select; - protected EXPAD expad; - protected bool bStrobe; - protected bool bSwapButton; - protected bool bSwapPlayer; - protected bool bZapperMode; - protected VSType nVSSwapType; - protected byte[] padbit = new byte[4]; - protected byte micbit; - protected byte[] padbitsync = new byte[4]; - protected byte micbitsync; + private NES nes; + private int excontroller_select; + private EXPAD expad; + private bool bStrobe; + private bool bSwapButton; + private bool bSwapPlayer; + private bool bZapperMode; + private VSType nVSSwapType; + private byte[] padbit = new byte[4]; + private byte micbit; + private byte[] padbitsync = new byte[4]; + private byte micbitsync; + private bool bBarcodeWorld; + + public uint pad1bit, pad2bit, pad3bit, pad4bit; public PAD(NES parent) { @@ -35,9 +38,47 @@ namespace VirtualNes.Core micbitsync = 0; } - public void Dispose() + internal byte Read(ushort addr) { + byte data = 0x00; + + if (addr == 0x4016) + { + data = (byte)(pad1bit & 1); + pad1bit >>= 1; + data |= (byte)(((pad3bit & 1)) << 1); + pad3bit >>= 1; + // Mic + if (!nes.rom.IsVSUNISYSTEM()) + { + data |= micbitsync; + } + if (expad != null) + { + data |= expad.Read4016(); + } + } + if (addr == 0x4017) + { + data = (byte)(pad2bit & 1); + pad2bit >>= 1; + data |= (byte)((pad4bit & 1) << 1); + pad4bit >>= 1; + + if (expad != null) + { + data |= expad.Read4017(); + } + + if (bBarcodeWorld) + { + data |= nes.Barcode2(); + } + } + + return data; } + public void Dispose() { } } public enum VSType diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/PPU.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/PPU.cs index 0e35183..0d5aea4 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/PPU.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/PPU.cs @@ -1,9 +1,39 @@ -using System; +using Codice.CM.Client.Differences; +using System; namespace VirtualNes.Core { public class PPU { + // PPU Control Register #1 PPU #0 + public const byte PPU_VBLANK_BIT = 0x80; + public const byte PPU_SPHIT_BIT = 0x40; // 堘偆丠 + public const byte PPU_SP16_BIT = 0x20; + public const byte PPU_BGTBL_BIT = 0x10; + public const byte PPU_SPTBL_BIT = 0x08; + public const byte PPU_INC32_BIT = 0x04; + public const byte PPU_NAMETBL_BIT = 0x03; + + // PPU Control Register #2 PPU #1 + public const byte PPU_BGCOLOR_BIT = 0xE0; + public const byte PPU_SPDISP_BIT = 0x10; + public const byte PPU_BGDISP_BIT = 0x08; + public const byte PPU_SPCLIP_BIT = 0x04; + public const byte PPU_BGCLIP_BIT = 0x02; + public const byte PPU_COLORMODE_BIT = 0x01; + + // PPU Status Register PPU #2 + public const byte PPU_VBLANK_FLAG = 0x80; + public const byte PPU_SPHIT_FLAG = 0x40; + public const byte PPU_SPMAX_FLAG = 0x20; + public const byte PPU_WENABLE_FLAG = 0x10; + + // SPRITE Attribute + public const byte SP_VMIRROR_BIT = 0x80; + public const byte SP_HMIRROR_BIT = 0x40; + public const byte SP_PRIORITY_BIT = 0x20; + public const byte SP_COLOR_BIT = 0x03; + private NES m_nes; private byte[] lpScreen; private byte[] lpColormode; @@ -42,6 +72,59 @@ namespace VirtualNes.Core { } + internal byte Read(ushort addr) + { + byte data = 0x00; + + switch (addr) + { + // Write only Register + case 0x2000: // PPU Control Register #1(W) + case 0x2001: // PPU Control Register #2(W) + case 0x2003: // SPR-RAM Address Register(W) + case 0x2005: // PPU Scroll Register(W2) + case 0x2006: // VRAM Address Register(W2) + data = MMU.PPU7_Temp; // 懡暘 + break; + // Read/Write Register + case 0x2002: // PPU Status Register(R) + //DEBUGOUT( "2002 RD L:%3d C:%8d\n", ScanlineNo, nes->cpu->GetTotalCycles() ); + data = (byte)(MMU.PPUREG[2] | VSSecurityData); + MMU.PPU56Toggle = 0; + byte temp = unchecked((byte)~PPU_VBLANK_FLAG); + MMU.PPUREG[2] &= temp; + break; + case 0x2004: // SPR_RAM I/O Register(RW) + data = MMU.SPRAM[MMU.PPUREG[3]++]; + break; + case 0x2007: // VRAM I/O Register(RW) + addr = (ushort)(MMU.loopy_v & 0x3FFF); + data = MMU.PPU7_Temp; + if ((MMU.PPUREG[0] & PPU_INC32_BIT) != 0) MMU.loopy_v += 32; + else MMU.loopy_v++; + if (addr >= 0x3000) + { + if (addr >= 0x3F00) + { + // data &= 0x3F; + if ((addr & 0x0010) == 0) + { + return MMU.BGPAL[addr & 0x000F]; + } + else + { + return MMU.SPPAL[addr & 0x000F]; + } + } + addr &= 0xEFFF; + } + MMU.PPU7_Temp = MMU.PPU_MEM_BANK[addr >> 10][addr & 0x03FF]; + break; + } + + return data; + } + internal void SetRenderScanline(int scanline) { ScanlineNo = scanline; diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/PadEX/EXPAD.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/PadEX/EXPAD.cs index 38e7a47..56e5f6f 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/PadEX/EXPAD.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/PadEX/EXPAD.cs @@ -1,3 +1,4 @@ +using System; using System.Collections; using System.Collections.Generic; using UnityEngine; @@ -6,5 +7,23 @@ namespace VirtualNes.Core { public class EXPAD { + protected NES nes; + + public EXPAD(NES parent) + { + nes = parent; + } + + public virtual void Dispose() { } + + public virtual void Reset() { } + public virtual void Strobe() { } + public virtual byte Read4016() { return 0x00; } + public virtual byte Read4017() { return 0x00; } + public virtual void Write4016(byte data) { } + public virtual void Write4017(byte data) { } + public virtual void Sync() { } + public virtual void SetSyncData(int type,int data) { } + public virtual int GetSyncData(int type) { return 0x00; } } } diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ROM.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ROM.cs index 8e910f0..46e12ff 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ROM.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ROM.cs @@ -350,6 +350,11 @@ namespace VirtualNes.Core { return fdsmakerID; } + + internal bool IsVSUNISYSTEM() + { + return (header.control2 & (byte)EnumRomControlByte2.ROM_VSUNISYSTEM) != 0; + } }