diff --git a/BizHawk.Client.EmuHawk/config/ControllerConfig.cs b/BizHawk.Client.EmuHawk/config/ControllerConfig.cs index 288d748b57..59e07f8119 100644 --- a/BizHawk.Client.EmuHawk/config/ControllerConfig.cs +++ b/BizHawk.Client.EmuHawk/config/ControllerConfig.cs @@ -28,7 +28,6 @@ namespace BizHawk.Client.EmuHawk ControllerImages.Add("Dual Gameboy Controller", Properties.Resources.GBController); ControllerImages.Add("SMS Controller", Properties.Resources.SMSController); - ControllerImages.Add("Genesis 3-Button Controller", Properties.Resources.GENController); ControllerImages.Add("GPGX Genesis Controller", Properties.Resources.GENController); ControllerImages.Add("Saturn Controller", Properties.Resources.SaturnController); diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj index f40253760d..ffd41c1f4d 100644 --- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj +++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj @@ -512,28 +512,28 @@ - MGBAHawk.cs + MGBAHawk.cs - MGBAHawk.cs + MGBAHawk.cs - MGBAHawk.cs + MGBAHawk.cs - MGBAHawk.cs + MGBAHawk.cs - MGBAHawk.cs + MGBAHawk.cs - MGBAHawk.cs + MGBAHawk.cs - MGBAHawk.cs + MGBAHawk.cs - MGBAHawk.cs + MGBAHawk.cs @@ -1001,12 +1001,6 @@ - - - - - - GPGX.cs @@ -1259,12 +1253,6 @@ - - - - - - @@ -1282,7 +1270,6 @@ - diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/Cart/EEPROM.cs b/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/Cart/EEPROM.cs deleted file mode 100644 index 96d1e3f118..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/Cart/EEPROM.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System; -using System.Globalization; - -using BizHawk.Emulation.Common; - -namespace BizHawk.Emulation.Cores.Sega.Genesis -{ - partial class Genesis - { - // State - bool EepromEnabled; - - int EepromSize; - int EepromAddrMask; - int SdaInAddr, SdaInBit; - int SdaOutAddr, SdaOutBit; - int SclAddr, SclBit; - - int SdaInCurrValue, SclCurrValue; - - // Code - - void InitializeEeprom(GameInfo game) - { - if (game["EEPROM"] == false) - return; - - EepromEnabled = true; - EepromAddrMask = game.GetHexValue("EEPROM_ADDR_MASK"); - EepromSize = EepromAddrMask + 1; - - var t = game.OptionValue("SDA_IN").Split(':'); - SdaInAddr = int.Parse(t[0], NumberStyles.HexNumber); - SdaInBit = int.Parse(t[1]); - - t = game.OptionValue("SDA_OUT").Split(':'); - SdaOutAddr = int.Parse(t[0], NumberStyles.HexNumber); - SdaOutBit = int.Parse(t[1]); - - t = game.OptionValue("SCL").Split(':'); - SclAddr = int.Parse(t[0], NumberStyles.HexNumber); - SclBit = int.Parse(t[1]); - - SaveRAM = new byte[EepromSize]; - - Console.WriteLine("EEPROM enabled. Size: ${0:X} SDA_IN: ${1:X}:{2} SDA_OUT: ${3:X}:{4}, SCL: ${5:X}:{6}", - EepromSize, SdaInAddr, SdaInBit, SdaOutAddr, SdaOutBit, SclAddr, SclBit); - } - - void WriteByteEeprom(int address, byte value) - { - if (address == SdaInAddr) - { - SdaInCurrValue = (value >> SdaInBit) & 1; - Console.WriteLine("SDA_IN: {0}", SdaInCurrValue); - } - if (address == SclAddr) - { - SclCurrValue = (value >> SclBit) & 1; - Console.WriteLine("SCL: {0}", SclCurrValue); - } - - // todo: logic! - - } - } -} diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/Cart/RomHeader.cs b/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/Cart/RomHeader.cs deleted file mode 100644 index cf3652cefa..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/Cart/RomHeader.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; -using System.Text; - -namespace BizHawk.Emulation.Cores.Sega.Genesis -{ - partial class Genesis - { - public string RH_Console { get { return GetRomString(0x100, 0x10); } } - public string RH_Copyright { get { return GetRomString(0x110, 0x10); } } - public string RH_NameDomestic { get { return GetRomString(0x120, 0x30); } } - public string RH_NameExport { get { return GetRomString(0x150, 0x30); } } - public int RH_RomSize { get { return GetRomLongWord(0x1A4); } } - public string RH_Region { get { return GetRomString(0x1F0, 3); } } - - public bool RH_SRamPresent { get { return (RomData[0x1B2] & 0x40) != 0; } } - public int RH_SRamCode { get { return (RomData[0x1B2] >> 3) & 3; } } - public int RH_SRamStart { get { return GetRomLongWord(0x1B4); } } - public int RH_SRamEnd { get { return GetRomLongWord(0x1B8); } } - - public string RH_SRamInterpretation() - { - switch (RH_SRamCode) - { - case 0: return "Even and odd addresses"; - case 2: return "Even addresses"; - case 3: return "Odd addresses"; - default: return "Invalid type"; - } - } - - string GetRomString(int offset, int len) - { - return Encoding.ASCII.GetString(RomData, offset, len).Trim(); - } - - int GetRomLongWord(int offset) - { - return (RomData[offset] << 24) | (RomData[offset + 1] << 16) | (RomData[offset + 2] << 8) | RomData[offset + 3]; - } - - void LogCartInfo() - { - Console.WriteLine("=================="); - Console.WriteLine("ROM Cartridge Data"); - Console.WriteLine("=================="); - Console.WriteLine("System: {0}", RH_Console); - Console.WriteLine("Copyright: {0}", RH_Copyright); - Console.WriteLine("Name (Dom): {0}", RH_NameDomestic); - Console.WriteLine("Name (Exp): {0}", RH_NameExport); - Console.WriteLine("Region: {0}", RH_Region); - Console.WriteLine("Rom Size: {0,7} (${0:X})", RH_RomSize); - Console.WriteLine("SRAM Used: {0}", RH_SRamPresent); - if (RH_SRamPresent) - { - Console.WriteLine("SRAM Start: {0,7} (${0:X})", RH_SRamStart); - Console.WriteLine("SRAM End: {0,7} (${0:X})", RH_SRamEnd); - Console.WriteLine("SRAM Type: {0}", RH_SRamInterpretation()); - } - } - } -} diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/Cart/SaveRAM.cs b/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/Cart/SaveRAM.cs deleted file mode 100644 index d1947fb9a4..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/Cart/SaveRAM.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using BizHawk.Emulation.Common; - -namespace BizHawk.Emulation.Cores.Sega.Genesis -{ - partial class Genesis - { - bool SaveRamEnabled; - bool SaveRamEveryOtherByte; - int SaveRamStartOffset; - int SaveRamEndOffset; - int SaveRamLength; - - byte[] SaveRAM = new byte[0]; - - void InitializeSaveRam(GameInfo game) - { - if (EepromEnabled) - return; - - if (game["DisableSaveRam"] || RH_SRamPresent == false) - return; - - SaveRamEnabled = true; - SaveRamEveryOtherByte = RH_SRamCode != 0; - SaveRamStartOffset = RH_SRamStart; - SaveRamEndOffset = RH_SRamEnd; - - if (game["SaveRamStartOffset"]) - SaveRamStartOffset = game.GetHexValue("SaveRamStartOffset"); - if (game["SaveRamEndOffset"]) - SaveRamEndOffset = game.GetHexValue("SaveRamEndOffset"); - - SaveRamLength = (SaveRamEndOffset - SaveRamStartOffset) + 1; - - if (SaveRamEveryOtherByte) - SaveRamLength = ((SaveRamEndOffset - SaveRamStartOffset) / 2) + 1; - - SaveRAM = new byte[SaveRamLength]; - - Console.WriteLine("SaveRAM enabled. Start: ${0:X6} End: ${1:X6} Length: ${2:X} Mode: {3}", SaveRamStartOffset, SaveRamEndOffset, SaveRamLength, RH_SRamInterpretation()); - } - - public byte[] CloneSaveRam() { return (byte[])SaveRAM.Clone(); } - public void StoreSaveRam(byte[] data) { Array.Copy(data, SaveRAM, data.Length); } - - public bool SaveRamModified { get; private set; } - } -} diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/Compat.txt b/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/Compat.txt deleted file mode 100644 index 64889f2059..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/Compat.txt +++ /dev/null @@ -1,156 +0,0 @@ -68000: - -Timings: - - - MULU/MULS/DIVU/DIVS have funky timings. - - How many cycles does TRAP take to execute? - - How many cycles does it take to accept an interrupt? - - AND has some funky timings when it comes to immediates? - -GAMES: - -Ahhh! Real monsters - no sound -Adventures of Mighty Max - crashes memory mapper -Air Diver - suffer from lack of 2cell vscroll -Alien Storm.... gfx glitches. control glitches? -Altered Beast: start with 0 health, 0 lives??? -Another World .. broken.. (E) tho -Arcus Odyssey does UNHANDLED Z80 READs... is this a problem? -Awesome Possum - controls are wrong -Batman - flicker and music is messed -Batman Forever - significant gfx issues -Battle Squadron - crashes memory mapper woo! -Blood Shot - FPS game - some texture corruption -Bonkers - substantial gfx corruption -Buck Rogers crashes in a fun way -Burning Force - some gfx issues. works way better than it has in the past though! -Cheese Cat-astrophe - crashes renderer!! -Chester Cheetah - freezes when starting new game -Chuck Rock - Music messed up -Contra Hard Corps: Scrolling is messed up in level 1... used to work. -Dashin' Desperados .. bottom screen messed up -Death Duel crashes my renderer... (!) -Decap Attack - Item select screen messed up -Double Dragon doesn't boot -Devilish/Bad Omen - intro messed up.... interesting debug target -Dune... freezes in intro -Exile - Immediate gfx issues... Debug target. -F1 World Championship... Gfx issue at bottom of screen... quite cool working game though! -Fatal Rewind - appears to do a read.w on FFFFFF... that would be an address error. read.l messes up too. Ergo: basically doesnt work. -Final Blow - Music messed up -Fire Shark - Messed up sound -Flavio's Raster FX Test.. doesnt work -Foreman for Real doent boot -Galaxy Force II - gfx issue in level select screen, and in level-end "shoot the core" part -Gargoyles... gameplay is nonfunctional -Gauntlet 4 .. title screen messed. gfx corruption. immediately - debug target. -Golden Axe - controls are jacked up -Golden Axe 3 intro.... weirder than before for sure -Grind Stormer -Herzog Zwei .. doesnt boot fully -Insector X .. title screen gfx issue -James Pond 3 crash in intro -Jim Power - gfx glitches -Jurassic Park 2 - crashes in intro -Lemmings: Sound is royally effed... gfx glitches. -Marvel Land .. holy shit thats psychadelic -Mega Turrican some gfx glitches -Mortal Kombat... -MUSHA: Intro music starts too soon. Suffers from lack of 2-cell-vertical-scroll mode. -Out of This World... pretty substantially broken -Outrun 2019, much more significant gfx issues. -Outrun, minor gfx issue. maybe related to h-int timing? -Outrunners, some gfx issues... but not as bad as you might think!!! apparently doesnt use interlace mode? -Panorama Cotton still not working right -Power Monger messed up -RamboIII - intro gfx corrupted - MAYBE GOOD DEBUGGING TARGET -Shining in the Darkness: Check out sprites in the tavern... very odd -Sonic 2: Aside from lack of interlace mode, the shadows in the special stage are white....? -Sonic 2: Something still amiss with title screen sprite masking -Sonic 3 serious gfx glitches -Star Control - Shit gets crazy -Steel Empire - controls messed up. probably gfx issues also. -Sub-Terrania some gfx issues in intro -Super Hang-On - Sprite priority/masking isnt happening the way its supposed to on the tracks. -Super Fantasy Zone: Sound totally boned, missing graphics -TaleSpin - gfx glitches -The Humans -The Immortal -Truxton - Sound is jaaaacked. -Verytex - gfx issues -Zero Tolerance - gfx bugs that didnt used to happen :( -Zombies At My Neighbors: doesnt boot really -Zoop doesnt boot - - -====================================================== -Fixed Issues: (listed for regression testing purposes) -====================================================== - -(Sprites X/Y are 10-bit, but must be masked to 9-bit) -- Dragon's Revenge.... ball sprite seems missing? of all the sprites to not show up... -- Fire Shark - Sprites dont render... VERY similar to Truxton. Same engine? -- Truxton - Sprites do not appear to be rendering. -- Zero Wing - Sprites arent rendering....... - -Flavio's DMA test... DMAs when it shouldnt!! - Masking off too much of the VDP command code - -Fun-n-Games fails its fadeouts. -- Fixed CRAM reads. I failed math. - -Sonic Spinball executes a VSRAM read -- Implemented VSRAM reads. - -Bugs related to longword read/write VRAM. Multiple bugs were present including sign-extension and endians and crap. - - Crusader of Centy- Text boxes messed up - - Eternal Champions - immediate gfx corruption - - Garfield... immediate gfx corruption. debug target. - - Kid Chameleon - gfx corruption on bounce bricks and level-end effect - -Games to test window calculation on: - - Road Blasters (doesnt use window, but Window & Nametable A are at same location) - - Out of this World - Same as Road Blasters - - Musha,Gaiares - Window at top - - Eliminate Down - Window at bottom - - Monster World 4, Wonder Boy in Monster World - Window at top - needs window scroll plane size adjustment - - D&D Warriors of the Eternal Sun - Window at bottom and at sides - - Truxton, Fire Shark - Window on Right - -====================================================== - -TODO: non-instant DMA emulation -TODO: Add 68000/VDP interrupt enable delay (one instruction, similar to After Burner/PCE) -TODO: H-Ints timing possibly not correct... Some game raster effects work, others don't work as expected. (could be HVC tho) -TODO: Test DMA/ VDP command words.... I'm not at all convinced that VRAM is always correct - - -============== -Notable games: -============== - -Ghouls n Ghosts sets up the graphics planes backwards from normal, by setting the plane A to be low priority and Plane B to be high priority. -If you have a bug in your priority code this may find it. - -Revenge of Shinobi will not play DAC sounds if YM2612 registers are not initialized to L/R channels enabled. - -Ballz doesnt really initialize hardly any VDP registers, relies on VDP registers powered-on to the correct values - -Contra appears to use VDP A0 set = byte-swap. Not sure if its important in anyway in that game, but the byte swap happens. - -Games that use VRAM->VRAM Copy: D&D Warriors of the Eternal Sun, MUSHA, Devilish, Viewpoint - -Games that require accurate VRAM fill emulation include Thunder Force IV, - Contra Hard Corps, Revenge of Shinobi, Taiga Drama, and Sword of Vermillion. - -Sonic Spinball reads from VSRAM - -Games to test for sprite masking/overflow: - - Sonic 1 title screen (uses overflow to mask) - - Sonic 2 title screen (uses sprite mask modes) - - Galaxy Force 2 level select (uses sprite mask) - - Landstalker sprite masking (chests and such) - - Nemesis test rom - -Games known to use 2-cell vertical scroll mode: - - Air Diver - - Exo Squad - - Contra Hard Corps (giant robot boss on stage 1) - - MUSHA (stage 3) diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/GenVDP.DMA.cs b/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/GenVDP.DMA.cs deleted file mode 100644 index 71ecf22dd1..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/GenVDP.DMA.cs +++ /dev/null @@ -1,112 +0,0 @@ -using System; -using BizHawk.Common; - -namespace BizHawk.Emulation.Cores.Sega.Genesis -{ - public partial class GenVDP - { - // TODO: make this a requirement of constructor? - 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 - { - get - { - if ((Registers[23] & 0x80) == 0) // 68000 -> VRAM copy mode - return ((Registers[21] << 1) | (Registers[22] << 9) | (Registers[23] << 17)) & 0xFFFFFE; - - // Else VRAM/VRAM copy mode - return (Registers[21] | (Registers[22] << 8)) & 0xFFFFFE; - } - } - - bool DmaFillModePending; - - void ExecuteVramFill(ushort data) - { - if (data != 0) - Console.WriteLine("fill word is not zero {0:X4}", data); - - Log.Note("VDP", "DMA FILL REQD, WRITE {0:X4}, {1:X4} times, at {2:X4}", data, DmaLength, VdpDataAddr); - - // TODO: It should spread this out, not do it all at once. - - int length = DmaLength; - if (length == 0) - length = 0x10000; - - byte fillByte = (byte)(data >> 8); - - do - { - VRAM[VdpDataAddr] = fillByte; - Log.Note("VDP", "VRAM DMA FILL Write: [{0:X4}] = {1:X2}", VdpDataAddr, fillByte); - UpdatePatternBuffer(VdpDataAddr); - VdpDataAddr += Registers[15]; - } while (--length > 0); - - // TOOD: test if the length register updated? One would assume so... - Registers[19] = 0; - Registers[20] = 0; - - // TODO: Source registers should be incremented also (even for Fill) - - DmaFillModePending = false; - } - - void Execute68000VramCopy() - { - Log.Note("VDP", "DMA 68000 -> VRAM COPY REQ'D. LENGTH {0:X4}, SOURCE {1:X4}", DmaLength, DmaSource); - - int length = DmaLength; - if (length == 0) - length = 0x10000; - - int source = DmaSource; - - do - { - ushort value = (ushort)DmaReadFrom68000(source); - source += 2; - // TODO funky source behavior - WriteVdpData(value); - } while (--length > 0); - - Registers[19] = 0; - Registers[20] = 0; - - // TODO: update DMA source registers. - // TODO: find correct number of 68k cycles to burn - } - - void ExecuteVramVramCopy() - { - Log.Note("VDP", "DMA VRAM -> VRAM COPY REQ'D. LENGTH {0:X4}, SOURCE {1:X4}", DmaLength, DmaSource); - - int length = DmaLength; - if (length == 0) - length = 0x10000; - - int source = DmaSource; - - do - { - byte data = VRAM[source]; - VRAM[VdpDataAddr] = data; - UpdatePatternBuffer(VdpDataAddr); - Log.Note("VDP", "VRAM/VRAM Copy VRAM[{0:X4}] = {1:X2}", VdpDataAddr, data); - source = (source + 1) & 0xFFFF; - VdpDataAddr += Registers[0xF]; - } while (--length > 0); - - Registers[19] = 0; - Registers[20] = 0; - - // TODO: length, source registers should be updated.... - // TODO: find correct number of 68k cycles to burn - } - } -} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/GenVDP.Render.cs b/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/GenVDP.Render.cs deleted file mode 100644 index 8474935ef4..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/GenVDP.Render.cs +++ /dev/null @@ -1,525 +0,0 @@ -using System; - -namespace BizHawk.Emulation.Cores.Sega.Genesis -{ - public partial class GenVDP - { - // Priority buffer contents have the following values: - // 0 = Backdrop color - // 1 = Plane B Low Priority - // 2 = Plane A Low Priority - // 4 = Plane B High Priority - // 5 = Plane A High Priority - // 9 = Sprite has been drawn - - byte[] PriorityBuffer = new byte[320]; - - static readonly byte[] PalXlatTable = { 0, 0, 36, 36, 73, 73, 109, 109, 145, 145, 182, 182, 219, 219, 255, 255 }; - - public void RenderLine() - { - if (DisplayEnabled) - { - Array.Clear(PriorityBuffer, 0, 320); - - // TODO: I would like to be able to render Scroll A before Scroll B, in order to minimize overdraw. - // But at the moment it complicates priority stuff. - - if (CellBasedVertScroll == false) - { - RenderScrollB(); - RenderScrollA(); - } - else - { - RenderScrollBTwoCellVScroll(); - RenderScrollATwoCellVScroll(); - } - - RenderSpritesScanline(); - } - else - { - // If display is disabled, fill in with background color. - for (int i = 0; i < FrameWidth; i++) - FrameBuffer[(ScanLine * FrameWidth) + i] = BackgroundColor; - } - - //if (ScanLine == 223) // shrug - // RenderPalette(); - } - - void RenderPalette() - { - for (int p = 0; p < 4; p++) - for (int i = 0; i < 16; i++) - FrameBuffer[(p * FrameWidth) + i] = Palette[(p * 16) + i]; - } - - void RenderScrollAScanline(int xScroll, int yScroll, int nameTableBase, int startPixel, int endPixel, bool window) - { - const int lowPriority = 2; - const int highPriority = 5; - int yTile = ((ScanLine + yScroll) / 8) % NameTableHeight; - int nameTableWidth = NameTableWidth; - if (window) - nameTableWidth = (DisplayWidth == 40) ? 64 : 32; - - // this is hellllla slow. but not optimizing until we implement & understand - // all scrolling modes, shadow & hilight, etc. - // in thinking about this, you could convince me to optimize the PCE background renderer now. - // Its way simple in comparison. But the PCE sprite renderer is way worse than gen. - for (int x = startPixel; x < endPixel; x++) - { - int xTile = Math.Abs(((x + (1024 - xScroll)) / 8) % nameTableWidth); - int xOfs = Math.Abs((x + (1024 - xScroll)) & 7); - int yOfs = (ScanLine + yScroll) % 8; - int cellOfs = nameTableBase + (yTile * nameTableWidth * 2) + (xTile * 2); - int nameTableEntry = VRAM[cellOfs] | (VRAM[cellOfs + 1] << 8); - int patternNo = nameTableEntry & 0x7FF; - bool hFlip = ((nameTableEntry >> 11) & 1) != 0; - bool vFlip = ((nameTableEntry >> 12) & 1) != 0; - bool priority = ((nameTableEntry >> 15) & 1) != 0; - int palette = (nameTableEntry >> 13) & 3; - - if (priority && PriorityBuffer[x] >= highPriority) continue; - if (!priority && PriorityBuffer[x] >= lowPriority) continue; - - if (vFlip) yOfs = 7 - yOfs; - if (hFlip) xOfs = 7 - xOfs; - - int texel = PatternBuffer[(patternNo * 64) + (yOfs * 8) + (xOfs)]; - if (texel == 0) continue; - int pixel = Palette[(palette * 16) + texel]; - FrameBuffer[(ScanLine * FrameWidth) + x] = pixel; - PriorityBuffer[x] = (byte)(priority ? highPriority : lowPriority); - } - } - - void RenderScrollAScanlineTwoCellVScroll(int xScroll, int nameTableBase, int startPixel, int endPixel, bool window) - { - const int lowPriority = 2; - const int highPriority = 5; - - int fineHScroll = xScroll & 15; - int nameTableWidth = NameTableWidth; - if (window) - nameTableWidth = (DisplayWidth == 40) ? 64 : 32; - - for (int x = startPixel; x < endPixel; x++) - { - int vsramUnitOffset = ((x - fineHScroll) / 16) % 40; - int yScroll = VSRAM[vsramUnitOffset * 2] & 0x3FF; - int yTile = ((ScanLine + yScroll) / 8) % NameTableHeight; - - int xTile = Math.Abs(((x + (1024 - xScroll)) / 8) % nameTableWidth); - int xOfs = Math.Abs((x + (1024 - xScroll)) & 7); - int yOfs = (ScanLine + yScroll) % 8; - int cellOfs = nameTableBase + (yTile * nameTableWidth * 2) + (xTile * 2); - int nameTableEntry = VRAM[cellOfs] | (VRAM[cellOfs + 1] << 8); - int patternNo = nameTableEntry & 0x7FF; - bool hFlip = ((nameTableEntry >> 11) & 1) != 0; - bool vFlip = ((nameTableEntry >> 12) & 1) != 0; - bool priority = ((nameTableEntry >> 15) & 1) != 0; - int palette = (nameTableEntry >> 13) & 3; - - if (priority && PriorityBuffer[x] >= highPriority) continue; - if (!priority && PriorityBuffer[x] >= lowPriority) continue; - - if (vFlip) yOfs = 7 - yOfs; - if (hFlip) xOfs = 7 - xOfs; - - int texel = PatternBuffer[(patternNo * 64) + (yOfs * 8) + (xOfs)]; - if (texel == 0) continue; - int pixel = Palette[(palette * 16) + texel]; - FrameBuffer[(ScanLine * FrameWidth) + x] = pixel; - PriorityBuffer[x] = (byte)(priority ? highPriority : lowPriority); - } - } - - void CalculateWindowScanlines(out int startScanline, out int endScanline) - { - int data = Registers[0x12]; - int windowVPosition = data & 31; - bool fromTop = (data & 0x80) == 0; - - if (windowVPosition == 0) - { - startScanline = -1; - endScanline = -1; - return; - } - - if (fromTop) - { - startScanline = 0; - endScanline = (windowVPosition * 8); - } - else - { - startScanline = windowVPosition * 8; - endScanline = FrameHeight; - } - } - - void CalculateWindowPosition(out int startPixel, out int endPixel) - { - int data = Registers[0x11]; - int windowHPosition = (data & 31) * 2; // Window H position is set in 2-cell increments - bool fromLeft = (data & 0x80) == 0; - - if (windowHPosition == 0) - { - startPixel = -1; - endPixel = -1; - return; - } - - if (fromLeft) - { - startPixel = 0; - endPixel = (windowHPosition * 8); - if (endPixel > FrameWidth) - endPixel = FrameWidth; - } - else - { - startPixel = windowHPosition * 8; - endPixel = FrameWidth; - if (startPixel > FrameWidth) - { - startPixel = -1; - endPixel = -1; - } - } - } - - void RenderScrollA() - { - // Calculate scroll offsets - - int hscroll = CalcHScrollPlaneA(ScanLine); - int vscroll = VSRAM[0] & 0x3FF; - - // Calculate window dimensions - - int startWindowScanline, endWindowScanline; - int startWindowPixel, endWindowPixel; - CalculateWindowScanlines(out startWindowScanline, out endWindowScanline); - CalculateWindowPosition(out startWindowPixel, out endWindowPixel); - - // Render scanline - - if (ScanLine >= startWindowScanline && ScanLine < endWindowScanline) // Window takes up whole scanline - { - RenderScrollAScanline(0, 0, NameTableAddrWindow, 0, FrameWidth, true); - } - else if (startWindowPixel != -1) // Window takes up partial scanline - { - if (startWindowPixel == 0) // Window grows from left side - { - RenderScrollAScanline(0, 0, NameTableAddrWindow, 0, endWindowPixel, true); - RenderScrollAScanline(hscroll, vscroll, NameTableAddrA, endWindowPixel, FrameWidth, false); - } - else // Window grows from right side - { - RenderScrollAScanline(hscroll, vscroll, NameTableAddrA, 0, startWindowPixel, false); - RenderScrollAScanline(0, 0, NameTableAddrWindow, startWindowPixel, FrameWidth, true); - } - } - else // No window this scanline - { - RenderScrollAScanline(hscroll, vscroll, NameTableAddrA, 0, FrameWidth, false); - } - } - - void RenderScrollATwoCellVScroll() - { - // Calculate scroll offsets - - int hscroll = CalcHScrollPlaneA(ScanLine); - - // Calculate window dimensions - - int startWindowScanline, endWindowScanline; - int startWindowPixel, endWindowPixel; - CalculateWindowScanlines(out startWindowScanline, out endWindowScanline); - CalculateWindowPosition(out startWindowPixel, out endWindowPixel); - - // Render scanline - - if (ScanLine >= startWindowScanline && ScanLine < endWindowScanline) // Window takes up whole scanline - { - RenderScrollAScanline(0, 0, NameTableAddrWindow, 0, FrameWidth, true); - } - else if (startWindowPixel != -1) // Window takes up partial scanline - { - if (startWindowPixel == 0) // Window grows from left side - { - RenderScrollAScanline(0, 0, NameTableAddrWindow, 0, endWindowPixel, true); - RenderScrollAScanlineTwoCellVScroll(hscroll, NameTableAddrA, endWindowPixel, FrameWidth, false); - } - else // Window grows from right side - { - RenderScrollAScanlineTwoCellVScroll(hscroll, NameTableAddrA, 0, startWindowPixel, false); - RenderScrollAScanline(0, 0, NameTableAddrWindow, startWindowPixel, FrameWidth, true); - } - } - else // No window this scanline - { - RenderScrollAScanlineTwoCellVScroll(hscroll, NameTableAddrA, 0, FrameWidth, false); - } - } - - void RenderScrollB() - { - int bgColor = BackgroundColor; - int xScroll = CalcHScrollPlaneB(ScanLine); - int yScroll = VSRAM[1] & 0x3FF; - - const int lowPriority = 1; - const int highPriority = 4; - - int yTile = ((ScanLine + yScroll) / 8) % NameTableHeight; - - // this is hellllla slow. but not optimizing until we implement & understand - // all scrolling modes, shadow & hilight, etc. - // in thinking about this, you could convince me to optimize the PCE background renderer now. - // Its way simple in comparison. But the PCE sprite renderer is way worse than gen. - for (int x = 0; x < FrameWidth; x++) - { - int xTile = Math.Abs(((x + (1024 - xScroll)) / 8) % NameTableWidth); - int xOfs = Math.Abs((x + (1024 - xScroll)) & 7); - int yOfs = (ScanLine + yScroll) % 8; - int cellOfs = NameTableAddrB + (yTile * NameTableWidth * 2) + (xTile * 2); - int nameTableEntry = VRAM[cellOfs] | (VRAM[cellOfs + 1] << 8); - int patternNo = nameTableEntry & 0x7FF; - bool hFlip = ((nameTableEntry >> 11) & 1) != 0; - bool vFlip = ((nameTableEntry >> 12) & 1) != 0; - bool priority = ((nameTableEntry >> 15) & 1) != 0; - int palette = (nameTableEntry >> 13) & 3; - - if (priority && PriorityBuffer[x] >= highPriority) continue; - if (!priority && PriorityBuffer[x] >= lowPriority) continue; - - if (vFlip) yOfs = 7 - yOfs; - if (hFlip) xOfs = 7 - xOfs; - - int texel = PatternBuffer[(patternNo * 64) + (yOfs * 8) + (xOfs)]; - int pixel = Palette[(palette * 16) + texel]; - if (texel != 0) - { - FrameBuffer[(ScanLine * FrameWidth) + x] = pixel; - PriorityBuffer[x] = (byte)(priority ? highPriority : lowPriority); - } - else - { - FrameBuffer[(ScanLine * FrameWidth) + x] = bgColor; - } - } - } - - void RenderScrollBTwoCellVScroll() - { - int bgColor = BackgroundColor; - int xScroll = CalcHScrollPlaneB(ScanLine); - int fineHScroll = xScroll & 15; - - const int lowPriority = 1; - const int highPriority = 4; - - for (int x = 0; x < FrameWidth; x++) - { - int vsramUnitOffset = ((x - fineHScroll) / 16) % 40; - int yScroll = VSRAM[(vsramUnitOffset * 2) + 1] & 0x3FF; - int yTile = ((ScanLine + yScroll) / 8) % NameTableHeight; - - int xTile = Math.Abs(((x + (1024 - xScroll)) / 8) % NameTableWidth); - int xOfs = Math.Abs((x + (1024 - xScroll)) & 7); - int yOfs = (ScanLine + yScroll) % 8; - int cellOfs = NameTableAddrB + (yTile * NameTableWidth * 2) + (xTile * 2); - int nameTableEntry = VRAM[cellOfs] | (VRAM[cellOfs + 1] << 8); - int patternNo = nameTableEntry & 0x7FF; - bool hFlip = ((nameTableEntry >> 11) & 1) != 0; - bool vFlip = ((nameTableEntry >> 12) & 1) != 0; - bool priority = ((nameTableEntry >> 15) & 1) != 0; - int palette = (nameTableEntry >> 13) & 3; - - if (priority && PriorityBuffer[x] >= highPriority) continue; - if (!priority && PriorityBuffer[x] >= lowPriority) continue; - - if (vFlip) yOfs = 7 - yOfs; - if (hFlip) xOfs = 7 - xOfs; - - int texel = PatternBuffer[(patternNo * 64) + (yOfs * 8) + (xOfs)]; - int pixel = Palette[(palette * 16) + texel]; - if (texel != 0) - { - FrameBuffer[(ScanLine * FrameWidth) + x] = pixel; - PriorityBuffer[x] = (byte)(priority ? highPriority : lowPriority); - } - else - { - FrameBuffer[(ScanLine * FrameWidth) + x] = bgColor; - } - } - } - - static readonly int[] SpriteSizeTable = { 8, 16, 24, 32 }; - Sprite sprite; - - void RenderSpritesScanline() - { - int scanLineBase = ScanLine * FrameWidth; - int processedSprites = 0; - int processedSpritesThisLine = 0; - int processedDotsThisLine = 0; - bool spriteMaskPrecursor = false; - - // This is incredibly unoptimized. TODO... - - FetchSprite(0); - while (true) - { - if (sprite.Y > ScanLine || sprite.Y + sprite.HeightPixels <= ScanLine) - goto nextSprite; - - processedSpritesThisLine++; - processedDotsThisLine += sprite.WidthPixels; - - if (sprite.X > -128) - spriteMaskPrecursor = true; - - if (sprite.X == -128 && spriteMaskPrecursor) - break; // apply sprite mask - - if (sprite.X + sprite.WidthPixels <= 0) - goto nextSprite; - - if (sprite.HeightCells == 2) - sprite.HeightCells = 2; - - int yline = ScanLine - sprite.Y; - if (sprite.VFlip) - yline = sprite.HeightPixels - 1 - yline; - int paletteBase = sprite.Palette * 16; - if (sprite.HFlip == false) - { - int pattern = sprite.PatternIndex + ((yline / 8)); - - for (int xi = 0; xi < sprite.WidthPixels; xi++) - { - if (sprite.X + xi < 0 || sprite.X + xi >= FrameWidth) - continue; - - if (sprite.Priority == false && PriorityBuffer[sprite.X + xi] >= 3) continue; - if (PriorityBuffer[sprite.X + xi] == 9) 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]; - PriorityBuffer[sprite.X + xi] = 9; - } - } - } - else - { // HFlip - int pattern = sprite.PatternIndex + ((yline / 8)) + (sprite.HeightCells * (sprite.WidthCells - 1)); - - for (int xi = 0; xi < sprite.WidthPixels; xi++) - { - if (sprite.X + xi < 0 || sprite.X + xi >= FrameWidth) - continue; - - if (sprite.Priority == false && PriorityBuffer[sprite.X + xi] >= 3) continue; - if (PriorityBuffer[sprite.X + xi] == 9) continue; - - int pixel = PatternBuffer[((pattern + ((-xi / 8) * sprite.HeightCells)) * 64) + ((yline & 7) * 8) + (7 - (xi & 7))]; - if (pixel != 0) - { - FrameBuffer[scanLineBase + sprite.X + xi] = Palette[paletteBase + pixel]; - PriorityBuffer[sprite.X + xi] = 9; - } - } - } - - nextSprite: - if (sprite.Link == 0) - break; - if (++processedSprites >= SpriteLimit) - break; - if (processedSpritesThisLine >= SpritePerLineLimit) - break; - if (processedDotsThisLine >= DotsPerLineLimit) - break; - if (DisplayWidth == 32 && sprite.Link >= 64) - break; - FetchSprite(sprite.Link); - } - } - - void FetchSprite(int spriteNo) - { - // Note - X/Y coordinates are 10-bits (3FF) but must be masked to 9-bits (1FF) - // In interlace mode this behavior should change - - int SatBase = SpriteAttributeTableAddr + (spriteNo * 8); - sprite.Y = (VRAM[SatBase + 0] | (VRAM[SatBase + 1] << 8) & 0x1FF) - 128; - sprite.X = (VRAM[SatBase + 6] | (VRAM[SatBase + 7] << 8) & 0x1FF) - 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.HFlip = ((VRAM[SatBase + 5] >> 3) & 1) != 0; - sprite.VFlip = ((VRAM[SatBase + 5] >> 4) & 1) != 0; - sprite.Palette = (VRAM[SatBase + 5] >> 5) & 3; - sprite.Priority = ((VRAM[SatBase + 5] >> 7) & 1) != 0; - } - - struct Sprite - { - public int X, Y; - public int WidthPixels, HeightPixels; - public int WidthCells, HeightCells; - public int Link; - public int Palette; - public int PatternIndex; - public bool Priority; - public bool HFlip; - public bool VFlip; - } - - int CalcHScrollPlaneA(int line) - { - int ofs = 0; - switch (Registers[11] & 3) - { - case 0: ofs = HScrollTableAddr; break; - case 1: ofs = HScrollTableAddr + ((line & 7) * 4); break; - case 2: ofs = HScrollTableAddr + ((line & ~7) * 4); break; - case 3: ofs = HScrollTableAddr + (line * 4); break; - } - - int value = VRAM[ofs] | (VRAM[ofs + 1] << 8); - return value & 0x3FF; - } - - int CalcHScrollPlaneB(int line) - { - int ofs = 0; - switch (Registers[11] & 3) - { - case 0: ofs = HScrollTableAddr; break; - case 1: ofs = HScrollTableAddr + ((line & 7) * 4); break; - case 2: ofs = HScrollTableAddr + ((line & ~7) * 4); break; - case 3: ofs = HScrollTableAddr + (line * 4); break; - } - - int value = VRAM[ofs + 2] | (VRAM[ofs + 3] << 8); - return value & 0x3FF; - } - } -} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/GenVDP.cs b/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/GenVDP.cs deleted file mode 100644 index bfe751b6ea..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/GenVDP.cs +++ /dev/null @@ -1,572 +0,0 @@ -using System; -using System.IO; -using System.Globalization; - -using BizHawk.Common; -using BizHawk.Common.BufferExtensions; -using BizHawk.Common.IOExtensions; -using BizHawk.Emulation.Common; - -namespace BizHawk.Emulation.Cores.Sega.Genesis -{ - public sealed partial class GenVDP : IVideoProvider - { - // Memory - public byte[] VRAM = new byte[0x10000]; - public ushort[] CRAM = new ushort[64]; - public ushort[] VSRAM = new ushort[40]; - public byte[] Registers = new byte[0x20]; - - public byte[] PatternBuffer = new byte[0x20000]; - public int[] Palette = new int[64]; - public int[] FrameBuffer = new int[320 * 224]; - public int FrameWidth = 320; - public int FrameHeight = 224; - - public int ScanLine; - public int HIntLineCounter; - - public bool HInterruptsEnabled { get { return (Registers[0] & 0x10) != 0; } } - public bool DisplayEnabled { get { return (Registers[1] & 0x40) != 0; } } - public bool VInterruptEnabled { get { return (Registers[1] & 0x20) != 0; } } - public bool DmaEnabled { get { return (Registers[1] & 0x10) != 0; } } - public bool CellBasedVertScroll { get { return (Registers[11] & 0x04) != 0; } } - - public bool InDisplayPeriod { get { return ScanLine < 224 && DisplayEnabled; } } - - ushort NameTableAddrA; - ushort NameTableAddrB; - ushort NameTableAddrWindow; - ushort SpriteAttributeTableAddr; - ushort HScrollTableAddr; - int NameTableWidth = 32; - int NameTableHeight = 32; - - int DisplayWidth; - int SpriteLimit; - int SpritePerLineLimit; - int DotsPerLineLimit; - - bool ControlWordPending; - ushort VdpDataAddr; - byte VdpDataCode; - - const int CommandVramRead = 0; - const int CommandVramWrite = 1; - const int CommandCramWrite = 3; - const int CommandVsramRead = 4; - const int CommandVsramWrite = 5; - const int CommandCramRead = 8; - - public ushort VdpStatusWord = 0x3400; - public const int StatusHorizBlanking = 0x04; - public const int StatusVerticalBlanking = 0x08; - public const int StatusOddFrame = 0x10; - public const int StatusSpriteCollision = 0x20; - public const int StatusSpriteOverflow = 0x40; - public const int StatusVerticalInterruptPending = 0x80; - - public bool VdpDebug = false; - - public Func GetPC; - - public GenVDP() - { - WriteVdpRegister(00, 0x04); - WriteVdpRegister(01, 0x04); - WriteVdpRegister(02, 0x30); - WriteVdpRegister(03, 0x3C); - WriteVdpRegister(04, 0x07); - WriteVdpRegister(05, 0x67); - WriteVdpRegister(10, 0xFF); - WriteVdpRegister(12, 0x81); - WriteVdpRegister(15, 0x02); - Log.Note("VDP", "VDP init routine complete"); - } - - public ushort ReadVdp(int addr) - { - switch (addr) - { - case 0: - case 2: - return ReadVdpData(); - case 4: - case 6: - return ReadVdpControl(); - default: - return ReadHVCounter(); - } - } - - public void WriteVdp(int addr, ushort data) - { - switch (addr) - { - case 0: - case 2: - WriteVdpData(data); - return; - case 4: - case 6: - WriteVdpControl(data); - return; - } - } - - public void WriteVdpControl(ushort data) - { - Log.Note("VDP", "Control Write {0:X4} (PC={1:X6})", data, GetPC()); - - if (ControlWordPending == false) - { - if ((data & 0xC000) == 0x8000) - { - int reg = (data >> 8) & 0x1F; - byte value = (byte)(data & 0xFF); - WriteVdpRegister(reg, value); - VdpDataCode = 0; - } - else - { - ControlWordPending = true; - VdpDataAddr &= 0xC000; - VdpDataAddr |= (ushort)(data & 0x3FFF); - VdpDataCode &= 0x3C; - VdpDataCode |= (byte)(data >> 14); - //Console.WriteLine("Address = {0:X4}", VdpDataAddr); - //Console.WriteLine("Code = {0:X2}", VdpDataCode); - } - } - else - { - ControlWordPending = false; - - // Update data address and code - VdpDataAddr &= 0x3FFF; - VdpDataAddr |= (ushort)((data & 0x03) << 14); - //Console.WriteLine("Address = {0:X4}", VdpDataAddr); - VdpDataCode &= 0x03; - VdpDataCode |= (byte)((data >> 2) & 0x3C); - //Log.Note("VDP", "Code = {0:X2}", VdpDataCode); - - if ((VdpDataCode & 0x20) != 0 && DmaEnabled) // DMA triggered - { - //Console.WriteLine("DMA TIME!"); - - // what type of DMA? - switch (Registers[23] >> 6) - { - case 2: - Log.Note("VDP", "VRAM FILL"); - DmaFillModePending = true; - break; - case 3: - Log.Error("VDP", "VRAM COPY *"); - ExecuteVramVramCopy(); - break; - default: - Execute68000VramCopy(); - break; - } - } - } - } - - public ushort ReadVdpControl() - { - VdpStatusWord |= 0x0200; // Fifo empty // TODO kill this, emulating the damn FIFO. - ControlWordPending = false; // Hmm.. if this happens in an interrupt between 1st and 2nd word.. - - // sprite overflow flag should clear. - // sprite collision flag should clear. - - return VdpStatusWord; - } - - public void WriteVdpData(ushort data) - { - Log.Note("VDP", "Data port write: {0:X4} (PC={1:X6})", data, GetPC()); - ControlWordPending = false; - - // byte-swap incoming data when A0 is set - if ((VdpDataAddr & 1) != 0) - { - data = (ushort)((data >> 8) | (data << 8)); - Log.Error("VDP", "VRAM byte-swap is happening because A0 is not 0. [{0:X4}] = {1:X4}", VdpDataAddr, data); - } - - switch (VdpDataCode & 0xF) - { - case CommandVramWrite: // VRAM Write - VRAM[VdpDataAddr & 0xFFFE] = (byte)data; - VRAM[(VdpDataAddr & 0xFFFE) + 1] = (byte)(data >> 8); - //if (VdpDebug) - Log.Note("VDP", "VRAM[{0:X4}] = {1:X4}", VdpDataAddr, data); - UpdatePatternBuffer(VdpDataAddr & 0xFFFE); - UpdatePatternBuffer((VdpDataAddr & 0xFFFE) + 1); - VdpDataAddr += Registers[0x0F]; - break; - case CommandCramWrite: // CRAM write - CRAM[(VdpDataAddr / 2) % 64] = data; - //if (VdpDebug) - Log.Note("VDP", "CRAM[{0:X2}] = {1:X4}", (VdpDataAddr / 2) % 64, data); - ProcessPalette((VdpDataAddr / 2) % 64); - VdpDataAddr += Registers[0x0F]; - break; - case CommandVsramWrite: // VSRAM write - VSRAM[(VdpDataAddr / 2) % 40] = data; - //if (VdpDebug) - Log.Note("VDP", "VSRAM[{0:X2}] = {1:X4}", (VdpDataAddr / 2) % 40, data); - VdpDataAddr += Registers[0x0F]; - break; - default: - Log.Error("VPD", "VDP DATA WRITE WITH UNHANDLED CODE!!! {0}", VdpDataCode & 7); - break; - } - - if (DmaFillModePending) - { - ExecuteVramFill(data); - } - } - - public ushort ReadVdpData() - { - int orig_addr = VdpDataAddr; - ushort retval = 0xBEEF; - switch (VdpDataCode & 0x0F) - { - case CommandVramRead: - //if ((VdpDataAddr & 1) != 0) throw new Exception("VRAM read is not word-aligned. what do?"); - retval = VRAM[VdpDataAddr & 0xFFFE]; - retval |= (ushort)(VRAM[(VdpDataAddr & 0xFFFE) + 1] << 8); - VdpDataAddr += Registers[0x0F]; - break; - case CommandVsramRead: - retval = VSRAM[(VdpDataAddr / 2) % 40]; - VdpDataAddr += Registers[0x0F]; - return retval; - case CommandCramRead: - retval = CRAM[(VdpDataAddr / 2) % 64]; - VdpDataAddr += Registers[0x0F]; - return retval; - default: - throw new Exception("VRAM read with unexpected code!!! " + (VdpDataCode & 0x0F)); - } - - Log.Note("VDP", "VDP Data Read from {0:X4} returning {1:X4}", orig_addr, retval); - return retval; - } - - ushort ReadHVCounter() - { - int vcounter = ScanLine; - if (vcounter > 0xEA) - vcounter -= 7; - // TODO generalize this across multiple video modes and stuff. - - // TODO dont tie this to musashi cycle count. - // Figure out a "clean" way to get cycle counter information available to VDP. - // Oh screw that. The VDP and the cpu cycle counters are going to be intertwined pretty tightly. - int hcounter = (488 - Native68000.Musashi.GetCyclesRemaining()) * 255 / 488; - // FIXME: totally utterly wrong. - - ushort res = (ushort)((vcounter << 8) | (hcounter & 0xFF)); - //Console.WriteLine("READ HVC: V={0:X2} H={1:X2} ret={2:X4}", vcounter, hcounter, res); - - return res; - } - - public void WriteVdpRegister(int register, byte data) - { - //if (VdpDebug) - Log.Note("VDP", "Register {0}: {1:X2}", register, data); - switch (register) - { - case 0x00: // Mode Set Register 1 - Registers[register] = data; - //if (VdpDebug) - //Log.Note("VDP", "HINT enabled: " + HInterruptsEnabled); - break; - - case 0x01: // Mode Set Register 2 - //if (VdpDebug) - //{ - // Registers[register] = data; - // 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); - //if (VdpDebug) - //Log.Note("VDP", "SET NTa A = {0:X4}", NameTableAddrA); - break; - - case 0x03: // Name Table Address for Window - NameTableAddrWindow = (ushort)((data & 0x3E) << 10); - //if (VdpDebug) - //Log.Note("VDP", "SET NTa W = {0:X4}", NameTableAddrWindow); - break; - - case 0x04: // Name Table Address for Layer B - NameTableAddrB = (ushort)(data << 13); - //if (VdpDebug) - //Log.Note("VDP", "SET NTa B = {0:X4}", NameTableAddrB); - break; - - case 0x05: // Sprite Attribute Table Address - SpriteAttributeTableAddr = (ushort)(data << 9); - //if (VdpDebug) - //Log.Note("VDP", "SET SAT attr = {0:X4}", SpriteAttributeTableAddr); - break; - - case 0x0A: // H Interrupt Register - //if (VdpDebug) - //Log.Note("VDP", "HInt occurs every {0} lines.", data); - break; - - case 0x0B: // VScroll/HScroll modes - //if (VdpDebug) - //{ - // 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!!! But it'll work."); break; - // case 2: Log.Note("VDP", "HScroll every 1 cell"); break; - // case 3: Log.Note("VDP", "HScroll every line"); break; - // } - //} - break; - - case 0x0C: // Mode Set #4 - // TODO interlaced modes - if ((data & 0x81) == 0) - { - // Display is 32 cells wide - if (DisplayWidth != 32) - { - FrameBuffer = new int[256 * 224]; - FrameWidth = 256; - DisplayWidth = 32; - SpriteLimit = 64; - SpritePerLineLimit = 16; - DotsPerLineLimit = 256; - } - } - else - { - // Display is 40 cells wide - if (DisplayWidth != 40) - { - FrameBuffer = new int[320 * 224]; - FrameWidth = 320; - DisplayWidth = 40; - SpriteLimit = 80; - SpritePerLineLimit = 20; - DotsPerLineLimit = 320; - } - } - break; - - case 0x0D: // H Scroll Table Address - HScrollTableAddr = (ushort)(data << 10); - //if (VdpDebug) - //Log.Note("VDP", "SET HScrollTab attr = {0:X4}", HScrollTableAddr); - break; - - case 0x0F: // Auto Address Register Increment - //if (VdpDebug) - //Log.Note("VDP", "Set Data Increment to " + data); - break; - - case 0x10: // Nametable Dimensions - switch (data & 0x03) - { - case 0: NameTableWidth = 32; break; - case 1: NameTableWidth = 64; break; - case 2: NameTableWidth = 32; break; // invalid setting - case 3: NameTableWidth = 128; break; - } - switch ((data >> 4) & 0x03) - { - case 0: NameTableHeight = 32; break; - case 1: NameTableHeight = 64; break; - case 2: NameTableHeight = 32; break; // invalid setting - case 3: NameTableHeight = 128; break; - } - break; - - case 0x11: // Window H Position - int whp = data & 31; - bool fromright = (data & 0x80) != 0; - //if (VdpDebug) - //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; - //if (VdpDebug) - //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; - } - - void ProcessPalette(int slot) - { - byte r = PalXlatTable[(CRAM[slot] & 0x000F) >> 0]; - byte g = PalXlatTable[(CRAM[slot] & 0x00F0) >> 4]; - byte b = PalXlatTable[(CRAM[slot] & 0x0F00) >> 8]; - Palette[slot] = Colors.ARGB(r, g, b); - } - - void UpdatePatternBuffer(int addr) - { - PatternBuffer[(addr * 2) + 1] = (byte)(VRAM[addr ^ 1] & 0x0F); - PatternBuffer[(addr * 2) + 0] = (byte)(VRAM[addr ^ 1] >> 4); - } - - public int[] GetVideoBuffer() - { - return FrameBuffer; - } - - public int VirtualWidth { get { return 320; } } - public int VirtualHeight { get { return FrameHeight; } } - - public int BufferWidth - { - get { return FrameWidth; } - } - - public int BufferHeight - { - get { return FrameHeight; } - } - - public int BackgroundColor - { - get { return Palette[Registers[7] & 0x3F]; } - } - - #region State Save/Load Code - - public void SaveStateText(TextWriter writer) - { - writer.WriteLine("[VDP]"); - - writer.Write("VRAM "); - VRAM.SaveAsHex(writer); - writer.Write("CRAM "); - CRAM.SaveAsHex(writer); - writer.Write("VSRAM "); - VSRAM.SaveAsHex(writer); - writer.Write("Registers "); - Registers.SaveAsHex(writer); - - writer.WriteLine("ControlWordPending {0}", ControlWordPending); - writer.WriteLine("DmaFillModePending {0}", DmaFillModePending); - writer.WriteLine("VdpDataAddr {0:X4}", VdpDataAddr); - writer.WriteLine("VdpDataCode {0}", VdpDataCode); - - writer.WriteLine("[/VDP]"); - } - - public void LoadStateText(TextReader reader) - { - while (true) - { - string[] args = reader.ReadLine().Split(' '); - if (args[0].Trim() == "") continue; - if (args[0] == "[/VDP]") break; - else if (args[0] == "VRAM") VRAM.ReadFromHex(args[1]); - else if (args[0] == "CRAM") CRAM.ReadFromHex(args[1]); - else if (args[0] == "VSRAM") VSRAM.ReadFromHex(args[1]); - else if (args[0] == "Registers") Registers.ReadFromHex(args[1]); - else if (args[0] == "ControlWordPending") ControlWordPending = bool.Parse(args[1]); - else if (args[0] == "DmaFillModePending") DmaFillModePending = bool.Parse(args[1]); - else if (args[0] == "VdpDataAddr") VdpDataAddr = ushort.Parse(args[1], NumberStyles.HexNumber); - else if (args[0] == "VdpDataCode") VdpDataCode = byte.Parse(args[1]); - else - Console.WriteLine("Skipping unrecognized identifier " + args[0]); - } - - for (int i = 0; i < CRAM.Length; i++) - ProcessPalette(i); - for (int i = 0; i < VRAM.Length; i++) - UpdatePatternBuffer(i); - for (int i = 0; i < Registers.Length; i++) - WriteVdpRegister(i, Registers[i]); - } - - public void SaveStateBinary(BinaryWriter writer) - { - writer.Write(VRAM); - writer.Write(CRAM); - writer.Write(VSRAM); - writer.Write(Registers); - - writer.Write(ControlWordPending); - writer.Write(DmaFillModePending); - writer.Write(VdpDataAddr); - writer.Write(VdpDataCode); - } - - public void LoadStateBinary(BinaryReader reader) - { - VRAM = reader.ReadBytes(VRAM.Length); - CRAM = reader.ReadUInt16s(CRAM.Length); - VSRAM = reader.ReadUInt16s(VSRAM.Length); - Registers = reader.ReadBytes(Registers.Length); - - ControlWordPending = reader.ReadBoolean(); - DmaFillModePending = reader.ReadBoolean(); - VdpDataAddr = reader.ReadUInt16(); - VdpDataCode = reader.ReadByte(); - - for (int i = 0; i < CRAM.Length; i++) - ProcessPalette(i); - for (int i = 0; i < VRAM.Length; i++) - UpdatePatternBuffer(i); - for (int i = 0; i < Registers.Length; i++) - WriteVdpRegister(i, Registers[i]); - } - - #endregion - } -} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/Genesis.IO.cs b/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/Genesis.IO.cs deleted file mode 100644 index e8233e54b3..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/Genesis.IO.cs +++ /dev/null @@ -1,132 +0,0 @@ -using BizHawk.Common; - -namespace BizHawk.Emulation.Cores.Sega.Genesis -{ - partial class Genesis - { - bool SegaCD = false; - - class IOPort - { - public byte Data; - public byte Control; - public byte TxData; - public byte RxData; - public byte SCtrl; - // TODO- a reference to connected device? That gets into the issue of configuring different types of controllers. :| - - public bool TH { get { return (Data & 0x40) != 0; } } - } - - IOPort[] IOPorts = new IOPort[] - { - new IOPort { Data = 0x7F, TxData = 0xFF, RxData = 0xFF, SCtrl = 0xFF }, - new IOPort { Data = 0x7F, TxData = 0xFF, RxData = 0xFF, SCtrl = 0xFF }, - new IOPort { Data = 0x7F, TxData = 0xFF, RxData = 0xFF, SCtrl = 0xFF } - }; - - byte ReadIO(int offset) - { - offset >>= 1; - offset &= 0x0F; - if (offset > 1) - Log.Note("CPU", "^^^ IO Read {0}: 00", offset); - switch (offset) - { - case 0: // version - byte value = (byte)(SegaCD ? 0x00 : 0x20); - switch ((char)RomData[0x01F0]) - { - case 'J': value |= 0x00; break; - case 'U': value |= 0x80; break; - case 'E': value |= 0xC0; break; - case 'A': value |= 0xC0; break; - case '4': value |= 0x80; break; - default: value |= 0x80; break; - } - //value |= 1; // US - Log.Note("CPU", "^^^ IO Read 0: {0:X2}", value); - return value; - case 1: // Port A - lagged = false; - ReadController(ref IOPorts[0].Data); - Log.Note("CPU", "^^^ IO Read 1: {0:X2}", IOPorts[0].Data); - return IOPorts[0].Data; - case 2: return 0xFF; - case 3: return 0xFF; - - case 0x04: return IOPorts[0].Control; - case 0x05: return IOPorts[1].Control; - case 0x06: return IOPorts[2].Control; - - case 0x07: return IOPorts[0].TxData; - case 0x08: return IOPorts[0].RxData; - case 0x09: return IOPorts[0].SCtrl; - - case 0x0A: return IOPorts[1].TxData; - case 0x0B: return IOPorts[1].RxData; - case 0x0C: return IOPorts[1].SCtrl; - - case 0x0D: return IOPorts[2].TxData; - case 0x0E: return IOPorts[2].RxData; - case 0x0F: return IOPorts[2].SCtrl; - } - Log.Note("CPU", "^^^ IO Read {0}: {1:X2}", offset, 0xFF); - return 0xFF; - } - - void WriteIO(int offset, int value) - { - offset >>= 1; - offset &= 0x0F; - - switch (offset) - { - case 0x00: break; - - case 0x01: IOPorts[0].Data = (byte)value; break; - case 0x02: IOPorts[1].Data = (byte)value; break; - case 0x03: IOPorts[2].Data = (byte)value; break; - - case 0x04: IOPorts[0].Control = (byte)value; break; - case 0x05: IOPorts[1].Control = (byte)value; break; - case 0x06: IOPorts[2].Control = (byte)value; break; - - case 0x07: IOPorts[0].TxData = (byte)value; break; - case 0x08: IOPorts[0].RxData = (byte)value; break; - case 0x09: IOPorts[0].SCtrl = (byte)value; break; - - case 0x0A: IOPorts[1].TxData = (byte)value; break; - case 0x0B: IOPorts[1].RxData = (byte)value; break; - case 0x0C: IOPorts[1].SCtrl = (byte)value; break; - - case 0x0D: IOPorts[2].TxData = (byte)value; break; - case 0x0E: IOPorts[2].RxData = (byte)value; break; - case 0x0F: IOPorts[2].SCtrl = (byte)value; break; - } - } - - void ReadController(ref byte data) - { - InputCallbacks.Call(); - data &= 0xC0; - if ((data & 0x40) != 0) // TH high - { - if (Controller.IsPressed("P1 Up") == false) data |= 0x01; - if (Controller.IsPressed("P1 Down") == false) data |= 0x02; - if (Controller.IsPressed("P1 Left") == false) data |= 0x04; - if (Controller.IsPressed("P1 Right") == false) data |= 0x08; - if (Controller.IsPressed("P1 B") == false) data |= 0x10; - if (Controller.IsPressed("P1 C") == false) data |= 0x20; - } - else - { // TH low - if (Controller.IsPressed("P1 Up") == false) data |= 0x01; - if (Controller.IsPressed("P1 Down") == false) data |= 0x02; - if (Controller.IsPressed("P1 A") == false) data |= 0x10; - if (Controller.IsPressed("P1 Start") == false) data |= 0x20; - } - - } - } -} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/Genesis.Input.cs b/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/Genesis.Input.cs deleted file mode 100644 index 890679d39e..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/Genesis.Input.cs +++ /dev/null @@ -1,20 +0,0 @@ -using BizHawk.Emulation.Common; - -namespace BizHawk.Emulation.Cores.Sega.Genesis -{ - partial class Genesis - { - public static readonly ControllerDefinition GenesisController = new ControllerDefinition - { - Name = "Genesis 3-Button Controller", - BoolButtons = - { - "Reset", - "P1 Up", "P1 Down", "P1 Left", "P1 Right", "P1 A", "P1 B", "P1 C", "P1 Start" - } - }; - - public ControllerDefinition ControllerDefinition { get { return GenesisController; } } - public IController Controller { private get; set; } - } -} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/Genesis.cs b/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/Genesis.cs deleted file mode 100644 index f20a97b41c..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/Genesis.cs +++ /dev/null @@ -1,495 +0,0 @@ -#define MUSASHI - -using System; -using System.Collections.Generic; -using System.IO; -using System.Runtime.InteropServices; - -using BizHawk.Common.BufferExtensions; - -using BizHawk.Emulation.Common; -using BizHawk.Emulation.Common.Components; -using BizHawk.Emulation.Cores.Components; -using BizHawk.Emulation.Cores.Components.M68000; -using BizHawk.Emulation.Cores.Components.Z80; -using Native68000; - -namespace BizHawk.Emulation.Cores.Sega.Genesis -{ - [CoreAttributes( - "GenesisHawk", - "Vecna", - isPorted: false, - isReleased: false - )] - public sealed partial class Genesis : IEmulator, ISaveRam, IStatable, IInputPollable - { - private int _lagcount = 0; - private bool lagged = true; - private bool islag = false; - - // ROM - public byte[] RomData; - - // Machine stuff - public MC68000 MainCPU; - public Z80A SoundCPU; - public GenVDP VDP; - public SN76489 PSG; - public YM2612 YM2612; - public byte[] Ram = new byte[0x10000]; - public byte[] Z80Ram = new byte[0x2000]; - - private bool M68000HasZ80Bus = false; - private bool Z80Reset = false; - private bool Z80Runnable { get { return (Z80Reset == false && M68000HasZ80Bus == false); } } - - private SoundMixer SoundMixer; - - [FeatureNotImplemented] - public IInputCallbackSystem InputCallbacks { get { throw new NotImplementedException(); } } - - public void ResetCounters() - { - Frame = 0; - _lagcount = 0; - islag = false; - } - - // Genesis timings: - // 53,693,175 Machine clocks / sec - // 7,670,454 Main 68000 cycles / sec (7 mclk divisor) - // 3,579,545 Z80 cycles / sec (15 mclk divisor) - - // At 59.92 FPS: - // 896,081 mclks / frame - // 128,011 Main 68000 cycles / frame - // 59,738 Z80 cycles / frame - - // At 262 lines/frame: - // 3420 mclks / line - // ~ 488.5 Main 68000 cycles / line - // 228 Z80 cycles / line - - // Video characteristics: - // 224 lines are active display. The remaining 38 lines are vertical blanking. - // In H40 mode, the dot clock is 480 pixels per line. - // 320 are active display, the remaining 160 are horizontal blanking. - // A total of 3420 mclks per line, but 2560 mclks are active display and 860 mclks are blanking. - -#if MUSASHI - VdpCallback _vdp; - ReadCallback read8; - ReadCallback read16; - ReadCallback read32; - WriteCallback write8; - WriteCallback write16; - WriteCallback write32; -#endif - - public Genesis(CoreComm comm, GameInfo game, byte[] rom) - { - ServiceProvider = new BasicServiceProvider(this); - CoreComm = comm; - MainCPU = new MC68000(); - SoundCPU = new Z80A(); - YM2612 = new YM2612() { MaxVolume = 23405 }; - PSG = new SN76489() { MaxVolume = 4681 }; - VDP = new GenVDP(); - VDP.DmaReadFrom68000 = ReadWord; - (ServiceProvider as BasicServiceProvider).Register(VDP); - SoundMixer = new SoundMixer(YM2612, PSG); - - MainCPU.ReadByte = ReadByte; - MainCPU.ReadWord = ReadWord; - MainCPU.ReadLong = ReadLong; - MainCPU.WriteByte = WriteByte; - MainCPU.WriteWord = WriteWord; - MainCPU.WriteLong = WriteLong; - MainCPU.IrqCallback = InterruptCallback; - - // ---------------------- musashi ----------------------- -#if MUSASHI - _vdp = vdpcallback; - read8 = Read8; - read16 = Read16; - read32 = Read32; - write8 = Write8; - write16 = Write16; - write32 = Write32; - - Musashi.RegisterVdpCallback(Marshal.GetFunctionPointerForDelegate(_vdp)); - Musashi.RegisterRead8(Marshal.GetFunctionPointerForDelegate(read8)); - Musashi.RegisterRead16(Marshal.GetFunctionPointerForDelegate(read16)); - Musashi.RegisterRead32(Marshal.GetFunctionPointerForDelegate(read32)); - Musashi.RegisterWrite8(Marshal.GetFunctionPointerForDelegate(write8)); - Musashi.RegisterWrite16(Marshal.GetFunctionPointerForDelegate(write16)); - Musashi.RegisterWrite32(Marshal.GetFunctionPointerForDelegate(write32)); -#endif - // ---------------------- musashi ----------------------- - - SoundCPU.ReadMemory = ReadMemoryZ80; - SoundCPU.WriteMemory = WriteMemoryZ80; - SoundCPU.WriteHardware = (a, v) => { Console.WriteLine("Z80: Attempt I/O Write {0:X2}:{1:X2}", a, v); }; - SoundCPU.ReadHardware = x => 0xFF; - SoundCPU.IRQCallback = () => SoundCPU.Interrupt = false; - Z80Reset = true; - RomData = new byte[0x400000]; - for (int i = 0; i < rom.Length; i++) - RomData[i] = rom[i]; - - SetupMemoryDomains(); -#if MUSASHI - Musashi.Init(); - Musashi.Reset(); - VDP.GetPC = () => Musashi.PC; -#else - MainCPU.Reset(); - VDP.GetPC = () => MainCPU.PC; -#endif - InitializeCartHardware(game); - } - - public IEmulatorServiceProvider ServiceProvider { get; private set; } - - void InitializeCartHardware(GameInfo game) - { - LogCartInfo(); - InitializeEeprom(game); - InitializeSaveRam(game); - } - - public void FrameAdvance(bool render, bool rendersound) - { - lagged = true; - Frame++; - PSG.BeginFrame(SoundCPU.TotalExecutedCycles); - YM2612.BeginFrame(SoundCPU.TotalExecutedCycles); - - // Do start-of-frame events - VDP.HIntLineCounter = VDP.Registers[10]; - //VDP.VdpStatusWord &= - unchecked { VDP.VdpStatusWord &= (ushort)~GenVDP.StatusVerticalBlanking; } - - for (VDP.ScanLine = 0; VDP.ScanLine < 262; VDP.ScanLine++) - { - //Log.Error("VDP","FRAME {0}, SCANLINE {1}", Frame, VDP.ScanLine); - - if (VDP.ScanLine < VDP.FrameHeight) - VDP.RenderLine(); - - Exec68k(365); - RunZ80(171); - - // H-Int now? - - VDP.HIntLineCounter--; - if (VDP.HIntLineCounter < 0 && VDP.ScanLine < 224) // FIXME - { - VDP.HIntLineCounter = VDP.Registers[10]; - VDP.VdpStatusWord |= GenVDP.StatusHorizBlanking; - - if (VDP.HInterruptsEnabled) - { - Set68kIrq(4); - //Console.WriteLine("Fire hint!"); - } - - } - - Exec68k(488 - 365); - RunZ80(228 - 171); - - if (VDP.ScanLine == 224) - { - VDP.VdpStatusWord |= GenVDP.StatusVerticalInterruptPending; - VDP.VdpStatusWord |= GenVDP.StatusVerticalBlanking; - Exec68k(16); // this is stupidly wrong. - // End-frame stuff - if (VDP.VInterruptEnabled) - Set68kIrq(6); - - SoundCPU.Interrupt = true; - //The INT output is asserted every frame for exactly one scanline, and it can't be disabled. A very short Z80 interrupt routine would be triggered multiple times if it finishes within 228 Z80 clock cycles. I think (but cannot recall the specifics) that some games have delay loops in the interrupt handler for this very reason. - } - } - PSG.EndFrame(SoundCPU.TotalExecutedCycles); - YM2612.EndFrame(SoundCPU.TotalExecutedCycles); - - - - if (lagged) - { - _lagcount++; - islag = true; - } - else - islag = false; - } - - void Exec68k(int cycles) - { -#if MUSASHI - Musashi.Execute(cycles); -#else - MainCPU.ExecuteCycles(cycles); -#endif - } - - void RunZ80(int cycles) - { - // I emulate the YM2612 synced to Z80 clock, for better or worse. - // So we still need to keep the Z80 cycle count accurate even if the Z80 isn't running. - - if (Z80Runnable) - SoundCPU.ExecuteCycles(cycles); - else - SoundCPU.TotalExecutedCycles += cycles; - } - - void Set68kIrq(int irq) - { -#if MUSASHI - Musashi.SetIRQ(irq); -#else - MainCPU.Interrupt = irq; -#endif - } - - public IDictionary GetCpuFlagsAndRegisters() - { - return new Dictionary - { - { "A-0", MainCPU.A[0].s32 }, - { "A-1", MainCPU.A[1].s32 }, - { "A-2", MainCPU.A[2].s32 }, - { "A-3", MainCPU.A[3].s32 }, - { "A-4", MainCPU.A[4].s32 }, - { "A-5", MainCPU.A[5].s32 }, - { "A-6", MainCPU.A[6].s32 }, - { "A-7", MainCPU.A[7].s32 }, - - { "D-0", MainCPU.D[0].s32 }, - { "D-1", MainCPU.D[1].s32 }, - { "D-2", MainCPU.D[2].s32 }, - { "D-3", MainCPU.D[3].s32 }, - { "D-4", MainCPU.D[4].s32 }, - { "D-5", MainCPU.D[5].s32 }, - { "D-6", MainCPU.D[6].s32 }, - { "D-7", MainCPU.D[7].s32 }, - - { "SR", MainCPU.SR }, - - { "Flag X", MainCPU.X }, - { "Flag N", MainCPU.N }, - { "Flag Z", MainCPU.Z }, - { "Flag V", MainCPU.V }, - { "Flag C", MainCPU.C } - }; - } - - int vdpcallback(int level) // Musashi handler - { - InterruptCallback(level); - return -1; - } - - void InterruptCallback(int level) - { - unchecked { VDP.VdpStatusWord &= (ushort)~GenVDP.StatusVerticalInterruptPending; } - } - - public CoreComm CoreComm { get; private set; } - - // TODO: Implement ISoundProvider - /* - public IAsyncSoundProvider SoundProvider - { - get { return SoundMixer; } - } - - public ISyncSoundProvider SyncSoundProvider { get { return new FakeSyncSound(SoundMixer, 735); } } - */ - - public int Frame { get; set; } - public int LagCount { get { return _lagcount; } set { _lagcount = value; } } - public bool IsLagFrame { get { return islag; } set { islag = value; } } - public bool DeterministicEmulation { get { return true; } } - public string SystemId { get { return "GEN"; } } - - public void SaveStateText(TextWriter writer) - { - var buf = new byte[141501 + SaveRAM.Length]; - var stream = new MemoryStream(buf); - var bwriter = new BinaryWriter(stream); - SaveStateBinary(bwriter); - - writer.WriteLine("Version 1"); - writer.Write("BigFatBlob "); - buf.SaveAsHex(writer); - - /*writer.WriteLine("[MegaDrive]"); - MainCPU.SaveStateText(writer, "Main68K"); - SoundCPU.SaveStateText(writer); - PSG.SaveStateText(writer); - VDP.SaveStateText(writer); - writer.WriteLine("Frame {0}", Frame); - writer.WriteLine("Lag {0}", _lagcount); - writer.WriteLine("IsLag {0}", islag); - writer.Write("MainRAM "); - Ram.SaveAsHex(writer); - writer.Write("Z80RAM "); - Z80Ram.SaveAsHex(writer); - writer.WriteLine("[/MegaDrive]");*/ - } - - public void LoadStateText(TextReader reader) - { - var buf = new byte[141501 + SaveRAM.Length]; - var version = reader.ReadLine(); - if (version != "Version 1") - throw new Exception("Not a valid state vesrion! sorry! your state is bad! Robust states will be added later!"); - var omgstate = reader.ReadLine().Split(' ')[1]; - buf.ReadFromHex(omgstate); - LoadStateBinary(new BinaryReader(new MemoryStream(buf))); - - /*while (true) - { - string[] args = reader.ReadLine().Split(' '); - if (args[0].Trim() == "") continue; - if (args[0] == "[MegaDrive]") continue; - if (args[0] == "[/MegaDrive]") break; - if (args[0] == "MainRAM") - Ram.ReadFromHex(args[1]); - else if (args[0] == "Z80RAM") - Z80Ram.ReadFromHex(args[1]); - else if (args[0] == "[Main68K]") - MainCPU.LoadStateText(reader, "Main68K"); - else if (args[0] == "[Z80]") - SoundCPU.LoadStateText(reader); - else if (args[0] == "Frame") - Frame = int.Parse(args[1]); - else if (args[0] == "Lag") - _lagcount = int.Parse(args[1]); - else if (args[0] == "IsLag") - islag = bool.Parse(args[1]); - else if (args[0] == "[PSG]") - PSG.LoadStateText(reader); - else if (args[0] == "[VDP]") - VDP.LoadStateText(reader); - else - Console.WriteLine("Skipping unrecognized identifier " + args[0]); - }*/ - } - - public void SaveStateBinary(BinaryWriter writer) - { - Musashi.SaveStateBinary(writer); // 124 - //SoundCPU.SaveStateBinary(writer); // 46 TODO fix this, there is no way to invoke this core from the UI for testing anyway. - //PSG.SaveStateBinary(writer); // 15 - VDP.SaveStateBinary(writer); // 65781 - YM2612.SaveStateBinary(writer); // 1785 - - writer.Write(Ram); // 65535 - writer.Write(Z80Ram); // 8192 - - writer.Write(Frame); // 4 - writer.Write(M68000HasZ80Bus); // 1 - writer.Write(Z80Reset); // 1 - writer.Write(BankRegion); // 4 - - for (int i = 0; i < 3; i++) - { - writer.Write(IOPorts[i].Data); - writer.Write(IOPorts[i].TxData); - writer.Write(IOPorts[i].RxData); - writer.Write(IOPorts[i].SCtrl); - } - - if (SaveRAM.Length > 0) - writer.Write(SaveRAM); - - // TODO: EEPROM/cart HW state - // TODO: lag counter crap - } - - public void LoadStateBinary(BinaryReader reader) - { - Musashi.LoadStateBinary(reader); - //SoundCPU.LoadStateBinary(reader); - //PSG.LoadStateBinary(reader); - VDP.LoadStateBinary(reader); - YM2612.LoadStateBinary(reader); - - Ram = reader.ReadBytes(Ram.Length); - Z80Ram = reader.ReadBytes(Z80Ram.Length); - - Frame = reader.ReadInt32(); - M68000HasZ80Bus = reader.ReadBoolean(); - Z80Reset = reader.ReadBoolean(); - BankRegion = reader.ReadInt32(); - - for (int i = 0; i < 3; i++) - { - IOPorts[i].Data = reader.ReadByte(); - IOPorts[i].TxData = reader.ReadByte(); - IOPorts[i].RxData = reader.ReadByte(); - IOPorts[i].SCtrl = reader.ReadByte(); - } - - if (SaveRAM.Length > 0) - SaveRAM = reader.ReadBytes(SaveRAM.Length); - } - - public byte[] SaveStateBinary() - { - var buf = new byte[141501 + SaveRAM.Length]; - var stream = new MemoryStream(buf); - var writer = new BinaryWriter(stream); - SaveStateBinary(writer); - //Console.WriteLine("buf len = {0}", stream.Position); - writer.Close(); - return buf; - } - - public bool BinarySaveStatesPreferred { get { return false; } } - - //MemoryDomainList memoryDomains; - - void SetupMemoryDomains() - { - /* - var domains = new List(3); - var MainMemoryDomain = new MemoryDomain("Main RAM", Ram.Length, MemoryDomain.Endian.Big, - addr => Ram[addr & 0xFFFF], - (addr, value) => Ram[addr & 0xFFFF] = value); - var Z80Domain = new MemoryDomain("Z80 RAM", Z80Ram.Length, MemoryDomain.Endian.Little, - addr => Z80Ram[addr & 0x1FFF], - (addr, value) => { Z80Ram[addr & 0x1FFF] = value; }); - - var VRamDomain = new MemoryDomain("Video RAM", VDP.VRAM.Length, MemoryDomain.Endian.Big, - addr => VDP.VRAM[addr & 0xFFFF], - (addr, value) => VDP.VRAM[addr & 0xFFFF] = value); - - var RomDomain = new MemoryDomain("MD CART", RomData.Length, MemoryDomain.Endian.Big, - addr => RomData[addr], //adelikat: For speed considerations, I didn't mask this, every tool that uses memory domains is smart enough not to overflow, if I'm wrong let me know! - (addr, value) => RomData[addr & (RomData.Length - 1)] = value); - - var SystemBusDomain = new MemoryDomain("System Bus", 0x1000000, MemoryDomain.Endian.Big, - addr => (byte)ReadByte((int)addr), - (addr, value) => Write8((uint)addr, (uint)value)); - - domains.Add(MainMemoryDomain); - domains.Add(Z80Domain); - domains.Add(VRamDomain); - domains.Add(RomDomain); - domains.Add(SystemBusDomain); - memoryDomains = new MemoryDomainList(domains); - (ServiceProvider as BasicServiceProvider).Register(memoryDomains); - */ - throw new NotImplementedException(); - } - - public void Dispose() { } - } -} diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/MemoryMap.68000.cs b/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/MemoryMap.68000.cs deleted file mode 100644 index 26d89235ad..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/MemoryMap.68000.cs +++ /dev/null @@ -1,254 +0,0 @@ -using System; - -namespace BizHawk.Emulation.Cores.Sega.Genesis -{ - partial class Genesis - { - public sbyte ReadByte(int address) - { - address &= 0x00FFFFFF; - - if (address < 0x200000) - return (sbyte)RomData[address]; - - if (address < 0x400000) - { - if (SaveRamEnabled && address >= SaveRamStartOffset && address < SaveRamEndOffset) - { - if (SaveRamEveryOtherByte) - return (sbyte)SaveRAM[(address - SaveRamStartOffset) >> 1]; - else - return (sbyte)SaveRAM[address - SaveRamStartOffset]; - } - return (sbyte)RomData[address]; - } - - if (address >= 0xE00000) - return (sbyte)Ram[address & 0xFFFF]; - - if (address == 0xA11100) // Z80 BUS status - { - //Console.WriteLine("QUERY z80 bus status. 68000 can access? " + (M68000HasZ80Bus && Z80Reset == false)); - return (sbyte)(M68000HasZ80Bus && Z80Reset == false ? 0 : 1); - } - - if (address >= 0xA10000 && address <= 0xA1001F) - return (sbyte)ReadIO(address); - - if ((address & 0xFF0000) == 0xA00000) - return (sbyte)ReadMemoryZ80((ushort)(address & 0x7FFF)); - - if (address >= 0xC00000 && address < 0xC00010) - { - //Console.WriteLine("byte-reading the VDP. someone is probably stupid."); - ushort value = VDP.ReadVdp(address & 0x0E); - if ((address & 1) == 0) // read MSB - return (sbyte)(value >> 8); - return (sbyte)value; // read LSB - } - - Console.WriteLine("UNHANDLED READB {0:X6}", address); - return 0x7D; - } - - public short ReadWord(int address) - { - address &= 0x00FFFFFF; - - int maskedAddr; - if (address < 0x400000) - return (short)((RomData[address] << 8) | RomData[address + 1]); - - if (address >= 0xE00000) // Work RAM - { - maskedAddr = address & 0xFFFE; - return (short)((Ram[maskedAddr] << 8) | Ram[maskedAddr + 1]); - } - - if (address >= 0xC00000 && address < 0xC00010) - return (short)VDP.ReadVdp(address & 0x0E); - - if (address >= 0xA10000 && address <= 0xA1001F) - return (sbyte)ReadIO(address); - - if (address == 0xA11100) // Z80 BUS status - return (short)(M68000HasZ80Bus && Z80Reset == false ? 0x0000 : 0x0100); - - Console.WriteLine("UNHANDLED READW {0:X6}", address); - return 0x7DCD; - } - - public int ReadLong(int address) - { - address &= 0x00FFFFFF; - - 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]; - } - - if (address >= 0xC00000) - { - //Console.WriteLine("long-read from VDP"); - short msw = ReadWord(address); - short msl = ReadWord(address + 2); - return (msw << 16) | (ushort)msl; - } - - // 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); - //return 0x7DCDCDCD; - } - - public void WriteByte(int address, sbyte value) - { - address &= 0x00FFFFFF; - - if (address >= 0xE00000) // Work RAM - { - //Console.WriteLine("MEM[{0:X4}] change from {1:X2} to {2:X2}", address & 0xFFFF, Ram[address & 0xFFFF], value); - Ram[address & 0xFFFF] = (byte)value; - return; - } - if ((address & 0xFF0000) == 0xA00000) - { - WriteMemoryZ80((ushort)(address & 0x7FFF), (byte)value); - return; - } - if (address >= 0xA10000 && address <= 0xA1001F) - { - WriteIO(address, value); - return; - } - if (address == 0xA11100) - { - M68000HasZ80Bus = (value & 1) != 0; - //Console.WriteLine("68000 has the z80 bus: " + M68000HasZ80Bus); - return; - } - if (address == 0xA11200) // Z80 RESET - { - Z80Reset = (value & 1) == 0; - if (Z80Reset) - SoundCPU.SoftReset(); - //Console.WriteLine("z80 reset: " + Z80Reset); - return; - } - if (address >= 0xC00000 && address < 0xC00010) - { - // when writing to VDP in byte mode, the LSB is duplicated into the MSB - VDP.WriteVdp(address & 0x1E, (ushort)((ushort)value | ((ushort)value << 8))); - return; - } - if (address >= 0xC00011 && address <= 0xC00017 && (address & 1) != 0) - { - PSG.WritePsgData((byte)value, SoundCPU.TotalExecutedCycles); - return; - } - - if (SaveRamEnabled && address >= SaveRamStartOffset && address < SaveRamEndOffset) - { - if (SaveRamEveryOtherByte) - SaveRAM[(address - SaveRamStartOffset) >> 1] = (byte)value; - else - SaveRAM[address - SaveRamStartOffset] = (byte)value; - - SaveRamModified = true; - return; - } - - if (EepromEnabled && (address == SclAddr || address == SdaInAddr)) - { - WriteByteEeprom(address, (byte)value); - return; - - } - - Console.WriteLine("UNHANDLED WRITEB {0:X6}:{1:X2}", address, value); - } - - public void WriteWord(int address, short value) - { - address &= 0x00FFFFFF; - - if (address >= 0xE00000) // Work RAM - { - //Console.WriteLine("MEM[{0:X4}] change to {1:X4}", address & 0xFFFF, value); - Ram[(address & 0xFFFF) + 0] = (byte)(value >> 8); - Ram[(address & 0xFFFF) + 1] = (byte)value; - return; - } - if (address >= 0xC00000) - { - switch (address & 0x1F) - { - case 0x00: - case 0x02: - VDP.WriteVdpData((ushort)value); - return; - case 0x04: - case 0x06: - VDP.WriteVdpControl((ushort)value); - return; - } - } - if (address == 0xA11100) // Z80 BUSREQ - { - M68000HasZ80Bus = (value & 0x100) != 0; - //Console.WriteLine("68000 has the z80 bus: " + M68000HasZ80Bus); - return; - } - if (address == 0xA11200) // Z80 RESET - { - Z80Reset = (value & 0x100) == 0; - if (Z80Reset) - SoundCPU.SoftReset(); - //Console.WriteLine("z80 reset: " + Z80Reset); - return; - } - Console.WriteLine("UNHANDLED WRITEW {0:X6}:{1:X4}", address, value); - } - - public void WriteLong(int address, int value) - { - address &= 0x00FFFFFF; - - if (address >= 0xE00000) // Work RAM - { - //Console.WriteLine("MEM[{0:X4}] change to {1:X8}", address & 0xFFFF, value); - Ram[(address & 0xFFFF) + 0] = (byte)(value >> 24); - Ram[(address & 0xFFFF) + 1] = (byte)(value >> 16); - Ram[(address & 0xFFFF) + 2] = (byte)(value >> 8); - Ram[(address & 0xFFFF) + 3] = (byte)value; - return; - } - if (address >= 0xC00000) - { - WriteWord(address, (short)(value >> 16)); - WriteWord(address + 2, (short)value); - return; - } - - Console.WriteLine("UNHANDLED WRITEL {0:X6}:{1:X8}", address, value); - } - - // Mushashi interop test stuff. TODO kill this when we're ready to ditch musashi. - - public uint Read8(uint a) { /*Console.WriteLine("read8 {0:X}", a);*/ return (uint)ReadByte((int)a) & 0xFF; } - public uint Read16(uint a) { /*Console.WriteLine("read16 {0:X}", a);*/ return (uint)ReadWord((int)a) & 0xFFFF; } - public uint Read32(uint a) { /*Console.WriteLine("read32 {0:X}", a);*/ return (uint)ReadLong((int)a); } - public void Write8(uint a, uint v) { /*Console.WriteLine("write8 {0:X}:{1:X2}", a, v);*/ WriteByte((int)a, (sbyte)v); } - public void Write16(uint a, uint v) { /*Console.WriteLine("write16 {0:X}:{1:X4}", a, v);*/ WriteWord((int)a, (short)v); } - public void Write32(uint a, uint v) { /*Console.WriteLine("write32 {0:X}:{1:X8}", a, v);*/ WriteLong((int)a, (int)v); } - } -} diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/MemoryMap.Z80.cs b/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/MemoryMap.Z80.cs deleted file mode 100644 index 51cacdacc8..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/MemoryMap.Z80.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; - -namespace BizHawk.Emulation.Cores.Sega.Genesis -{ - partial class Genesis - { - private int BankRegion; - - public byte ReadMemoryZ80(ushort address) - { - if (address < 0x4000) - { - //Console.WriteLine("read z80 memory {0:X4}: {1:X2}",address, Z80Ram[address & 0x1FFF]); - return Z80Ram[address & 0x1FFF]; - } - if (address >= 0x4000 && address < 0x6000) - { - //Console.WriteLine(" === Z80 READS FM STATUS ==="); - return YM2612.ReadStatus(SoundCPU.TotalExecutedCycles); // 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; - } - - public void WriteMemoryZ80(ushort address, byte value) - { - if (address < 0x4000) - { - //Console.WriteLine("write z80 memory {0:X4}: {1:X2}",address, value); - Z80Ram[address & 0x1FFF] = value; - return; - } - if (address >= 0x4000 && address < 0x6000) - { - //Console.WriteLine(" === Z80 WRITES YM2612 {0:X4}:{1:X2} ===",address, value); - YM2612.Write(address & 3, value, SoundCPU.TotalExecutedCycles); - return; - } - if (address < 0x6100) - { - BankRegion >>= 1; - BankRegion |= (value & 1) << 23; - BankRegion &= 0x00FF8000; - //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); - return; - } - Console.WriteLine("UNHANDLED Z80 WRITE {0:X4}:{1:X2}", address, value); - } - } -} diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/Native68000/Musashi.cs b/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/Native68000/Musashi.cs deleted file mode 100644 index 6493555494..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/Native68000/Musashi.cs +++ /dev/null @@ -1,92 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using System.IO; - -namespace Native68000 -{ - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate int VdpCallback(int i); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate uint ReadCallback(uint a); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate void WriteCallback(uint a, uint v); - - public class Musashi - { - [DllImport("MusashiDLL.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern void RegisterVdpCallback(IntPtr callback); - - [DllImport("MusashiDLL.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern void RegisterRead8(IntPtr callback); - - [DllImport("MusashiDLL.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern void RegisterRead16(IntPtr callback); - - [DllImport("MusashiDLL.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern void RegisterRead32(IntPtr callback); - - [DllImport("MusashiDLL.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern void RegisterWrite8(IntPtr callback); - - [DllImport("MusashiDLL.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern void RegisterWrite16(IntPtr callback); - - [DllImport("MusashiDLL.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern void RegisterWrite32(IntPtr callback); - - [DllImport("MusashiDLL.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern void Init(); - - [DllImport("MusashiDLL.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern void Reset(); - - [DllImport("MusashiDLL.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern void SetIRQ(int level); - - [DllImport("MusashiDLL.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern int Execute(int cycles); - - [DllImport("MusashiDLL.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern int QueryCpuState(int regcode); - - [DllImport("MusashiDLL.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern void SetCpuState(int regcode, int value); - - [DllImport("MusashiDLL.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern int GetCyclesRemaining(); - - public static int D0 { get { return QueryCpuState(0); } } - public static int D1 { get { return QueryCpuState(1); } } - public static int D2 { get { return QueryCpuState(2); } } - public static int D3 { get { return QueryCpuState(3); } } - public static int D4 { get { return QueryCpuState(4); } } - public static int D5 { get { return QueryCpuState(5); } } - public static int D6 { get { return QueryCpuState(6); } } - public static int D7 { get { return QueryCpuState(7); } } - - public static int A0 { get { return QueryCpuState(8); } } - public static int A1 { get { return QueryCpuState(9); } } - public static int A2 { get { return QueryCpuState(10); } } - public static int A3 { get { return QueryCpuState(11); } } - public static int A4 { get { return QueryCpuState(12); } } - public static int A5 { get { return QueryCpuState(13); } } - public static int A6 { get { return QueryCpuState(14); } } - public static int A7 { get { return QueryCpuState(15); } } - - public static int PC { get { return QueryCpuState(16); } } - public static int SR { get { return QueryCpuState(17); } } - public static int SP { get { return QueryCpuState(18); } } - - public static void SaveStateBinary(BinaryWriter writer) - { - for (int i=0; i<31; i++) - writer.Write(QueryCpuState(i)); - } - - public static void LoadStateBinary(BinaryReader reader) - { - for (int i = 0; i < 31; i++) - SetCpuState(i, reader.ReadInt32()); - } - } -} \ No newline at end of file