LR35902 analysis suggestions

This commit is contained in:
Adrian Conlon
2025-01-26 21:17:07 +00:00
parent 1b8925ebe4
commit f31442511f
11 changed files with 107 additions and 56 deletions

View File

@@ -51,7 +51,7 @@ namespace LR35902
public IoRegisters IO { get; }
public bool GameRomDisabled { get; private set; } = false;
public bool GameRomDisabled { get; private set; }
public bool GameRomEnabled => !this.GameRomDisabled;
@@ -115,56 +115,56 @@ namespace LR35902
this.RunVerticalBlankLines(lines);
}
public override MemoryMapping Mapping(ushort address)
public override MemoryMapping Mapping(ushort absolute)
{
if (address < 0x100 && this.IO.BootRomEnabled)
if (absolute < 0x100 && this.IO.BootRomEnabled)
{
return new MemoryMapping(this.bootRom, 0x0000, Mask.Sixteen, AccessLevel.ReadOnly);
}
if (address < 0x4000 && this.GameRomEnabled)
if (absolute < 0x4000 && this.GameRomEnabled)
{
return new MemoryMapping(this.gameRomBanks[0], 0x0000, 0xffff, AccessLevel.ReadOnly);
}
if (address < 0x8000 && this.GameRomEnabled)
if (absolute < 0x8000 && this.GameRomEnabled)
{
return new MemoryMapping(this.gameRomBanks[this.romBank], 0x4000, 0xffff, AccessLevel.ReadOnly);
}
if (address < 0xa000)
if (absolute < 0xa000)
{
return new MemoryMapping(this.VRAM, 0x8000, 0xffff, AccessLevel.ReadWrite);
}
if (address < 0xc000)
if (absolute < 0xc000)
{
return this.ramBanks.Count == 0
? new MemoryMapping(this.unmapped2000, 0xa000, 0xffff, AccessLevel.ReadOnly)
: new MemoryMapping(this.ramBanks[this.ramBank], 0xa000, 0xffff, AccessLevel.ReadWrite);
}
if (address < 0xe000)
if (absolute < 0xe000)
{
return new MemoryMapping(this.lowInternalRam, 0xc000, 0xffff, AccessLevel.ReadWrite);
}
if (address < 0xfe00)
if (absolute < 0xfe00)
{
return new MemoryMapping(this.lowInternalRam, 0xe000, 0xffff, AccessLevel.ReadWrite); // Low internal RAM mirror
}
if (address < 0xfea0)
if (absolute < 0xfea0)
{
return new MemoryMapping(this.OAMRAM, 0xfe00, 0xffff, AccessLevel.ReadWrite);
}
if (address < IoRegisters.BASE)
if (absolute < IoRegisters.BASE)
{
return new MemoryMapping(this.unmapped60, 0xfea0, 0xffff, AccessLevel.ReadOnly);
}
if (address < 0xff80)
if (absolute < 0xff80)
{
return new MemoryMapping(this.IO, IoRegisters.BASE, 0xffff, AccessLevel.ReadWrite);
}
@@ -193,7 +193,7 @@ namespace LR35902
// Register 1: ROM bank code
if (this.banked && this.higherRomBank)
{
// assert((address >= 0x2000) && (address < 0x4000));
// assert((absolute >= 0x2000) && (absolute < 0x4000));
// assert((value > 0) && (value < 0x20));
this.romBank = value & (byte)Mask.Five;
}
@@ -226,6 +226,8 @@ namespace LR35902
}
}
break;
default:
break;
}
}

View File

@@ -5,6 +5,7 @@
namespace LR35902
{
using EightBit;
using System.Globalization;
public enum IoRegister
{
@@ -16,7 +17,7 @@ namespace LR35902
public sealed class Disassembler(Bus bus)
{
private bool prefixCB = false;
private bool prefixCB;
public Bus Bus { get; } = bus;
@@ -38,6 +39,8 @@ namespace LR35902
public static string State(LR35902 cpu)
{
ArgumentNullException.ThrowIfNull(cpu);
var pc = cpu.PC;
var sp = cpu.SP;
@@ -63,6 +66,7 @@ namespace LR35902
public string Disassemble(LR35902 cpu)
{
ArgumentNullException.ThrowIfNull(cpu);
this.prefixCB = false;
return this.Disassemble(cpu, cpu.PC.Word);
}
@@ -211,6 +215,8 @@ namespace LR35902
case 7:
specification = $"SRL {R(z)}";
break;
default:
break;
}
break;
@@ -223,6 +229,8 @@ namespace LR35902
case 3: // SET y, r[z]
specification = $"SET {y},{R(z)}";
break;
default:
break;
}
return output;
@@ -268,7 +276,7 @@ namespace LR35902
}
output += '\t';
output += string.Format(specification, (int)immediate, (int)absolute, relative, (int)displacement, indexedImmediate);
output += string.Format(CultureInfo.InvariantCulture, specification, (int)immediate, (int)absolute, relative, (int)displacement, indexedImmediate);
switch (ioRegister)
{
@@ -283,6 +291,8 @@ namespace LR35902
break;
case IoRegister.Unused:
break;
default:
break;
}
return output;
@@ -330,6 +340,8 @@ namespace LR35902
case 1: // ADD HL,rp
specification = $"ADD HL,{RP(p)}";
break;
default:
break;
}
break;
@@ -351,6 +363,8 @@ namespace LR35902
case 3: // GB: LDD (HL),A
specification = "LDD (HL),A";
break;
default:
break;
}
break;
@@ -369,8 +383,12 @@ namespace LR35902
case 3: // GB: LDD A,(HL)
specification = "LDD A,(HL)";
break;
default:
break;
}
break;
default:
break;
}
@@ -384,6 +402,8 @@ namespace LR35902
case 1: // DEC rp
specification = $"DEC {RP(p)}";
break;
default:
break;
}
break;
@@ -424,8 +444,12 @@ namespace LR35902
case 7:
specification = "CCF";
break;
default:
break;
}
break;
default:
break;
}
@@ -474,6 +498,8 @@ namespace LR35902
specification = "LD HL,SP+{4}";
dumpCount++;
break;
default:
break;
}
break;
@@ -498,8 +524,12 @@ namespace LR35902
case 3: // LD SP,HL
specification = "LD SP,HL";
break;
default:
break;
}
break;
default:
break;
}
@@ -530,6 +560,8 @@ namespace LR35902
specification = "LD A,({1:X4}H)";
dumpCount += 2;
break;
default:
break;
}
break;
@@ -550,6 +582,8 @@ namespace LR35902
case 7: // EI
specification = "EI";
break;
default:
break;
}
break;
@@ -570,8 +604,12 @@ namespace LR35902
specification = "CALL {1:X4}H";
dumpCount += 2;
break;
default:
break;
}
break;
default:
break;
}
@@ -583,8 +621,12 @@ namespace LR35902
case 7: // Restart: RST y * 8
specification = $"RST {y * 8:X2}";
break;
default:
break;
}
break;
default:
break;
}

View File

@@ -14,7 +14,7 @@ namespace LR35902
private readonly AbstractColourPalette<T> colours = colours;
private readonly ObjectAttribute[] objectAttributes = new ObjectAttribute[40];
private byte control;
private byte scanLine = 0;
private byte scanLine;
public T[] Pixels { get; } = new T[DisplayCharacteristics.PixelCount];

View File

@@ -96,7 +96,7 @@ namespace LR35902
public event EventHandler<LcdStatusModeEventArgs>? DisplayStatusModeUpdated;
public bool BootRomDisabled { get; private set; } = false;
public bool BootRomDisabled { get; private set; }
public bool BootRomEnabled => !this.BootRomDisabled;
@@ -335,6 +335,8 @@ namespace LR35902
case BOOT_DISABLE:
this.BootRomDisabled = value != 0;
break;
default:
break;
}
}

View File

@@ -2,7 +2,7 @@
// Copyright (c) Adrian Conlon. All rights reserved.
// </copyright>
namespace Fuse
namespace LR35902.FuseTest
{
public static class Program
{

View File

@@ -1,9 +1,10 @@
// <copyright file="RegisterState.cs" company="Adrian Conlon">
// Copyright (c) Adrian Conlon. All rights reserved.
// </copyright>
namespace Fuse
namespace LR35902.FuseTest
{
using System;
using Fuse;
using System.Globalization;
public class RegisterState : AbstractRegisterState, IRegisterState

View File

@@ -2,9 +2,9 @@
// Copyright (c) Adrian Conlon. All rights reserved.
// </copyright>
namespace Fuse
namespace LR35902.FuseTest
{
using LR35902;
using Fuse;
public enum Register
{
@@ -16,19 +16,13 @@ namespace Fuse
PC,
}
public class TestRunner<T> : LR35902.Bus
where T : Fuse.IRegisterState, new()
public class TestRunner<T>(Test<T> test, Result<T> result) : Bus
where T : IRegisterState, new()
{
private readonly Test<T> test;
private readonly Result<T> result;
private readonly Test<T> test = test;
private readonly Result<T> result = result;
private readonly EightBit.Ram ram = new(0x10000);
public TestRunner(Test<T> test, Result<T> result)
{
this.test = test;
this.result = result;
}
public bool Failed { get; private set; } = false;
public bool Unimplemented { get; private set; } = false;
@@ -42,13 +36,13 @@ namespace Fuse
var allowedCycles = this.test.RegisterState.TStates;
try
{
this.CPU.Run(allowedCycles);
_ = this.CPU.Run(allowedCycles);
this.Check();
}
catch (System.InvalidOperationException error)
catch (InvalidOperationException error)
{
this.Unimplemented = true;
System.Console.Error.WriteLine($"**** Error: {error.Message}");
Console.Error.WriteLine($"**** Error: {error.Message}");
}
}
@@ -73,7 +67,7 @@ namespace Fuse
private static void DumpDifference(string description, byte expected, byte actual)
{
var output = $"**** {description}, Expected: {expected:x2}, Got {actual:x2}";
System.Console.Error.WriteLine(output);
Console.Error.WriteLine(output);
}
private static void DumpDifference(string highDescription, string lowDescription, EightBit.Register16 expected, EightBit.Register16 actual)
@@ -123,11 +117,11 @@ namespace Fuse
private void Check()
{
this.Checkregisters();
this.CheckRegisters();
this.CheckMemory();
}
private void Checkregisters()
private void CheckRegisters()
{
var expectedState = this.result.RegisterState;
var expectedRegisters = expectedState.Registers;
@@ -144,7 +138,7 @@ namespace Fuse
if (!success)
{
this.Failed = true;
System.Console.Error.WriteLine($"**** Failed test (Register): {this.test.Description}");
Console.Error.WriteLine($"**** Failed test (Register): {this.test.Description}");
if (!af)
{
@@ -206,10 +200,10 @@ namespace Fuse
if (first)
{
first = false;
System.Console.Error.WriteLine($"**** Failed test (Memory): {this.test.Description}");
Console.Error.WriteLine($"**** Failed test (Memory): {this.test.Description}");
}
System.Console.Error.WriteLine($"**** Difference: Address: {address:x4} Expected: {expected:x2} Actual: {actual:x2}");
Console.Error.WriteLine($"**** Difference: Address: {address:x4} Expected: {expected:x2} Actual: {actual:x2}");
}
++address;

View File

@@ -1,10 +1,13 @@
// <copyright file="TestSuite.cs" company="Adrian Conlon">
// Copyright (c) Adrian Conlon. All rights reserved.
// </copyright>
namespace Fuse
namespace LR35902.FuseTest
{
using Fuse;
public class TestSuite<T>
where T : Fuse.IRegisterState, new()
where T : IRegisterState, new()
{
private readonly Tests<T> tests;
private readonly Results<T> results;
@@ -34,7 +37,7 @@ namespace Fuse
foreach (var test in this.tests.Container)
{
var key = test.Key;
System.Console.Out.WriteLine($"** Checking: {key}");
Console.Out.WriteLine($"** Checking: {key}");
var input = test.Value;
var result = this.results.Container[key];
@@ -52,8 +55,8 @@ namespace Fuse
}
}
System.Console.Out.WriteLine($"+++ Failed test count: {failedCount}");
System.Console.Out.WriteLine($"+++ Unimplemented test count: {unimplementedCount}");
Console.Out.WriteLine($"+++ Failed test count: {failedCount}");
Console.Out.WriteLine($"+++ Unimplemented test count: {unimplementedCount}");
}
}
}

View File

@@ -10,7 +10,7 @@ namespace LR35902
{
private readonly Bus bus = bus;
private readonly Register16 af = new((int)Mask.Sixteen);
private bool prefixCB = false;
private bool prefixCB;
public int ClockCycles => this.Cycles * 4;
@@ -29,9 +29,9 @@ namespace LR35902
public override Register16 HL { get; } = new Register16((int)Mask.Sixteen);
private bool IME { get; set; } = false;
private bool IME { get; set; }
private bool Stopped { get; set; } = false;
private bool Stopped { get; set; }
public override void Execute()
{
@@ -130,7 +130,7 @@ namespace LR35902
}
}
private void TickMachine()
private void TickMachine()
{
this.Tick(4);
this.OnMachineTicked();
@@ -156,8 +156,8 @@ namespace LR35902
protected override void JumpRelative(sbyte offset)
{
base.JumpRelative(offset);
this.TickMachine();
base.JumpRelative(offset);
this.TickMachine();
}
protected override bool JumpConditional(bool condition)
@@ -166,12 +166,12 @@ namespace LR35902
{
this.TickMachine();
}
return condition;
return condition;
}
protected override bool ReturnConditional(bool condition)
{
_ = base.ReturnConditional(condition);
_ = base.ReturnConditional(condition);
this.TickMachine();
return condition;
}
@@ -187,7 +187,7 @@ namespace LR35902
protected override void Return()
{
base.Return();
base.Return();
this.TickMachine();
}
@@ -669,6 +669,8 @@ namespace LR35902
this.EI();
//this.Tick();
break;
default:
break;
}
break;
@@ -690,6 +692,8 @@ namespace LR35902
case 0: // CALL nn
this.CallIndirect();
break;
default:
break;
}
break;
@@ -740,6 +744,8 @@ namespace LR35902
throw new InvalidOperationException("Invalid operation mode");
}
break;
default:
break;
}
}

View File

@@ -7,7 +7,7 @@
<GenerateDocumentationFile>False</GenerateDocumentationFile>
<SignAssembly>False</SignAssembly>
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
<AnalysisLevel>latest</AnalysisLevel>
<AnalysisLevel>latest-all</AnalysisLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">

View File

@@ -14,6 +14,7 @@ namespace LR35902
public ObjectAttribute(Ram ram, ushort address)
{
ArgumentNullException.ThrowIfNull(ram);
this.PositionY = ram.Peek(address);
this.PositionX = ram.Peek(++address);
this.Pattern = ram.Peek(++address);