diff --git a/src/Dotnet6502.C64/Hardware/Vic2.cs b/src/Dotnet6502.C64/Hardware/Vic2.cs index f88e9b7..0a28ec6 100644 --- a/src/Dotnet6502.C64/Hardware/Vic2.cs +++ b/src/Dotnet6502.C64/Hardware/Vic2.cs @@ -8,18 +8,30 @@ namespace Dotnet6502.C64.Hardware; public class Vic2 { // Reference: https://zimmers.net/cbmpics/cbm/c64/vic-ii.txt + public enum GraphicsMode + { + StandardTextMode, + MulticolorTextMode, + StandardBitmapMode, + MulticolorBitmapMode, + EcmTextMode, + Invalid, + } + private const int DotsPerCpuCycle = 8; private const int DotsPerScanline = 520; - private const int VisibleDotsPerScanLine = 418; + public const int VisibleDotsPerScanLine = 418; private const int TotalScanlines = 263; private const int FirstVisibleScanline = 28; private const int LastVisibleScanLine = 262; private const int FirstDisplayWindowScanLine = 51; private const int LastDisplayWindowScanLine = 250; - private const int VisibleScanLines = LastVisibleScanLine - FirstVisibleScanline + 1; + public const int VisibleScanLines = LastVisibleScanLine - FirstVisibleScanline + 1; private readonly IC64Display _c64Display; private readonly Memory _vic2Registers; + // private readonly Memory _colorRam; + private readonly ReadOnlyMemory _screenRam; private readonly RgbColor[] _frameBuffer = new RgbColor[VisibleDotsPerScanLine * VisibleScanLines]; private readonly RgbColor[] _palette = new RgbColor[16]; private int _lineCycleCount; @@ -48,10 +60,12 @@ public class Vic2 /// private ushort _videoMatrixLineIndex; - public Vic2(IC64Display c64Display, IoMemoryArea ioMemoryArea) + public Vic2(IC64Display c64Display, IoMemoryArea ioMemoryArea, ReadOnlyMemory screenRam) { _c64Display = c64Display; + _screenRam = screenRam; _vic2Registers = ioMemoryArea.Vic2Registers; + // _colorRam = ioMemoryArea.ColorRam; // Fill in the palette values based on the Colodore Palette _palette[0] = new RgbColor(0, 0, 0); // Black @@ -182,6 +196,13 @@ public class Vic2 var firstBorderBottomLine = rsel ? 247 : 251; var borderColor = registerData.BorderColor; + // var colorRam = _colorRam.Span; + var screenRam = _screenRam.Span; + + var row = (_currentScanLine - FirstVisibleScanline) / 8; + var rowInChar = (_currentScanLine - FirstVisibleScanline) % 8; + var column = _lineCycleCount - 17; + // Write the next 8 dots for (var x = 0; x < DotsPerCpuCycle; x++) { @@ -195,6 +216,11 @@ public class Vic2 _frameBuffer[pixelIndex] = _palette[borderColor]; continue; } + + // Standard text only mode atm + var columnInChar = x; + var charCode = screenRam[row * 40 + column]; + // var color = colorRam[row * 40 + column]; } } @@ -210,4 +236,26 @@ public class Vic2 _currentScanLine <= 247 && (_currentScanLine & 0b111) == registerData.YScroll; } + + /// + /// Gets the current graphics mode based on the current register set + /// + /// + /// + private GraphicsMode GetGraphicsMode(Vic2RegisterData registerData) + { + var ecm = registerData.Ecm; + var bmm = registerData.Bmm; + var mcm = registerData.Mcm; + + return (ecm, bmm, mcm) switch + { + (false, false, false) => GraphicsMode.StandardTextMode, + (false, false, true) => GraphicsMode.MulticolorTextMode, + (false, true, false) => GraphicsMode.StandardBitmapMode, + (false, true, true) => GraphicsMode.MulticolorBitmapMode, + (true, false, false) => GraphicsMode.EcmTextMode, + _ => GraphicsMode.Invalid, + }; + } } \ No newline at end of file diff --git a/src/Dotnet6502.C64/Hardware/Vic2RegisterData.cs b/src/Dotnet6502.C64/Hardware/Vic2RegisterData.cs index ce9bceb..d2ec23a 100644 --- a/src/Dotnet6502.C64/Hardware/Vic2RegisterData.cs +++ b/src/Dotnet6502.C64/Hardware/Vic2RegisterData.cs @@ -49,6 +49,12 @@ public readonly ref struct Vic2RegisterData /// public byte CharacterMapPointer => (byte)((_registerBytes[VmCb] & 0xF) >> 1); + public bool Ecm => (_registerBytes[ControlRegister1] & 0b0100_0000) > 0; + + public bool Bmm => (_registerBytes[ControlRegister1] & 0b0010_0000) > 0; + + public bool Mcm => (_registerBytes[ControlRegister2] & 0b00010000) > 0; + /// /// - 7 = Raster bit 8 /// - 6 = ECM diff --git a/src/Dotnet6502.C64/Integration/MonogameApp.cs b/src/Dotnet6502.C64/Integration/MonogameApp.cs index 69dbe60..9e64d1e 100644 --- a/src/Dotnet6502.C64/Integration/MonogameApp.cs +++ b/src/Dotnet6502.C64/Integration/MonogameApp.cs @@ -1,5 +1,6 @@ using System.Diagnostics; using Dotnet6502.C64.Emulation; +using Dotnet6502.C64.Hardware; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; @@ -8,8 +9,8 @@ namespace Dotnet6502.C64.Integration; public class MonogameApp : Game, IC64Display { - private const int Width = 464; - private const int Height = 247; + private const int Width = Vic2.VisibleDotsPerScanLine; + private const int Height = Vic2.VisibleScanLines; private readonly GraphicsDeviceManager _graphicsDeviceManager; private readonly object _synchronizationLock = new(); diff --git a/src/Dotnet6502.C64/Program.cs b/src/Dotnet6502.C64/Program.cs index da84997..be8669c 100644 --- a/src/Dotnet6502.C64/Program.cs +++ b/src/Dotnet6502.C64/Program.cs @@ -11,9 +11,9 @@ var cliArgs = CommandLineHandler.Parse(args); Console.WriteLine("Starting Dotnet6502 Commodore64 emulator"); var ioMemoryArea = new IoMemoryArea(); var pla = await SetupPla(cliArgs); -var memoryBus = SetupMemoryBus(); +var (memoryBus, screenRam) = SetupMemoryBus(); var app = new MonogameApp(false); -var vic2 = new Vic2(app, ioMemoryArea); +var vic2 = new Vic2(app, ioMemoryArea, screenRam); var hal = new C64Hal(memoryBus, cancellationTokenSource.Token, vic2); var jitCustomizer = new C64JitCustomizer(); var jitCompiler = new JitCompiler(hal, jitCustomizer, memoryBus); @@ -66,19 +66,22 @@ async Task SetupPla(CommandLineHandler.Values values) return programmableLogicArray; } -MemoryBus SetupMemoryBus() +(MemoryBus, ReadOnlyMemory screenRam) SetupMemoryBus() { - var memoryBus1 = new MemoryBus(); - memoryBus1.Attach(pla, 0x0000); - pla.AttachToBus(memoryBus1); + var bus = new MemoryBus(); + bus.Attach(pla, 0x0000); + pla.AttachToBus(bus); // fill in the rest with ram - memoryBus1.Attach(new BasicRamMemoryDevice(0x7fff - 0x0002 + 1), 0x0002); - memoryBus1.Attach(new BasicRamMemoryDevice(0xcfff - 0xc000 + 1), 0xc000); + var screenRamArea = new BasicRamMemoryDevice(0x07ff - 0x0400 + 1); + bus.Attach(new BasicRamMemoryDevice(0x03ff - 0x0002 + 1), 0x0002); + bus.Attach(screenRamArea, 0x0400); + bus.Attach(new BasicRamMemoryDevice(0x7fff - 0x0800 + 1), 0x0800); + bus.Attach(new BasicRamMemoryDevice(0xcfff - 0xc000 + 1), 0xc000); // TODO: Add cartridge rom low swapping to this region - memoryBus1.Attach(new BasicRamMemoryDevice(0x9fff - 0x8000 + 1), 0x8000); - return memoryBus1; + bus.Attach(new BasicRamMemoryDevice(0x9fff - 0x8000 + 1), 0x8000); + return (bus, screenRamArea.RawBlockFromZero!.Value); } async Task RunSystem()