diff --git a/BizHawk.Emulation/Consoles/Sega/Genesis/GenVDP.DMA.cs b/BizHawk.Emulation/Consoles/Sega/Genesis/GenVDP.DMA.cs index 0ed0f4f0fc..546f629189 100644 --- a/BizHawk.Emulation/Consoles/Sega/Genesis/GenVDP.DMA.cs +++ b/BizHawk.Emulation/Consoles/Sega/Genesis/GenVDP.DMA.cs @@ -8,6 +8,7 @@ namespace BizHawk.Emulation.Consoles.Sega public Func DmaReadFrom68000; // TODO make ushort public int DmaLength { get { return Registers[19] | (Registers[20] << 8); } } + public int DmaMode { get { return (Registers[23] >> 6) & 3; } } public int DmaSource { @@ -21,28 +22,26 @@ namespace BizHawk.Emulation.Consoles.Sega } } - bool DmaFillModePending; void ExecuteDmaFill(ushort data) { - Console.WriteLine("DMA FILL REQD, WRITE {0:X4}, {1:X4} times, at {2:X4}", data, DmaLength, VdpDataAddr); + Log.Note("VDP","DMA FILL REQD, WRITE {0:X4}, {1:X4} times, at {2:X4}", data, DmaLength, VdpDataAddr); - // TODO: Is the address really VdpDataAddr and not DMA source? I guess that makes sense. // TODO: It should spread this out, not do it all at once. - // TODO: DMA can go to places besides just VRAM (eg CRAM, VSRAM) - // TODO: Does DMA fill really use the actual increment register value? + // TODO: DMA can go to places besides just VRAM (eg CRAM, VSRAM) ??? can it? + // TODO: what is this genvdp.txt comment about accurate vdp fill emulation writing some other byte first? int length = DmaLength; if (length == 0) - length = 0x10000; // Really necessary? + length = 0x10000; byte fillByte = (byte)(data >> 8); do { - VRAM[VdpDataAddr & 0xFFFF] = fillByte; - UpdatePatternBuffer(VdpDataAddr & 0xFFFF); + VRAM[VdpDataAddr] = fillByte; + UpdatePatternBuffer(VdpDataAddr); VdpDataAddr += Registers[15]; } while (--length > 0); @@ -51,7 +50,7 @@ namespace BizHawk.Emulation.Consoles.Sega void Execute68000VramCopy() { - Console.WriteLine("DMA 68000 -> VRAM COPY REQ'D. LENGTH {0:X4}, SOURCE {1:X4}", DmaLength, DmaSource); + Log.Note("VDP", "DMA 68000 -> VRAM COPY REQ'D. LENGTH {0:X4}, SOURCE {1:X4}", DmaLength, DmaSource); int length = DmaLength; if (length == 0) diff --git a/BizHawk.Emulation/Consoles/Sega/Genesis/GenVDP.Render.cs b/BizHawk.Emulation/Consoles/Sega/Genesis/GenVDP.Render.cs index bd150e6cf8..c160b84260 100644 --- a/BizHawk.Emulation/Consoles/Sega/Genesis/GenVDP.Render.cs +++ b/BizHawk.Emulation/Consoles/Sega/Genesis/GenVDP.Render.cs @@ -8,15 +8,14 @@ namespace BizHawk.Emulation.Consoles.Sega { if (ScanLine == 0) { - for (int i = 0; i < FrameBuffer.Length; i++) - FrameBuffer[i] = 0; + Array.Clear(FrameBuffer, 0, FrameBuffer.Length); //RenderPatterns(); RenderPalette(); RenderScrollA(); RenderScrollB(); - RenderSprites(); } + RenderSprites(); } void RenderPalette() @@ -76,33 +75,68 @@ namespace BizHawk.Emulation.Consoles.Sega } } + static readonly int[] SpriteSizeTable = { 8, 16, 24, 32 }; + Sprite sprite; void RenderSprites() { - Sprite sprite = FetchSprite(0); - /*if (sprite.X > 0) - Console.WriteLine("doot");*/ + int scanLineBase = ScanLine * FrameWidth; + int processedSprites = 0; + + FetchSprite(0); + while (true) + { + if (sprite.Y > ScanLine || sprite.Y+sprite.HeightPixels <= ScanLine) + goto nextSprite; + if (sprite.X + sprite.WidthPixels <= 0) + goto nextSprite; + + if (sprite.HeightCells == 2) + sprite.HeightCells = 2; + + int yline = ScanLine - sprite.Y; + int paletteBase = sprite.Palette * 16; + int pattern = sprite.PatternIndex + ((yline / 8)); + int x = sprite.X; + + for (int xi = 0; xi < sprite.WidthPixels; xi++) + { + if (sprite.X + xi < 0 || sprite.X + xi > FrameWidth) + continue; + + int pixel = PatternBuffer[((pattern+((xi/8)*sprite.HeightCells)) * 64) + ((yline & 7) * 8) + (xi & 7)]; + if (pixel != 0) + FrameBuffer[scanLineBase + sprite.X + xi] = Palette[paletteBase + pixel]; + } + + nextSprite: + if (sprite.Link == 0) + break; + if (++processedSprites > 80) + break; + FetchSprite(sprite.Link); + } } - Sprite FetchSprite(int spriteNo) + void FetchSprite(int spriteNo) { int satbase = SpriteAttributeTableAddr + (spriteNo*8); - Sprite sprite = new Sprite(); - sprite.Y = (VRAM[satbase + 1] | (VRAM[satbase + 0] << 8) & 0x3FF) - 128; - sprite.X = (VRAM[satbase + 7] | (VRAM[satbase + 6] << 8) & 0x3FF) - 128; - sprite.Width = ((VRAM[satbase + 2] >> 2) & 3) + 1; - sprite.Height = (VRAM[satbase + 2] & 3) + 1; - sprite.Link = VRAM[satbase + 3] & 0x7F; - sprite.PatternIndex = VRAM[satbase + 5] | (VRAM[satbase + 6] << 8) & 0x7FF; + sprite.Y = (VRAM[satbase + 0] | (VRAM[satbase + 1] << 8) & 0x3FF) - 128; + sprite.X = (VRAM[satbase + 6] | (VRAM[satbase + 7] << 8) & 0x3FF) - 128; + sprite.WidthPixels = SpriteSizeTable[(VRAM[satbase + 3] >> 2) & 3]; + sprite.HeightPixels = SpriteSizeTable[VRAM[satbase + 3] & 3]; + sprite.WidthCells = ((VRAM[satbase + 3] >> 2) & 3) + 1; + sprite.HeightCells = (VRAM[satbase + 3] & 3) + 1; + sprite.Link = VRAM[satbase + 2] & 0x7F; + sprite.PatternIndex = (VRAM[satbase + 4] | (VRAM[satbase + 5] << 8)) & 0x7FF; sprite.Palette = (VRAM[satbase + 5] >> 5) & 3; - return sprite; } - struct Sprite { public int X, Y; - public int Width, Height; + public int WidthPixels, HeightPixels; + public int WidthCells, HeightCells; public int Link; public int Palette; public int PatternIndex; diff --git a/BizHawk.Emulation/Consoles/Sega/Genesis/GenVDP.cs b/BizHawk.Emulation/Consoles/Sega/Genesis/GenVDP.cs index c03d733b57..04f30d7f54 100644 --- a/BizHawk.Emulation/Consoles/Sega/Genesis/GenVDP.cs +++ b/BizHawk.Emulation/Consoles/Sega/Genesis/GenVDP.cs @@ -24,23 +24,23 @@ namespace BizHawk.Emulation.Consoles.Sega public bool CellBasedVertScroll { get { return (Registers[11] & 0x08) != 0; } } public bool Display40Mode { get { return (Registers[12] & 0x81) != 0; } } - private ushort NameTableAddrA; - private ushort NameTableAddrB; - private ushort NameTableAddrWindow; - private ushort SpriteAttributeTableAddr; - private ushort HScrollTableAddr; - private byte NameTableWidth; - private byte NameTableHeight; + ushort NameTableAddrA; + ushort NameTableAddrB; + ushort NameTableAddrWindow; + ushort SpriteAttributeTableAddr; + ushort HScrollTableAddr; + byte NameTableWidth; + byte NameTableHeight; - private bool ControlWordPending; - private ushort VdpDataAddr; - private byte VdpDataCode; + bool ControlWordPending; + ushort VdpDataAddr; + byte VdpDataCode; - private static readonly byte[] PalXlatTable = { 0, 0, 36, 36, 73, 73, 109, 109, 145, 145, 182, 182, 219, 219, 255, 255 }; + static readonly byte[] PalXlatTable = { 0, 0, 36, 36, 73, 73, 109, 109, 145, 145, 182, 182, 219, 219, 255, 255 }; public void WriteVdpControl(ushort data) { - //Console.WriteLine("[PC = {0:X6}] VDP: Control Write {1:X4}", /*Genesis._MainCPU.PC*/0, data); + Log.Note("VDP", "VDP: Control Write {0:X4}", data); if (ControlWordPending == false) { @@ -77,28 +77,28 @@ namespace BizHawk.Emulation.Consoles.Sega // what type of DMA? switch (Registers[23] >> 6) { - case 2: - Console.WriteLine("VRAM FILL"); + case 2: + Log.Note("VDP", "VRAM FILL"); DmaFillModePending = true; break; - case 3: - Console.WriteLine("VRAM COPY **** UNIMPLEMENTED ***"); + case 3: + Log.Note("VDP", "VRAM COPY **** UNIMPLEMENTED ***"); break; default: - Console.WriteLine("68k->VRAM COPY **** UNIMPLEMENTED ***"); + Log.Note("VDP", "68k->VRAM COPY"); Execute68000VramCopy(); break; } - Console.WriteLine("DMA LEN = "+DmaLength); + Log.Note("VDP", "DMA LEN = " + DmaLength); } } } public ushort ReadVdpControl() { - //Console.WriteLine("VDP: Control Read"); ushort value = 0x3400; // fixed bits per genvdp.txt TODO test on everdrive, I guess. value |= 0x0200; // Fifo empty + Log.Note("VDP", "VDP: Control Read {0:X4}", value); return value; } @@ -144,40 +144,67 @@ namespace BizHawk.Emulation.Consoles.Sega public ushort ReadVdpData() { - //Console.WriteLine("VDP: Data Read"); + Console.WriteLine("VDP: Data Read"); return 0; } public void WriteVdpRegister(int register, byte data) { - //Console.WriteLine("Register {0}: {1:X2}", register, data); + Log.Note("VDP", "Register {0}: {1:X2}", register, data); switch (register) { - case 0x00: + case 0x00: // Mode Set Register 1 Registers[register] = data; - Console.WriteLine("HINT enabled: "+ HInterruptsEnabled); + //Log.Note("VDP", "HINT enabled: " + HInterruptsEnabled); break; - case 0x01: + + case 0x01: // Mode Set Register 2 Registers[register] = data; - Console.WriteLine("DmaEnabled: "+DmaEnabled); - Console.WriteLine("VINT enabled: " + VInterruptEnabled); + //Log.Note("VDP", "DisplayEnabled: " + DisplayEnabled); + //Log.Note("VDP", "DmaEnabled: " + DmaEnabled); + //Log.Note("VDP", "VINT enabled: " + VInterruptEnabled); break; + case 0x02: // Name Table Address for Layer A NameTableAddrA = (ushort) ((data & 0x38) << 10); - Console.WriteLine("SET NTa A = {0:X4}",NameTableAddrA); + //Log.Note("VDP", "SET NTa A = {0:X4}", NameTableAddrA); break; + case 0x03: // Name Table Address for Window NameTableAddrWindow = (ushort) ((data & 0x3E) << 10); - Console.WriteLine("SET NTa W = {0:X4}", NameTableAddrWindow); + //Log.Note("VDP", "SET NTa W = {0:X4}", NameTableAddrWindow); break; + case 0x04: // Name Table Address for Layer B NameTableAddrB = (ushort) (data << 13); - Console.WriteLine("SET NTa B = {0:X4}", NameTableAddrB); + //Log.Note("VDP", "SET NTa B = {0:X4}", NameTableAddrB); break; + case 0x05: // Sprite Attribute Table Address SpriteAttributeTableAddr = (ushort) (data << 9); - Console.WriteLine("SET SAT attr = {0:X4}", SpriteAttributeTableAddr); + //Log.Note("VDP", "SET SAT attr = {0:X4}", SpriteAttributeTableAddr); break; + + case 0x0A: // H Interrupt Register + //Log.Note("VDP", "HInt occurs every {0} lines.", data); + break; + + case 0x0B: // VScroll/HScroll modes + /*if ((data & 4) != 0) + Log.Note("VDP", "VSCroll Every 2 Cells Enabled"); + else + Log.Note("VDP", "Full Screen VScroll");*/ + + int hscrollmode = data & 3; + switch (hscrollmode) + { + //case 0: Log.Note("VDP", "Full Screen HScroll"); break; + //case 1: Log.Note("VDP", "Prohibited HSCROLL mode!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); break; + //case 2: Log.Note("VDP", "HScroll every 1 cell"); break; + //case 3: Log.Note("VDP", "HScroll every 2 cell"); break; + } + break; + case 0x0C: // Mode Set #4 // TODO interlaced modes if ((data & 0x81) == 0) @@ -187,7 +214,7 @@ namespace BizHawk.Emulation.Consoles.Sega { FrameBuffer = new int[256*224]; FrameWidth = 256; - Console.WriteLine("SWITCH TO 32 CELL WIDE MODE"); + //Log.Note("VDP", "SWITCH TO 32 CELL WIDE MODE"); } } else { // Display is 40 cells wide @@ -195,18 +222,21 @@ namespace BizHawk.Emulation.Consoles.Sega { FrameBuffer = new int[320*224]; FrameWidth = 320; - Console.WriteLine("SWITCH TO 40 CELL WIDE MODE"); + //Log.Note("VDP", "SWITCH TO 40 CELL WIDE MODE"); } } break; + case 0x0D: // H Scroll Table Address HScrollTableAddr = (ushort) (data << 10); - Console.WriteLine("SET HScrollTab attr = {0:X4}", HScrollTableAddr); + //Log.Note("VDP", "SET HScrollTab attr = {0:X4}", HScrollTableAddr); break; - case 0x0F: - Console.WriteLine("Set Data Increment to "+data); + + case 0x0F: // Auto Address Register Increment + //Log.Note("VDP", "Set Data Increment to " + data); break; - case 0x10: + + case 0x10: // Nametable Dimensions switch (data & 0x03) { case 0: NameTableWidth = 32; break; @@ -221,13 +251,49 @@ namespace BizHawk.Emulation.Consoles.Sega case 2: NameTableHeight = 32; break; // invalid setting case 3: NameTableHeight = 128; break; } - Console.WriteLine("Name Table Dimensions set to {0}x{1}", NameTableWidth, NameTableHeight); + //Log.Note("VDP", "Name Table Dimensions set to {0}x{1}", NameTableWidth, NameTableHeight); break; + + case 0x11: // Window H Position + int whp = data & 31; + bool fromright = (data & 0x80) != 0; + //Log.Note("VDP", "Window H is {0} units from {1}", whp, fromright ? "right" : "left"); + break; + + case 0x12: // Window V + whp = data & 31; + fromright = (data & 0x80) != 0; + //Log.Note("VDP", "Window V is {0} units from {1}", whp, fromright ? "lower" : "upper"); + break; + + case 0x13: // DMA Length Low + Registers[register] = data; + //Log.Note("VDP", "DMA Length = {0:X4}", DmaLength); + break; + + case 0x14: // DMA Length High + Registers[register] = data; + //Log.Note("VDP", "DMA Length = {0:X4}", DmaLength); + break; + + case 0x15: // DMA Source Low + Registers[register] = data; + //Log.Note("VDP", "DMA Source = {0:X6}", DmaSource); + break; + case 0x16: // DMA Source Mid + Registers[register] = data; + //Log.Note("VDP", "DMA Source = {0:X6}", DmaSource); + break; + case 0x17: // DMA Source High + Registers[register] = data; + //Log.Note("VDP", "DMA Source = {0:X6}", DmaSource); + break; + } Registers[register] = data; } - private void ProcessPalette(int slot) + void ProcessPalette(int slot) { byte r = PalXlatTable[(CRAM[slot] & 0x000F) >> 0]; byte g = PalXlatTable[(CRAM[slot] & 0x00F0) >> 4]; @@ -235,7 +301,7 @@ namespace BizHawk.Emulation.Consoles.Sega Palette[slot] = Colors.ARGB(r, g, b); } - private void UpdatePatternBuffer(int addr) + void UpdatePatternBuffer(int addr) { PatternBuffer[(addr*2) + 1] = (byte) (VRAM[addr^1] & 0x0F); PatternBuffer[(addr*2) + 0] = (byte) (VRAM[addr^1] >> 4); diff --git a/BizHawk.Emulation/Consoles/Sega/Genesis/Genesis.cs b/BizHawk.Emulation/Consoles/Sega/Genesis/Genesis.cs index c083ce18fa..a1ef204cc0 100644 --- a/BizHawk.Emulation/Consoles/Sega/Genesis/Genesis.cs +++ b/BizHawk.Emulation/Consoles/Sega/Genesis/Genesis.cs @@ -82,6 +82,7 @@ namespace BizHawk.Emulation.Consoles.Sega for (int i = 0; i < rom.Length; i++) RomData[i] = rom[i]; + SetupMemoryDomains(); MainCPU.Reset(); } @@ -91,7 +92,7 @@ namespace BizHawk.Emulation.Consoles.Sega PSG.BeginFrame(SoundCPU.TotalExecutedCycles); for (VDP.ScanLine = 0; VDP.ScanLine < 262; VDP.ScanLine++) { - Log.Error("VDP","FRAME {0}, SCANLINE {1}", Frame, VDP.ScanLine); + //Log.Error("VDP","FRAME {0}, SCANLINE {1}", Frame, VDP.ScanLine); if (VDP.ScanLine < 224) VDP.RenderLine(); @@ -179,8 +180,30 @@ namespace BizHawk.Emulation.Consoles.Sega return new byte[0]; } - public IList MemoryDomains { get { throw new NotImplementedException(); } } - public MemoryDomain MainMemory { get { throw new NotImplementedException(); } } + IList memoryDomains; + + void SetupMemoryDomains() + { + var domains = new List(3); + var MainMemoryDomain = new MemoryDomain("68000 RAM", Ram.Length, Endian.Big, + addr => Ram[addr & 0xFFFF], + (addr, value) => Ram[addr & 0xFFFF] = value); + var Z80Domain = new MemoryDomain("Z80 RAM", Z80Ram.Length, Endian.Little, + addr => Z80Ram[addr & 0x1FFF], + (addr, value) => { Z80Ram[addr & 0x1FFF] = value; }); + + var VRamDomain = new MemoryDomain("Video RAM", VDP.VRAM.Length, Endian.Big, + addr => VDP.VRAM[addr & 0xFFFF], + (addr, value) => VDP.VRAM[addr & 0xFFFF] = value); + + domains.Add(MainMemoryDomain); + domains.Add(Z80Domain); + domains.Add(VRamDomain); + memoryDomains = domains.AsReadOnly(); + } + + public IList MemoryDomains { get { return memoryDomains; } } + public MemoryDomain MainMemory { get { return memoryDomains[0]; } } public void Dispose() { } } diff --git a/BizHawk.Emulation/Consoles/Sega/Genesis/IO.cs b/BizHawk.Emulation/Consoles/Sega/Genesis/IO.cs index 51857d59b0..2ea0c6bf5e 100644 --- a/BizHawk.Emulation/Consoles/Sega/Genesis/IO.cs +++ b/BizHawk.Emulation/Consoles/Sega/Genesis/IO.cs @@ -54,7 +54,7 @@ case 0x04: return IOPorts[0].Control; case 0x05: return IOPorts[1].Control; - case 0x06: return 0xFF;// IOPorts[2].Control; TODO hack? returning FF fixes revenge of shinobi and strider. investigate later. + case 0x06: return 0xFF;// return IOPorts[2].Control; //TODO hack? returning FF fixes revenge of shinobi and strider. investigate later. case 0x07: return IOPorts[0].TxData; case 0x08: return IOPorts[0].RxData; diff --git a/BizHawk.Emulation/Consoles/Sega/Genesis/MemoryMap.68000.cs b/BizHawk.Emulation/Consoles/Sega/Genesis/MemoryMap.68000.cs index c5cbf1f1aa..8c06cf9a1b 100644 --- a/BizHawk.Emulation/Consoles/Sega/Genesis/MemoryMap.68000.cs +++ b/BizHawk.Emulation/Consoles/Sega/Genesis/MemoryMap.68000.cs @@ -16,7 +16,7 @@ namespace BizHawk.Emulation.Consoles.Sega if (address == 0xA11100) // Z80 BUS status { - Console.WriteLine("QUERY z80 bus status. 68000 can access? " + (M68000HasZ80Bus && Z80Reset == false)); + //Console.WriteLine("QUERY z80 bus status. 68000 can access? " + (M68000HasZ80Bus && Z80Reset == false)); return (sbyte) (M68000HasZ80Bus && Z80Reset == false ? 0 : 1); } @@ -69,13 +69,17 @@ namespace BizHawk.Emulation.Consoles.Sega int maskedAddr; if (address < 0x400000) // Cartridge ROM return (RomData[address] << 24) | (RomData[address + 1] << 16) | (RomData[address + 2] << 8) | RomData[address + 3]; - + if (address >= 0xE00000) // Work RAM { maskedAddr = address & 0xFFFF; return (Ram[maskedAddr] << 24) | (Ram[maskedAddr + 1] << 16) | (Ram[maskedAddr + 2] << 8) | Ram[maskedAddr + 3]; } + // try to handle certain things separate if they need to be separate? otherwise handle as 2x readwords? + { + return ((ushort)ReadWord(address) | (ushort)(ReadWord(address + 2) << 16)); + } if (address == 0xA10008) return 0; // FIXME HACK for tg-sync. Console.WriteLine("UNHANDLED READL {0:X6}", address); @@ -105,7 +109,7 @@ namespace BizHawk.Emulation.Consoles.Sega if (address == 0xA11100) { M68000HasZ80Bus = (value & 1) != 0; - Console.WriteLine("68000 has the z80 bus: " + M68000HasZ80Bus); + //Console.WriteLine("68000 has the z80 bus: " + M68000HasZ80Bus); return; } if (address == 0xA11200) // Z80 RESET @@ -113,7 +117,7 @@ namespace BizHawk.Emulation.Consoles.Sega Z80Reset = (value & 1) == 0; if (Z80Reset) SoundCPU.Reset(); - Console.WriteLine("z80 reset: " + Z80Reset); + //Console.WriteLine("z80 reset: " + Z80Reset); return; } if (address >= 0xC00000) @@ -170,7 +174,7 @@ namespace BizHawk.Emulation.Consoles.Sega if (address == 0xA11100) // Z80 BUSREQ { M68000HasZ80Bus = (value & 0x100) != 0; - Console.WriteLine("68000 has the z80 bus: " + M68000HasZ80Bus); + //Console.WriteLine("68000 has the z80 bus: " + M68000HasZ80Bus); return; } if (address == 0xA11200) // Z80 RESET @@ -178,7 +182,7 @@ namespace BizHawk.Emulation.Consoles.Sega Z80Reset = (value & 0x100) == 0; if (Z80Reset) SoundCPU.Reset(); - Console.WriteLine("z80 reset: " + Z80Reset); + //Console.WriteLine("z80 reset: " + Z80Reset); return; } Console.WriteLine("UNHANDLED WRITEW {0:X6}:{1:X4}", address, value); diff --git a/BizHawk.Emulation/Consoles/Sega/Genesis/MemoryMap.Z80.cs b/BizHawk.Emulation/Consoles/Sega/Genesis/MemoryMap.Z80.cs index 326263240e..955a9bfce8 100644 --- a/BizHawk.Emulation/Consoles/Sega/Genesis/MemoryMap.Z80.cs +++ b/BizHawk.Emulation/Consoles/Sega/Genesis/MemoryMap.Z80.cs @@ -16,13 +16,15 @@ namespace BizHawk.Emulation.Consoles.Sega if (address >= 0x4000 && address < 0x6000) { //Console.WriteLine(" === Z80 READS FM STATUS ==="); - return YM2612.ReadStatus(); + return YM2612.ReadStatus(); // TODO: more than 1 read port probably? } if (address >= 0x8000) { // 68000 Bank region return (byte) ReadByte(BankRegion | (address & 0x7FFF)); } + if (address <= 0x6100) // read from bank address register - returns FF + return 0xFF; Console.WriteLine("UNHANDLED Z80 READ {0:X4}",address); return 0xCD; } @@ -37,18 +39,40 @@ namespace BizHawk.Emulation.Consoles.Sega } if (address >= 0x4000 && address < 0x6000) { - //Console.WriteLine(" === Z80 WRITES Z80 {0:X4}:{1:X2} ===",address, value); + //Console.WriteLine(" === Z80 WRITES YM2612 {0:X4}:{1:X2} ===",address, value); YM2612.Write(address & 3, value); return; } - if (address == 0x6000) + if (address < 0x6100) { BankRegion >>= 1; BankRegion |= (value & 1) << 23; BankRegion &= 0x00FF8000; - Console.WriteLine("Bank pointing at {0:X8}",BankRegion); + //Console.WriteLine("Bank pointing at {0:X8}",BankRegion); return; } + if (address >= 0x7F00 && address < 0x7F20) + { + switch (address & 0x1F) + { + case 0x00: + case 0x02: + VDP.WriteVdpData((ushort) ((value<<8) | value)); + return; + + case 0x04: + case 0x06: + VDP.WriteVdpControl((ushort)((value << 8) | value)); + return; + + case 0x11: + case 0x13: + case 0x15: + case 0x17: + PSG.WritePsgData(value, SoundCPU.TotalExecutedCycles); + return; + } + } if (address >= 0x8000) { WriteByte(BankRegion | (address & 0x7FFF), (sbyte) value);