From c1556de4a42c46120165e5f2ebd0ff39205b4e77 Mon Sep 17 00:00:00 2001 From: saxxonpike Date: Sat, 17 Nov 2012 06:03:44 +0000 Subject: [PATCH] commodore64: work begins on alternate VIC emulation --- BizHawk.Emulation/BizHawk.Emulation.csproj | 3 + .../Computers/Commodore64/VicIINew.cs | 52 + .../Computers/Commodore64/VicIINewPipeline.cs | 1103 +++++++++++++++++ .../Computers/Commodore64/VicIIRegs.cs | 578 +++++++++ 4 files changed, 1736 insertions(+) create mode 100644 BizHawk.Emulation/Computers/Commodore64/VicIINew.cs create mode 100644 BizHawk.Emulation/Computers/Commodore64/VicIINewPipeline.cs create mode 100644 BizHawk.Emulation/Computers/Commodore64/VicIIRegs.cs diff --git a/BizHawk.Emulation/BizHawk.Emulation.csproj b/BizHawk.Emulation/BizHawk.Emulation.csproj index 392d373929..b95534ff48 100644 --- a/BizHawk.Emulation/BizHawk.Emulation.csproj +++ b/BizHawk.Emulation/BizHawk.Emulation.csproj @@ -103,6 +103,9 @@ + + + diff --git a/BizHawk.Emulation/Computers/Commodore64/VicIINew.cs b/BizHawk.Emulation/Computers/Commodore64/VicIINew.cs new file mode 100644 index 0000000000..bc3108b929 --- /dev/null +++ b/BizHawk.Emulation/Computers/Commodore64/VicIINew.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace BizHawk.Emulation.Computers.Commodore64 +{ + public struct VicIIDataGenerator + { + + } + + public struct VicIISpriteGenerator + { + + } + + public partial class VicIINew + { + public Memory mem; + public Region region; + public ChipSignals signal; + + public VicIINew(ChipSignals newSignal, Region newRegion) + { + region = newRegion; + signal = newSignal; + HardReset(); + InitPipeline(newRegion); + } + + public void HardReset() + { + InitRegs(); + cycle = 0; + } + + public bool Interrupt + { + get + { + return IRQ; + } + } + + public void PerformCycle() + { + ExecutePipeline(); + } + + } +} diff --git a/BizHawk.Emulation/Computers/Commodore64/VicIINewPipeline.cs b/BizHawk.Emulation/Computers/Commodore64/VicIINewPipeline.cs new file mode 100644 index 0000000000..0da8b00a47 --- /dev/null +++ b/BizHawk.Emulation/Computers/Commodore64/VicIINewPipeline.cs @@ -0,0 +1,1103 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace BizHawk.Emulation.Computers.Commodore64 +{ + public partial class VicIINew + { + private int cycle; + private Action[][] pipeline; + private int pipelineLength; + + private void ExecutePipeline() + { + foreach (Action a in pipeline[cycle++]) + a(); + + if (cycle >= pipelineLength) + cycle = 0; + } + + private void InitPipeline(Region region) + { + switch (region) + { + case Region.NTSC: + rasterLines = 263; + rasterLeft = 0x19C; + pipeline = new Action[][] + { + new Action[] + { // 0 + PipelineScan, + PipelineIRQ0, + PipelineFetchSprite3P, + PipelineRender + }, + new Action[] + { // 1 + PipelineScan, + PipelineIRQ1, + PipelineFetchSprite3S, + PipelineRender + }, + new Action[] + { // 2 + PipelineScan, + PipelineFetchSprite4P, + PipelineRender + }, + new Action[] + { // 3 + PipelineScan, + PipelineFetchSprite4S, + PipelineRender + }, + new Action[] + { // 4 + PipelineScan, + PipelineFetchSprite5P, + PipelineRender + }, + new Action[] + { // 5 + PipelineScan, + PipelineFetchSprite5S, + PipelineRender + }, + new Action[] + { // 6 + PipelineScan, + PipelineFetchSprite6P, + PipelineRender + }, + new Action[] + { // 7 + PipelineScan, + PipelineFetchSprite6S, + PipelineRender + }, + new Action[] + { // 8 + PipelineScan, + PipelineFetchSprite7P, + PipelineRender + }, + new Action[] + { // 9 + PipelineScan, + PipelineFetchSprite7S, + PipelineRender + }, + new Action[] + { // 10 + PipelineScan, + PipelineDramRefresh, + PipelineRender + }, + new Action[] + { // 11 + PipelineScan, + PipelineDramRefresh, + PipelineRender + }, + new Action[] + { // 12 + PipelineScan, + PipelineDramRefresh, + PipelineRender + }, + new Action[] + { // 13 + PipelineScan, + PipelineVCReset, + PipelineDramRefresh, + PipelineRender + }, + new Action[] + { // 14 + PipelineScan, + PipelineDramRefresh, + PipelineRender + }, + new Action[] + { // 15 + PipelineScan, + PipelineSpriteMCBASEAdvance, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 16 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 17 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 18 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 19 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 20 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 21 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 22 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 23 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 24 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 25 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 26 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 27 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 28 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 29 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 30 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 31 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 32 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 33 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 34 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 35 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 36 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 37 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 38 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 39 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 40 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 41 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 42 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 43 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 44 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 45 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 46 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 47 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 48 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 49 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 50 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 51 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 52 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 53 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 54 + PipelineScan, + PipelineFetchC, + PipelineSpriteMYEFlip, + PipelineSpriteEnable0, + PipelineRender + }, + new Action[] + { // 55 + PipelineScan, + PipelineSpriteEnable1, + PipelineIdle, + PipelineRender + }, + new Action[] + { // 56 + PipelineScan, + PipelineIdle, + PipelineRender + }, + new Action[] + { // 57 + PipelineScan, + PipelineSpriteDMA, + PipelineRCReset, + PipelineIdle, + PipelineRender + }, + new Action[] + { // 58 + PipelineScan, + PipelineIdle, + PipelineRender + }, + new Action[] + { // 59 + PipelineScan, + PipelineFetchSprite0P, + PipelineRender + }, + new Action[] + { // 60 + PipelineScan, + PipelineFetchSprite0S, + PipelineRender + }, + new Action[] + { // 61 + PipelineScan, + PipelineFetchSprite1P, + PipelineRender + }, + new Action[] + { // 62 + PipelineScan, + PipelineFetchSprite1S, + PipelineBorderCheck, + PipelineRender + }, + new Action[] + { // 63 + PipelineScan, + PipelineFetchSprite2P, + PipelineRender + }, + new Action[] + { // 64 + PipelineScan, + PipelineFetchSprite2S, + PipelineRender + }, + }; + break; + case Region.PAL: + rasterLines = 312; + rasterLeft = 0x194; + pipeline = new Action[][] + { + new Action[] + { // 0 + PipelineScan, + PipelineIRQ0, + PipelineFetchSprite3P, + PipelineRender + }, + new Action[] + { // 1 + PipelineScan, + PipelineIRQ1, + PipelineFetchSprite3S, + PipelineRender + }, + new Action[] + { // 2 + PipelineScan, + PipelineFetchSprite4P, + PipelineRender + }, + new Action[] + { // 3 + PipelineScan, + PipelineFetchSprite4S, + PipelineRender + }, + new Action[] + { // 4 + PipelineScan, + PipelineFetchSprite5P, + PipelineRender + }, + new Action[] + { // 5 + PipelineScan, + PipelineFetchSprite5S, + PipelineRender + }, + new Action[] + { // 6 + PipelineScan, + PipelineFetchSprite6P, + PipelineRender + }, + new Action[] + { // 7 + PipelineScan, + PipelineFetchSprite6S, + PipelineRender + }, + new Action[] + { // 8 + PipelineScan, + PipelineFetchSprite7P, + PipelineRender + }, + new Action[] + { // 9 + PipelineScan, + PipelineFetchSprite7S, + PipelineRender + }, + new Action[] + { // 10 + PipelineScan, + PipelineDramRefresh, + PipelineRender + }, + new Action[] + { // 11 + PipelineScan, + PipelineDramRefresh, + PipelineRender + }, + new Action[] + { // 12 + PipelineScan, + PipelineDramRefresh, + PipelineRender + }, + new Action[] + { // 13 + PipelineScan, + PipelineVCReset, + PipelineDramRefresh, + PipelineRender + }, + new Action[] + { // 14 + PipelineScan, + PipelineDramRefresh, + PipelineRender + }, + new Action[] + { // 15 + PipelineScan, + PipelineSpriteMCBASEAdvance, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 16 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 17 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 18 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 19 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 20 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 21 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 22 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 23 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 24 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 25 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 26 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 27 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 28 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 29 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 30 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 31 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 32 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 33 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 34 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 35 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 36 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 37 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 38 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 39 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 40 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 41 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 42 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 43 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 44 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 45 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 46 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 47 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 48 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 49 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 50 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 51 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 52 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 53 + PipelineScan, + PipelineFetchC, + PipelineRender + }, + new Action[] + { // 54 + PipelineScan, + PipelineFetchC, + PipelineSpriteMYEFlip, + PipelineSpriteEnable0, + PipelineRender + }, + new Action[] + { // 55 + PipelineScan, + PipelineSpriteEnable1, + PipelineIdle, + PipelineRender + }, + new Action[] + { // 56 + PipelineScan, + PipelineIdle, + PipelineRender + }, + new Action[] + { // 57 + PipelineScan, + PipelineSpriteDMA, + PipelineRCReset, + PipelineFetchSprite0P, + PipelineRender + }, + new Action[] + { // 58 + PipelineScan, + PipelineFetchSprite0S, + PipelineRender + }, + new Action[] + { // 59 + PipelineScan, + PipelineFetchSprite1P, + PipelineRender + }, + new Action[] + { // 60 + PipelineScan, + PipelineFetchSprite1S, + PipelineRender + }, + new Action[] + { // 61 + PipelineScan, + PipelineFetchSprite2P, + PipelineRender + }, + new Action[] + { // 62 + PipelineScan, + PipelineFetchSprite2S, + PipelineBorderCheck, + PipelineRender + } + }; + break; + } + + pipelineLength = pipeline.Length; + } + + private void PipelineBorderCheck() + { + if ((RASTER == borderTop) && (DEN)) + borderOnVertical = false; + if (RASTER == borderBottom) + borderOnVertical = true; + } + + private void PipelineDramRefresh() + { + mem.VicRead((ushort)refreshAddress); + refreshAddress = (refreshAddress - 1) & 0xFF; + refreshAddress |= 0x3F00; + } + + private void PipelineFetchC() + { + int cAddress = (VM << 10) | VC; + characterDataBus = mem.VicRead((ushort)cAddress); + colorDataBus = mem.colorRam[VC]; + } + + private void PipelineFetchCIdle() + { + characterDataBus = 0; + colorDataBus = 0; + } + + private void PipelineFetchG() + { + switch (graphicsMode) + { + case 0: // 000 + case 1: // 001 + PipelineFetchG000(); + break; + case 2: // 010 + case 3: // 011 + PipelineFetchG010(); + break; + case 4: // 100 + case 5: // 101 + PipelineFetchG100(); + break; + case 6: // 110 + case 7: // 111 + PipelineFetchG110(); + break; + } + } + + private void PipelineFetchG000() + { + int gAddress = (CB << 11) | (characterData << 3) | RC; + bitmapData = mem.VicRead((ushort)gAddress); + } + + private void PipelineFetchG010() + { + int gAddress = ((CB & 0x4) << 11) | (VC << 3) | RC; + bitmapData = mem.VicRead((ushort)gAddress); + } + + private void PipelineFetchG100() + { + int gAddress = (CB << 11) | ((characterData & 0x3F) << 3) | RC; + bitmapData = mem.VicRead((ushort)gAddress); + } + + private void PipelineFetchG110() + { + int gAddress = ((CB & 0x4) << 11) | ((VC & 0x33F) << 3) | RC; + bitmapData = mem.VicRead((ushort)gAddress); + } + + private void PipelineFetchGIdle() + { + mem.VicRead(ECM ? (ushort)0x39FF : (ushort)0x3FFF); + } + + private void PipelineFetchSprite0P() + { + PipelineFetchSpriteP(0); + } + + private void PipelineFetchSprite0S() + { + PipelineFetchSpriteS(0); + } + + private void PipelineFetchSprite1P() + { + PipelineFetchSpriteP(1); + } + + private void PipelineFetchSprite1S() + { + PipelineFetchSpriteS(1); + } + + private void PipelineFetchSprite2P() + { + PipelineFetchSpriteP(2); + } + + private void PipelineFetchSprite2S() + { + PipelineFetchSpriteS(2); + } + + private void PipelineFetchSprite3P() + { + PipelineFetchSpriteP(3); + } + + private void PipelineFetchSprite3S() + { + PipelineFetchSpriteS(3); + } + + private void PipelineFetchSprite4P() + { + PipelineFetchSpriteP(4); + } + + private void PipelineFetchSprite4S() + { + PipelineFetchSpriteS(4); + } + + private void PipelineFetchSprite5P() + { + PipelineFetchSpriteP(5); + } + + private void PipelineFetchSprite5S() + { + PipelineFetchSpriteS(5); + } + + private void PipelineFetchSprite6P() + { + PipelineFetchSpriteP(6); + } + + private void PipelineFetchSprite6S() + { + PipelineFetchSpriteS(6); + } + + private void PipelineFetchSprite7P() + { + PipelineFetchSpriteP(7); + } + + private void PipelineFetchSprite7S() + { + PipelineFetchSpriteS(7); + } + + private void PipelineFetchSpriteP(int index) + { + ushort pointerOffset = (ushort)((VM << 10) | 0x3F8 | index); + sprites[index].MPTR = mem.VicRead(pointerOffset); + + if (sprites[index].MDMA) + { + sprites[index].MSRC = 24; + sprites[index].MSR = mem.VicRead((ushort)((sprites[index].MPTR << 6) | (sprites[index].MC))); + sprites[index].MC++; + } + + signal.VicAEC = !sprites[index].MDMA; + } + + private void PipelineFetchSpriteS(int index) + { + if (sprites[index].MDMA) + { + for (int i = 0; i < 2; i++) + { + sprites[index].MSR <<= 8; + sprites[index].MSR |= mem.VicRead((ushort)((sprites[index].MPTR << 6) | (sprites[index].MC))); + sprites[index].MC++; + } + } + + signal.VicAEC = !sprites[index].MDMA; + } + + private void PipelineIdle() + { + } + + private void PipelineIRQ0() + { + } + + private void PipelineIRQ1() + { + } + + private void PipelinePlot000() + { + } + + private void PipelinePlot001() + { + } + + private void PipelinePlot010() + { + } + + private void PipelinePlot011() + { + } + + private void PipelinePlot100() + { + } + + private void PipelinePlot101() + { + } + + private void PipelinePlot110() + { + } + + private void PipelinePlot111() + { + } + private void PipelineRCReset() + { + } + + private void PipelineRender() + { + } + + private void PipelineScan() + { + } + + private void PipelineSpriteDMA() + { + } + + private void PipelineSpriteEnable0() + { + } + + private void PipelineSpriteEnable1() + { + } + + private void PipelineSpriteMCBASEAdvance() + { + } + + private void PipelineSpriteMYEFlip() + { + } + + private void PipelineVCReset() + { + } + } +} diff --git a/BizHawk.Emulation/Computers/Commodore64/VicIIRegs.cs b/BizHawk.Emulation/Computers/Commodore64/VicIIRegs.cs new file mode 100644 index 0000000000..6ba43ca9c6 --- /dev/null +++ b/BizHawk.Emulation/Computers/Commodore64/VicIIRegs.cs @@ -0,0 +1,578 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace BizHawk.Emulation.Computers.Commodore64 +{ + public partial class VicIINew + { + private class VicIINewSprite + { + // internal regs + public int MC; + public int MCBASE; + public bool MDMA; + public int MPTR; + public int MSR; + public int MSRC; + + // external regs + public int MxC; // sprite color + public bool MxD; // sprite-data collision + public bool MxDP; // sprite priority + public bool MxE; // sprite enabled + public bool MxM; // sprite-sprite collision + public bool MxMC; // sprite multicolor + public int MxX; // sprite X coordinate + public bool MxXE; // sprite X expansion + public int MxY; // sprite Y coordinate + public bool MxYE; // sprite Y expansion + } + + // internal regs + private int RC; + private int VC; + private int VMLI; + + // external regs + private bool BMM; // bitmap mode + private int[] BxC = new int[4]; // background colors + private int CB; // character bitmap offset + private bool CSEL; // column select + private bool DEN; // display enabled + private int EC; // border color + private bool ECM; // extra color mode + private bool ELP; // enable lightpen interrupt + private bool EMBC; // enable sprite-data interrupt + private bool EMMC; // enable sprite-sprite interrupt + private bool ERST; // enable raster line interrupt + private bool ILP; // light pen interrupt active + private bool IMBC; // sprite-data interrupt active + private bool IMMC; // sprite-sprite interrupt active + private bool IRQ; // interrupt was triggered + private bool IRST; // raster line interrupt active + private int LPX; // lightpen X coordinate + private int LPY; // lightpen Y coordinate + private bool MCM; // multicolor mode + private int[] MMx = new int[2]; // sprite extra color + private int RASTER; // current raster line + private bool RES; // reset bit (does nothing in this version of the VIC) + private bool RSEL; // row select + private int VM; // video memory offset + private int XSCROLL; // X scroll position + private int YSCROLL; // Y scroll position + private VicIINewSprite[] sprites; + + private bool badline; + private byte bitmapData; + private int borderBottom; + private int borderLeft; + private bool borderOnMain; + private bool borderOnVertical; + private int borderRight; + private int borderTop; + private byte characterData; + private byte characterDataBus; + private byte[] characterMemory; + private byte colorData; + private byte colorDataBus; + private byte[] colorMemory; + private bool displayEnabled; + private int graphicsMode; + private int rasterInterruptLine; + private int rasterLeft; + private int rasterLines; + private int rasterWidth; + private int rasterX; + private int refreshAddress; + + private void InitRegs() + { + // reset regs + for (int i = 0; i < 0x40; i++) + this[i] = 0x00; + + // power on state + this[0x16] = 0xC0; + this[0x18] = 0x01; + this[0x19] = 0x71; + this[0x1A] = 0xF0; + + // init sprites + sprites = new VicIINewSprite[8]; + for (int i = 0; i < 8; i++) + sprites[i] = new VicIINewSprite(); + } + + private byte this[int addr] + { + get + { + int result = 0xFF; // value for any open bits + addr &= 0x3F; + + switch (addr) + { + case 0x00: + case 0x02: + case 0x04: + case 0x06: + case 0x08: + case 0x0A: + case 0x0C: + case 0x0E: + result = sprites[addr >> 1].MxX; + break; + case 0x01: + case 0x03: + case 0x05: + case 0x07: + case 0x09: + case 0x0B: + case 0x0D: + case 0x0F: + result = sprites[addr >> 1].MxY; + break; + case 0x10: + result = ((sprites[0].MxX & 0x100) != 0) ? 0x01 : 0x00; + result |= ((sprites[1].MxX & 0x100) != 0) ? 0x02 : 0x00; + result |= ((sprites[2].MxX & 0x100) != 0) ? 0x04 : 0x00; + result |= ((sprites[3].MxX & 0x100) != 0) ? 0x08 : 0x00; + result |= ((sprites[4].MxX & 0x100) != 0) ? 0x10 : 0x00; + result |= ((sprites[5].MxX & 0x100) != 0) ? 0x20 : 0x00; + result |= ((sprites[6].MxX & 0x100) != 0) ? 0x40 : 0x00; + result |= ((sprites[7].MxX & 0x100) != 0) ? 0x80 : 0x00; + break; + case 0x11: + result = YSCROLL & 0x07; + result |= (RSEL ? 0x08 : 0x00); + result |= (DEN ? 0x10 : 0x00); + result |= (BMM ? 0x20 : 0x00); + result |= (ECM ? 0x40 : 0x00); + result |= ((RASTER & 0x100) >> 1); + break; + case 0x12: + result = RASTER & 0xFF; + break; + case 0x13: + result = LPX; + break; + case 0x14: + result = LPY; + break; + case 0x15: + result = (sprites[0].MxE ? 0x01 : 0x00); + result |= (sprites[1].MxE ? 0x02 : 0x00); + result |= (sprites[2].MxE ? 0x04 : 0x00); + result |= (sprites[3].MxE ? 0x08 : 0x00); + result |= (sprites[4].MxE ? 0x10 : 0x00); + result |= (sprites[5].MxE ? 0x20 : 0x00); + result |= (sprites[6].MxE ? 0x40 : 0x00); + result |= (sprites[7].MxE ? 0x80 : 0x00); + break; + case 0x16: + result &= 0xC0; + result |= XSCROLL & 0x07; + result |= (CSEL ? 0x08 : 0x00); + result |= (MCM ? 0x10 : 0x00); + result |= (RES ? 0x20 : 0x00); + break; + case 0x17: + result = (sprites[0].MxYE ? 0x01 : 0x00); + result |= (sprites[1].MxYE ? 0x02 : 0x00); + result |= (sprites[2].MxYE ? 0x04 : 0x00); + result |= (sprites[3].MxYE ? 0x08 : 0x00); + result |= (sprites[4].MxYE ? 0x10 : 0x00); + result |= (sprites[5].MxYE ? 0x20 : 0x00); + result |= (sprites[6].MxYE ? 0x40 : 0x00); + result |= (sprites[7].MxYE ? 0x80 : 0x00); + break; + case 0x18: + result &= 0x01; + result |= (CB & 0x07) << 1; + result |= (VM & 0x0F) << 4; + break; + case 0x19: + result &= 0x70; + result |= (IRST ? 0x01 : 0x00); + result |= (IMBC ? 0x02 : 0x00); + result |= (IMMC ? 0x04 : 0x00); + result |= (ILP ? 0x08 : 0x00); + result |= (IRQ ? 0x80 : 0x00); + break; + case 0x1A: + result &= 0xF0; + result |= (ERST ? 0x01 : 0x00); + result |= (EMBC ? 0x02 : 0x00); + result |= (EMMC ? 0x04 : 0x00); + result |= (ELP ? 0x08 : 0x00); + break; + case 0x1B: + result = (sprites[0].MxDP ? 0x01 : 0x00); + result |= (sprites[1].MxDP ? 0x02 : 0x00); + result |= (sprites[2].MxDP ? 0x04 : 0x00); + result |= (sprites[3].MxDP ? 0x08 : 0x00); + result |= (sprites[4].MxDP ? 0x10 : 0x00); + result |= (sprites[5].MxDP ? 0x20 : 0x00); + result |= (sprites[6].MxDP ? 0x40 : 0x00); + result |= (sprites[7].MxDP ? 0x80 : 0x00); + break; + case 0x1C: + result = (sprites[0].MxMC ? 0x01 : 0x00); + result |= (sprites[1].MxMC ? 0x02 : 0x00); + result |= (sprites[2].MxMC ? 0x04 : 0x00); + result |= (sprites[3].MxMC ? 0x08 : 0x00); + result |= (sprites[4].MxMC ? 0x10 : 0x00); + result |= (sprites[5].MxMC ? 0x20 : 0x00); + result |= (sprites[6].MxMC ? 0x40 : 0x00); + result |= (sprites[7].MxMC ? 0x80 : 0x00); + break; + case 0x1D: + result = (sprites[0].MxXE ? 0x01 : 0x00); + result |= (sprites[1].MxXE ? 0x02 : 0x00); + result |= (sprites[2].MxXE ? 0x04 : 0x00); + result |= (sprites[3].MxXE ? 0x08 : 0x00); + result |= (sprites[4].MxXE ? 0x10 : 0x00); + result |= (sprites[5].MxXE ? 0x20 : 0x00); + result |= (sprites[6].MxXE ? 0x40 : 0x00); + result |= (sprites[7].MxXE ? 0x80 : 0x00); + break; + case 0x1E: + result = (sprites[0].MxM ? 0x01 : 0x00); + result |= (sprites[1].MxM ? 0x02 : 0x00); + result |= (sprites[2].MxM ? 0x04 : 0x00); + result |= (sprites[3].MxM ? 0x08 : 0x00); + result |= (sprites[4].MxM ? 0x10 : 0x00); + result |= (sprites[5].MxM ? 0x20 : 0x00); + result |= (sprites[6].MxM ? 0x40 : 0x00); + result |= (sprites[7].MxM ? 0x80 : 0x00); + break; + case 0x1F: + result = (sprites[0].MxD ? 0x01 : 0x00); + result |= (sprites[1].MxD ? 0x02 : 0x00); + result |= (sprites[2].MxD ? 0x04 : 0x00); + result |= (sprites[3].MxD ? 0x08 : 0x00); + result |= (sprites[4].MxD ? 0x10 : 0x00); + result |= (sprites[5].MxD ? 0x20 : 0x00); + result |= (sprites[6].MxD ? 0x40 : 0x00); + result |= (sprites[7].MxD ? 0x80 : 0x00); + break; + case 0x20: + result &= 0xF0; + result |= EC & 0x0F; + break; + case 0x21: + case 0x22: + case 0x23: + case 0x24: + result &= 0xF0; + result |= BxC[addr - 0x21] & 0x0F; + break; + case 0x25: + case 0x26: + result &= 0xF0; + result |= MMx[addr - 0x25] & 0x0F; + break; + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + result &= 0xF0; + result |= sprites[addr - 0x27].MxC & 0x0F; + break; + default: + result = 0xFF; + break; + } + + return (byte)(result); + } + set + { + int index; + int val = value; + addr &= 0x3F; + + switch (addr) + { + case 0x00: + case 0x02: + case 0x04: + case 0x06: + case 0x08: + case 0x0A: + case 0x0C: + case 0x0E: + index = addr >> 1; + sprites[index].MxX &= 0x100; + sprites[index].MxX |= (val & 0xFF); + break; + case 0x01: + case 0x03: + case 0x05: + case 0x07: + case 0x09: + case 0x0B: + case 0x0D: + case 0x0F: + index = addr >> 1; + sprites[index].MxY &= 0x100; + sprites[index].MxY |= (val & 0xFF); + break; + case 0x10: + sprites[0].MxX = (sprites[0].MxX & 0xFF) | ((val & 0x01) << 8); + sprites[1].MxX = (sprites[1].MxX & 0xFF) | ((val & 0x02) << 7); + sprites[2].MxX = (sprites[2].MxX & 0xFF) | ((val & 0x04) << 6); + sprites[3].MxX = (sprites[3].MxX & 0xFF) | ((val & 0x08) << 5); + sprites[4].MxX = (sprites[4].MxX & 0xFF) | ((val & 0x10) << 4); + sprites[5].MxX = (sprites[5].MxX & 0xFF) | ((val & 0x20) << 3); + sprites[6].MxX = (sprites[6].MxX & 0xFF) | ((val & 0x40) << 2); + sprites[7].MxX = (sprites[7].MxX & 0xFF) | ((val & 0x80) << 1); + break; + case 0x11: + YSCROLL = (val & 0x07); + RSEL = ((val & 0x08) != 0x00); + DEN = ((val & 0x10) != 0x00); + BMM = ((val & 0x20) != 0x00); + ECM = ((val & 0x40) != 0x00); + RASTER &= 0xFF; + RASTER |= ((val & 0x80) << 1); + break; + case 0x12: + RASTER &= 0x100; + RASTER |= (val & 0xFF); + break; + case 0x13: + LPX = (val & 0xFF); + break; + case 0x14: + LPY = (val & 0xFF); + break; + case 0x15: + sprites[0].MxE = ((val & 0x01) != 0x00); + sprites[1].MxE = ((val & 0x02) != 0x00); + sprites[2].MxE = ((val & 0x04) != 0x00); + sprites[3].MxE = ((val & 0x08) != 0x00); + sprites[4].MxE = ((val & 0x10) != 0x00); + sprites[5].MxE = ((val & 0x20) != 0x00); + sprites[6].MxE = ((val & 0x40) != 0x00); + sprites[7].MxE = ((val & 0x80) != 0x00); + break; + case 0x16: + XSCROLL = (val & 0x07); + CSEL = ((val & 0x08) != 0x00); + MCM = ((val & 0x10) != 0x00); + RES = ((val & 0x20) != 0x00); + break; + case 0x17: + sprites[0].MxYE = ((val & 0x01) != 0x00); + sprites[1].MxYE = ((val & 0x02) != 0x00); + sprites[2].MxYE = ((val & 0x04) != 0x00); + sprites[3].MxYE = ((val & 0x08) != 0x00); + sprites[4].MxYE = ((val & 0x10) != 0x00); + sprites[5].MxYE = ((val & 0x20) != 0x00); + sprites[6].MxYE = ((val & 0x40) != 0x00); + sprites[7].MxYE = ((val & 0x80) != 0x00); + break; + case 0x18: + CB = (val & 0x0E) >> 1; + VM = (val & 0xF0) >> 4; + break; + case 0x19: + IRST = ((val & 0x01) != 0x00); + IMBC = ((val & 0x02) != 0x00); + IMMC = ((val & 0x04) != 0x00); + ILP = ((val & 0x08) != 0x00); + break; + case 0x1A: + ERST = ((val & 0x01) != 0x00); + EMBC = ((val & 0x02) != 0x00); + EMMC = ((val & 0x04) != 0x00); + ELP = ((val & 0x08) != 0x00); + break; + case 0x1B: + sprites[0].MxDP = ((val & 0x01) != 0x00); + sprites[1].MxDP = ((val & 0x02) != 0x00); + sprites[2].MxDP = ((val & 0x04) != 0x00); + sprites[3].MxDP = ((val & 0x08) != 0x00); + sprites[4].MxDP = ((val & 0x10) != 0x00); + sprites[5].MxDP = ((val & 0x20) != 0x00); + sprites[6].MxDP = ((val & 0x40) != 0x00); + sprites[7].MxDP = ((val & 0x80) != 0x00); + break; + case 0x1C: + sprites[0].MxMC = ((val & 0x01) != 0x00); + sprites[1].MxMC = ((val & 0x02) != 0x00); + sprites[2].MxMC = ((val & 0x04) != 0x00); + sprites[3].MxMC = ((val & 0x08) != 0x00); + sprites[4].MxMC = ((val & 0x10) != 0x00); + sprites[5].MxMC = ((val & 0x20) != 0x00); + sprites[6].MxMC = ((val & 0x40) != 0x00); + sprites[7].MxMC = ((val & 0x80) != 0x00); + break; + case 0x1D: + sprites[0].MxXE = ((val & 0x01) != 0x00); + sprites[1].MxXE = ((val & 0x02) != 0x00); + sprites[2].MxXE = ((val & 0x04) != 0x00); + sprites[3].MxXE = ((val & 0x08) != 0x00); + sprites[4].MxXE = ((val & 0x10) != 0x00); + sprites[5].MxXE = ((val & 0x20) != 0x00); + sprites[6].MxXE = ((val & 0x40) != 0x00); + sprites[7].MxXE = ((val & 0x80) != 0x00); + break; + case 0x1E: + sprites[0].MxM = ((val & 0x01) != 0x00); + sprites[1].MxM = ((val & 0x02) != 0x00); + sprites[2].MxM = ((val & 0x04) != 0x00); + sprites[3].MxM = ((val & 0x08) != 0x00); + sprites[4].MxM = ((val & 0x10) != 0x00); + sprites[5].MxM = ((val & 0x20) != 0x00); + sprites[6].MxM = ((val & 0x40) != 0x00); + sprites[7].MxM = ((val & 0x80) != 0x00); + break; + case 0x1F: + sprites[0].MxD = ((val & 0x01) != 0x00); + sprites[1].MxD = ((val & 0x02) != 0x00); + sprites[2].MxD = ((val & 0x04) != 0x00); + sprites[3].MxD = ((val & 0x08) != 0x00); + sprites[4].MxD = ((val & 0x10) != 0x00); + sprites[5].MxD = ((val & 0x20) != 0x00); + sprites[6].MxD = ((val & 0x40) != 0x00); + sprites[7].MxD = ((val & 0x80) != 0x00); + break; + case 0x20: + EC = (val & 0x0F); + break; + case 0x21: + case 0x22: + case 0x23: + case 0x24: + BxC[addr - 0x21] = val & 0x0F; + break; + case 0x25: + case 0x26: + MMx[addr - 0x25] = val & 0x0F; + break; + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + sprites[addr - 0x27].MxC = val & 0x0F; + break; + } + } + } + + public byte Peek(int addr) + { + return this[addr & 0x3F]; + } + + public void Poke(int addr, byte val) + { + this[addr & 0x3F] = val; + } + + public byte Read(ushort addr, byte val) + { + byte result = 0; + addr &= 0x3F; + + switch (addr) + { + case 0x1E: + // clear after read + result = this[addr]; + this[addr] = 0x00; + IMMC = false; + break; + case 0x1F: + // clear after read + result = this[addr]; + this[addr] = 0x00; + IMBC = false; + break; + default: + result = this[addr]; + break; + } + + return result; + } + + private void UpdateBorder() + { + borderTop = RSEL ? 0x033 : 0x037; + borderBottom = RSEL ? 0x0FB : 0x0F7; + borderLeft = CSEL ? 0x018 : 0x01F; + borderRight = CSEL ? 0x158 : 0x14F; + } + + private void UpdateInterrupts() + { + IRQ = ((IRST & ERST) || (IMMC & EMMC) || (IMBC & EMBC) || (ILP & ELP)); + } + + private void UpdatePlotter() + { + graphicsMode = (ECM ? 0x04 : 0x00) | (BMM ? 0x02 : 0x00) | (MCM ? 0x01 : 0x00); + } + + public void Write(ushort addr, byte val) + { + addr &= 0x3F; + + switch (addr) + { + case 0x11: + rasterInterruptLine &= 0xFF; + rasterInterruptLine |= (val & 0x80) << 1; + // raster upper bit can't be changed, save and restore the value + val &= 0x7F; + val |= (byte)(this[addr] & 0x80); + this[addr] = val; + UpdateBorder(); + UpdatePlotter(); + break; + case 0x12: + // raster interrupt lower 8 bits + rasterInterruptLine &= 0x100; + rasterInterruptLine |= (val & 0xFF); + break; + case 0x16: + this[addr] = val; + UpdateBorder(); + UpdatePlotter(); + break; + case 0x19: + // only allow clearing of these flags + if ((val & 0x01) != 0x00) + IRST = false; + if ((val & 0x02) != 0x00) + IMBC = false; + if ((val & 0x04) != 0x00) + IMMC = false; + if ((val & 0x08) != 0x00) + ILP = false; + UpdateInterrupts(); + break; + case 0x1E: + case 0x1F: + // can't write to these regs + break; + default: + this[addr] = val; + break; + } + } + } +} \ No newline at end of file