Work my way through a bunch of the analysis suggestions.

Signed-off-by: Adrian Conlon <adrian.conlon@gmail.com>
This commit is contained in:
Adrian Conlon 2020-06-22 00:00:15 +01:00
parent db0e8c613f
commit cd4af67177
32 changed files with 297 additions and 292 deletions

View File

@ -66,7 +66,7 @@ namespace EightBit
public void Write()
{
this.OnWritingByte();
var value = this.Data; // N.B. Don't join these two lines together: the
var value = this.Data; // N.B. Don't join these two lines together: the
this.Reference() = value; // data bus integrity is lost, due to evaluation order!
this.OnWrittenByte();
}

View File

@ -30,7 +30,7 @@ namespace EightBit
public static byte HighByte(ushort value) => HighByte((int)value);
public static byte LowByte(int value) => (byte)(value & (int)Mask.Mask8);
public static byte LowByte(int value) => (byte)(value & (int)Mask.Eight);
public static byte LowByte(ushort value) => LowByte((int)value);

View File

@ -22,6 +22,25 @@ namespace EightBit
GC.SuppressFinalize(this);
}
public IEnumerable<Tuple<ushort, byte[]>> Parse()
{
this.eof = false;
while (!this.reader.EndOfStream && !this.eof)
{
var line = this.reader.ReadLine();
var parsed = this.Parse(line);
if (parsed != null)
{
yield return parsed;
}
}
if (!this.eof)
{
throw new InvalidOperationException("File is missing an EOF record");
}
}
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
@ -35,22 +54,28 @@ namespace EightBit
}
}
public IEnumerable<Tuple<ushort, byte[]>> Parse()
private static byte[] ParseDataRecord(string line, byte count)
{
this.eof = false;
while (!this.reader.EndOfStream && !this.eof)
if (string.IsNullOrEmpty(line))
{
var line = this.reader.ReadLine();
var parsed = this.Parse(line);
if (parsed != null)
{
yield return parsed;
}
throw new ArgumentNullException(nameof(line));
}
if (!this.eof)
var requiredLength = 9 + 2 + (count * 2);
if (line.Length != requiredLength)
{
throw new InvalidOperationException("File is missing an EOF record");
throw new ArgumentOutOfRangeException(nameof(line), "Invalid hex file: line is not the required length");
}
var data = new byte[count];
for (var i = 0; i < count; ++i)
{
var position = 9 + (i * 2);
var extracted = line.Substring(position, 2);
data[i] = Convert.ToByte(extracted, 16);
}
return data;
}
private Tuple<ushort, byte[]> Parse(string line)
@ -86,29 +111,5 @@ namespace EightBit
throw new InvalidOperationException("Unhandled hex file record.");
}
}
private static byte[] ParseDataRecord(string line, byte count)
{
if (string.IsNullOrEmpty(line))
{
throw new ArgumentNullException(nameof(line));
}
var requiredLength = 9 + 2 + (count * 2);
if (line.Length != requiredLength)
{
throw new ArgumentOutOfRangeException(nameof(line), "Invalid hex file: line is not the required length");
}
var data = new byte[count];
for (var i = 0; i < count; ++i)
{
var position = 9 + (i * 2);
var extracted = line.Substring(position, 2);
data[i] = Convert.ToByte(extracted, 16);
}
return data;
}
}
}

View File

@ -32,9 +32,9 @@ namespace EightBit
public event EventHandler<EventArgs> LoweredHALT;
public Register16 SP { get; } = new Register16((ushort)Mask.Mask16);
public Register16 SP { get; } = new Register16((ushort)Mask.Sixteen);
public Register16 MEMPTR { get; } = new Register16((ushort)Mask.Mask16);
public Register16 MEMPTR { get; } = new Register16((ushort)Mask.Sixteen);
public abstract Register16 AF { get; }
@ -89,18 +89,18 @@ namespace EightBit
protected static int CalculateHalfCarryAdd(byte before, byte value, int calculation)
{
var index = BuildHalfCarryIndex(before, value, calculation);
return HalfCarryTableAdd[index & (int)Mask.Mask3];
return HalfCarryTableAdd[index & (int)Mask.Three];
}
protected static int CalculateHalfCarrySub(byte before, byte value, int calculation)
{
var index = BuildHalfCarryIndex(before, value, calculation);
return HalfCarryTableSub[index & (int)Mask.Mask3];
return HalfCarryTableSub[index & (int)Mask.Three];
}
protected override void OnRaisedPOWER()
{
this.PC.Word = this.SP.Word = this.AF.Word = this.BC.Word = this.DE.Word = this.HL.Word = (ushort)Mask.Mask16;
this.PC.Word = this.SP.Word = this.AF.Word = this.BC.Word = this.DE.Word = this.HL.Word = (ushort)Mask.Sixteen;
this.RaiseHALT();
base.OnRaisedPOWER();
}

View File

@ -7,21 +7,21 @@ namespace EightBit
public enum Mask
{
None = 0,
Mask1 = Bits.Bit1 - 1,
Mask2 = Bits.Bit2 - 1,
Mask3 = Bits.Bit3 - 1,
Mask4 = Bits.Bit4 - 1,
Mask5 = Bits.Bit5 - 1,
Mask6 = Bits.Bit6 - 1,
Mask7 = Bits.Bit7 - 1,
Mask8 = Bits.Bit8 - 1,
Mask9 = Bits.Bit9 - 1,
Mask10 = Bits.Bit10 - 1,
Mask11 = Bits.Bit11 - 1,
Mask12 = Bits.Bit12 - 1,
Mask13 = Bits.Bit13 - 1,
Mask14 = Bits.Bit14 - 1,
Mask15 = Bits.Bit15 - 1,
Mask16 = Bits.Bit16 - 1,
One = Bits.Bit1 - 1,
Two = Bits.Bit2 - 1,
Three = Bits.Bit3 - 1,
Four = Bits.Bit4 - 1,
Five = Bits.Bit5 - 1,
Six = Bits.Bit6 - 1,
Seven = Bits.Bit7 - 1,
Eight = Bits.Bit8 - 1,
Nine = Bits.Bit9 - 1,
Ten = Bits.Bit10 - 1,
Eleven = Bits.Bit11 - 1,
Twelve = Bits.Bit12 - 1,
Thirteen = Bits.Bit13 - 1,
Fourteen = Bits.Bit14 - 1,
Fifteen = Bits.Bit15 - 1,
Sixteen = Bits.Bit16 - 1,
}
}

View File

@ -11,7 +11,7 @@ namespace Fuse
{
private readonly List<byte> bytes = new List<byte>();
public ushort Address { get; private set; } = (ushort)EightBit.Mask.Mask16;
public ushort Address { get; private set; } = (ushort)EightBit.Mask.Sixteen;
public ReadOnlyCollection<byte> Bytes => this.bytes.AsReadOnly();

View File

@ -27,9 +27,9 @@ namespace Fuse
public string Specifier { get; private set; }
public ushort Address { get; private set; } = (ushort)EightBit.Mask.Mask16;
public ushort Address { get; private set; } = (ushort)EightBit.Mask.Sixteen;
public byte Value { get; private set; } = (byte)EightBit.Mask.Mask8;
public byte Value { get; private set; } = (byte)EightBit.Mask.Eight;
public bool TryParse(Lines lines)
{

View File

@ -23,7 +23,7 @@ namespace Intel8080.Test
this.ports = new InputOutput();
this.CPU = new Intel8080(this, this.ports);
this.disassembler = new Disassembler(this);
this.mapping = new MemoryMapping(this.ram, 0x0000, (ushort)Mask.Mask16, AccessLevel.ReadWrite);
this.mapping = new MemoryMapping(this.ram, 0x0000, (ushort)Mask.Sixteen, AccessLevel.ReadWrite);
}
public Intel8080 CPU { get; }

View File

@ -30,11 +30,11 @@ namespace EightBit
}
}
public override Register16 BC { get; } = new Register16((int)Mask.Mask16);
public override Register16 BC { get; } = new Register16((int)Mask.Sixteen);
public override Register16 DE { get; } = new Register16((int)Mask.Mask16);
public override Register16 DE { get; } = new Register16((int)Mask.Sixteen);
public override Register16 HL { get; } = new Register16((int)Mask.Mask16);
public override Register16 HL { get; } = new Register16((int)Mask.Sixteen);
public override int Execute()
{
@ -616,7 +616,7 @@ namespace EightBit
private byte Decrement(byte operand)
{
this.F = AdjustSZP(this.F, --operand);
this.F = SetBit(this.F, StatusBits.AC, LowNibble(operand) != (byte)Mask.Mask4);
this.F = SetBit(this.F, StatusBits.AC, LowNibble(operand) != (byte)Mask.Four);
return operand;
}

View File

@ -102,7 +102,7 @@ namespace EightBit.GameBoy
public void RunRasterLines()
{
this.enabledLCD = (this.IO.Peek(IoRegisters.LCDC) & (byte)LcdcControl.LcdEnable) != 0;
this.enabledLCD = (this.IO.Peek(IoRegisters.LCDC) & (byte)LcdcControls.LcdEnable) != 0;
this.IO.ResetLY();
this.RunRasterLines(DisplayCharacteristics.RasterHeight);
}
@ -117,7 +117,7 @@ namespace EightBit.GameBoy
{
if ((address < 0x100) && this.IO.BootRomEnabled)
{
return new MemoryMapping(this.bootRom, 0x0000, Mask.Mask16, AccessLevel.ReadOnly);
return new MemoryMapping(this.bootRom, 0x0000, Mask.Sixteen, AccessLevel.ReadOnly);
}
if ((address < 0x4000) && this.GameRomEnabled)
@ -198,7 +198,7 @@ namespace EightBit.GameBoy
{
// assert((address >= 0x2000) && (address < 0x4000));
// assert((value > 0) && (value < 0x20));
this.romBank = value & (byte)Mask.Mask5;
this.romBank = value & (byte)Mask.Five;
}
break;
@ -214,7 +214,7 @@ namespace EightBit.GameBoy
// Register 3: ROM/RAM change
if (this.banked)
{
switch (value & (byte)Mask.Mask1)
switch (value & (byte)Mask.One)
{
case 0:
this.higherRomBank = true;

View File

@ -29,14 +29,14 @@ namespace EightBit.GameBoy
if (this.scanLine < DisplayCharacteristics.RasterHeight)
{
this.control = this.bus.IO.Peek(IoRegisters.LCDC);
if ((this.control & (byte)LcdcControl.LcdEnable) != 0)
if ((this.control & (byte)LcdcControls.LcdEnable) != 0)
{
if ((this.control & (byte)LcdcControl.DisplayBackground) != 0)
if ((this.control & (byte)LcdcControls.DisplayBackground) != 0)
{
this.RenderBackground();
}
if ((this.control & (byte)LcdcControl.ObjectEnable) != 0)
if ((this.control & (byte)LcdcControls.ObjectEnable) != 0)
{
this.RenderObjects();
}
@ -68,9 +68,9 @@ namespace EightBit.GameBoy
{
var palette = this.CreatePalette(IoRegisters.BGP);
var window = (this.control & (byte)LcdcControl.WindowEnable) != 0;
var bgArea = (this.control & (byte)LcdcControl.BackgroundCodeAreaSelection) != 0 ? 0x1c00 : 0x1800;
var bgCharacters = (this.control & (byte)LcdcControl.BackgroundCharacterDataSelection) != 0 ? 0 : 0x800;
var window = (this.control & (byte)LcdcControls.WindowEnable) != 0;
var bgArea = (this.control & (byte)LcdcControls.BackgroundCodeAreaSelection) != 0 ? 0x1c00 : 0x1800;
var bgCharacters = (this.control & (byte)LcdcControls.BackgroundCharacterDataSelection) != 0 ? 0 : 0x800;
var wx = this.bus.IO.Peek(IoRegisters.WX);
var wy = this.bus.IO.Peek(IoRegisters.WY);
@ -99,7 +99,7 @@ namespace EightBit.GameBoy
private void RenderObjects()
{
var objBlockHeight = (this.control & (byte)LcdcControl.ObjectBlockCompositionSelection) != 0 ? 16 : 8;
var objBlockHeight = (this.control & (byte)LcdcControls.ObjectBlockCompositionSelection) != 0 ? 16 : 8;
var palettes = new int[2][];
palettes[0] = this.CreatePalette(IoRegisters.OBP0);

View File

@ -99,7 +99,7 @@ namespace EightBit.GameBoy
public bool BootRomEnabled => !this.BootRomDisabled;
public int TimerClock => this.TimerControl & (byte)Mask.Mask2;
public int TimerClock => this.TimerControl & (byte)Mask.Two;
public bool TimerEnabled => !this.TimerDisabled;
@ -134,7 +134,7 @@ namespace EightBit.GameBoy
public void Reset()
{
this.Poke(NR52, 0xf1);
this.Poke(LCDC, (byte)(LcdcControl.DisplayBackground | LcdcControl.BackgroundCharacterDataSelection | LcdcControl.LcdEnable));
this.Poke(LCDC, (byte)(LcdcControls.DisplayBackground | LcdcControls.BackgroundCharacterDataSelection | LcdcControls.LcdEnable));
this.divCounter.Word = 0xabcc;
this.timerCounter = 0;
}
@ -180,7 +180,7 @@ namespace EightBit.GameBoy
public void UpdateLcdStatusMode(LcdStatusMode mode)
{
var current = this.Peek(STAT) & unchecked((byte)~Mask.Mask2);
var current = this.Peek(STAT) & unchecked((byte)~Mask.Two);
this.Poke(STAT, (byte)(current | (int)mode));
this.OnDisplayStatusModeUpdated(mode);
}
@ -364,7 +364,7 @@ namespace EightBit.GameBoy
var upOrSelect = (live && !this.p12) ? 0 : Bits.Bit2;
var downOrStart = (live && !this.p13) ? 0 : Bits.Bit3;
var lowNibble = (byte)(rightOrA | leftOrB | upOrSelect | downOrStart);
var highNibble = (byte)Chip.PromoteNibble((byte)Mask.Mask4);
var highNibble = (byte)Chip.PromoteNibble((byte)Mask.Four);
var value = (byte)(lowNibble | highNibble);
this.Poke(port, value);
}
@ -382,19 +382,19 @@ namespace EightBit.GameBoy
case TMA:
break;
case TAC:
this.ApplyMask(port, (byte)Mask.Mask3);
this.ApplyMask(port, (byte)Mask.Three);
break;
// Interrupt Flags
case IF:
this.ApplyMask(port, (byte)Mask.Mask5);
this.ApplyMask(port, (byte)Mask.Five);
break;
// LCD Display Registers
case LCDC:
break;
case STAT:
this.ApplyMask(port, (byte)Mask.Mask7);
this.ApplyMask(port, (byte)Mask.Seven);
break;
case SCY:
case SCX:

View File

@ -11,9 +11,9 @@ namespace LR35902.BlarggTest
var configuration = new Configuration();
#if DEBUG
//configuration.DebugMode = true;
////configuration.DebugMode = true;
#endif
//configuration.DebugMode = true;
////configuration.DebugMode = true;
var computer = new Computer(configuration);

View File

@ -31,7 +31,7 @@ namespace Fuse
public bool Unimplemented { get; private set; } = false;
public override EightBit.MemoryMapping Mapping(ushort address) => new EightBit.MemoryMapping(this.ram, 0, EightBit.Mask.Mask16, EightBit.AccessLevel.ReadWrite);
public override EightBit.MemoryMapping Mapping(ushort address) => new EightBit.MemoryMapping(this.ram, 0, EightBit.Mask.Sixteen, EightBit.AccessLevel.ReadWrite);
public void Run()
{

View File

@ -9,7 +9,7 @@ namespace EightBit.GameBoy
public class LR35902 : IntelProcessor
{
private readonly Bus bus;
private readonly Register16 af = new Register16((int)Mask.Mask16);
private readonly Register16 af = new Register16((int)Mask.Sixteen);
private bool prefixCB = false;
public LR35902(Bus bus)
@ -30,11 +30,11 @@ namespace EightBit.GameBoy
}
}
public override Register16 BC { get; } = new Register16((int)Mask.Mask16);
public override Register16 BC { get; } = new Register16((int)Mask.Sixteen);
public override Register16 DE { get; } = new Register16((int)Mask.Mask16);
public override Register16 DE { get; } = new Register16((int)Mask.Sixteen);
public override Register16 HL { get; } = new Register16((int)Mask.Mask16);
public override Register16 HL { get; } = new Register16((int)Mask.Sixteen);
private bool IME { get; set; } = false;
@ -123,7 +123,7 @@ namespace EightBit.GameBoy
{
base.HandleRESET();
this.DI();
this.SP.Word = (ushort)(Mask.Mask16 - 1);
this.SP.Word = (ushort)(Mask.Sixteen - 1);
this.Tick(4);
}
@ -635,7 +635,7 @@ namespace EightBit.GameBoy
var value = (sbyte)this.FetchByte();
var result = before + value;
this.SP.Word = (ushort)result;
var carried = before ^ value ^ (result & (int)Mask.Mask16);
var carried = before ^ value ^ (result & (int)Mask.Sixteen);
this.F = ClearBit(this.F, StatusBits.ZF | StatusBits.NF);
this.F = SetBit(this.F, StatusBits.CF, carried & (int)Bits.Bit8);
this.F = SetBit(this.F, StatusBits.HC, carried & (int)Bits.Bit4);
@ -655,7 +655,7 @@ namespace EightBit.GameBoy
var value = (sbyte)this.FetchByte();
var result = before + value;
this.HL.Word = (ushort)result;
var carried = before ^ value ^ (result & (int)Mask.Mask16);
var carried = before ^ value ^ (result & (int)Mask.Sixteen);
this.F = ClearBit(this.F, StatusBits.ZF | StatusBits.NF);
this.F = SetBit(this.F, StatusBits.CF, carried & (int)Bits.Bit8);
this.F = SetBit(this.F, StatusBits.HC, carried & (int)Bits.Bit4);

View File

@ -4,7 +4,7 @@
namespace EightBit.GameBoy
{
[System.Flags]
public enum LcdcControl
public enum LcdcControls
{
None = 0,
DisplayBackground = Bits.Bit0,

View File

@ -24,9 +24,9 @@ namespace M6502.Test
this.CPU = new M6502(this);
this.symbols = new Symbols();
this.disassembler = new Disassembler(this, this.CPU, this.symbols);
this.mapping = new MemoryMapping(this.ram, 0x0000, (ushort)Mask.Mask16, AccessLevel.ReadWrite);
this.mapping = new MemoryMapping(this.ram, 0x0000, (ushort)Mask.Sixteen, AccessLevel.ReadWrite);
this.oldPC = (ushort)Mask.Mask16;
this.oldPC = (ushort)Mask.Sixteen;
}
public M6502 CPU { get; }

View File

@ -555,7 +555,7 @@ namespace EightBit
this.Y = 0;
this.A = 0;
this.P = (byte)StatusBits.RF;
this.S = (byte)Mask.Mask8;
this.S = (byte)Mask.Eight;
this.LowerSYNC();
this.LowerRW();
base.OnRaisedPOWER();

View File

@ -1,4 +1,7 @@
namespace EightBit
// <copyright file="Disassembler.cs" company="Adrian Conlon">
// Copyright (c) Adrian Conlon. All rights reserved.
// </copyright>
namespace EightBit
{
using System;
using System.Collections.Generic;
@ -46,12 +49,6 @@
public string Trace() => this.Trace(this.CPU.PC);
////private static string Dump_RelativeValue(sbyte value) => value.ToString("D");
////private static string Dump_RelativeValue(short value) => value.ToString("D");
////private static string Dump_RelativeValue(Register16 value) => Dump_RelativeValue(value);
public string Disassemble(ushort current)
{
this.address = current;
@ -68,26 +65,70 @@
return this.DisassembleUnprefixed();
}
private static string RR(int which)
{
switch (which)
{
case 0b00:
return "X";
case 0b01:
return "Y";
case 0b10:
return "U";
case 0b11:
return "S";
default:
throw new ArgumentOutOfRangeException(nameof(which), which, "Register specification is unknown");
}
}
private static string WrapIndirect(string what, bool indirect)
{
var open = indirect ? "[" : string.Empty;
var close = indirect ? "]" : string.Empty;
return $"{open}{what}{close}";
}
private static string ReferenceTransfer8(int specifier)
{
switch (specifier)
{
case 0b1000:
return "A";
case 0b1001:
return "B";
case 0b1010:
return "CC";
case 0b1011:
return "DP";
default:
throw new ArgumentOutOfRangeException(nameof(specifier), specifier, "8bit register specification is unknown");
}
}
private static string ReferenceTransfer16(int specifier)
{
switch (specifier)
{
case 0b0000:
return "D";
case 0b0001:
return "X";
case 0b0010:
return "Y";
case 0b0011:
return "U";
case 0b0100:
return "S";
case 0b0101:
return "PC";
default:
throw new ArgumentOutOfRangeException(nameof(specifier), specifier, "16bit register specification is unknown");
}
}
private string Disassemble(int current) => this.Disassemble((ushort)current);
////private string Dump_Flags()
////{
//// var returned = string.Empty;
//// returned += this.CPU.EntireRegisterSet != 0 ? "E" : "-";
//// returned += this.CPU.FastInterruptMasked != 0 ? "F" : "-";
//// returned += this.CPU.HalfCarry != 0 ? "H" : "-";
//// returned += this.CPU.InterruptMasked != 0 ? "I" : "-";
//// returned += this.CPU.Negative != 0 ? "N" : "-";
//// returned += this.CPU.Zero != 0 ? "Z" : "-";
//// returned += this.CPU.Overflow != 0 ? "V" : "-";
//// returned += this.CPU.Carry != 0 ? "C" : "-";
//// return returned;
////}
////private string Disassemble(Register16 current) => this.Disassemble(current.Word);
////private string Disassemble() => this.Disassemble(this.CPU.PC);
private string DisassembleUnprefixed()
{
var opcode = this.GetByte(this.address);
@ -431,7 +472,6 @@
case 0x7d: output += this.Address_extended("TST"); break; // TST (extended)
// Branching
case 0x16: output += this.BranchLong("LBRA"); break; // BRA (LBRA relative)
case 0x17: output += this.BranchLong("LBSR"); break; // BSR (LBSR relative)
case 0x20: output += this.BranchShort("BRA"); break; // BRA (relative)
@ -496,7 +536,6 @@
case 0xbe: output += this.Address_extended("LDY"); break; // LD (LDY extended)
// Branching
case 0x21: output += this.BranchLong("LBRN"); break; // BRN (LBRN relative)
case 0x22: output += this.BranchLong("LBHI"); break; // BHI (LBHI relative)
case 0x23: output += this.BranchLong("LBLS"); break; // BLS (LBLS relative)
@ -568,31 +607,7 @@
return output;
}
//
private static string RR(int which)
{
switch (which)
{
case 0b00:
return "X";
case 0b01:
return "Y";
case 0b10:
return "U";
case 0b11:
return "S";
default:
throw new ArgumentOutOfRangeException(nameof(which), which, "Register specification is unknown");
}
}
private static string WrapIndirect(string what, bool indirect)
{
var open = indirect ? "[" : "";
var close = indirect ? "]" : "";
return $"{open}{what}{close}";
}
////
private string Address_direct(string mnemomic)
{
@ -613,49 +628,49 @@
if ((type & (byte)Bits.Bit7) != 0)
{
var indirect = (type & (byte)Bits.Bit4) != 0;
switch (type & (byte)Mask.Mask4)
switch (type & (byte)Mask.Four)
{
case 0b0000: // ,R+
case 0b0000: // ,R+
output += $"\t{mnemomic}\t{WrapIndirect($",{r}+", indirect)}";
break;
case 0b0001: // ,R++
case 0b0001: // ,R++
output += $"\t{mnemomic}\t{WrapIndirect($",{r}++", indirect)}";
break;
case 0b0010: // ,-R
case 0b0010: // ,-R
output += $"\t{mnemomic}\t{WrapIndirect($",-{r}", indirect)}";
break;
case 0b0011: // ,--R
case 0b0011: // ,--R
output += $"\t{mnemomic}\t{WrapIndirect($",--{r}", indirect)}";
break;
case 0b0100: // ,R
case 0b0100: // ,R
output += $"\t{mnemomic}\t{WrapIndirect($",{r}", indirect)}";
break;
case 0b0101: // B,R
case 0b0101: // B,R
output += $"\t{mnemomic}\t{WrapIndirect($"B,{r}", indirect)}";
break;
case 0b0110: // A,R
case 0b0110: // A,R
output += $"\t{mnemomic}\t{WrapIndirect($"A,{r}", indirect)}";
break;
case 0b1000: // n,R (eight-bit)
case 0b1000: // n,R (eight-bit)
byte8 = this.GetByte(++this.address);
output += $"{byte8:x2}\t{mnemomic}\t{WrapIndirect($"{byte8:x2},{r}", indirect)}";
break;
case 0b1001: // n,R (sixteen-bit)
case 0b1001: // n,R (sixteen-bit)
word = this.GetWord(++this.address);
output += $"{word:x4}\t{mnemomic}\t{WrapIndirect($"{word:x4},{r}", indirect)}";
break;
case 0b1011: // D,R
case 0b1011: // D,R
output += $"\t{mnemomic}\t{WrapIndirect($"D,{r}", indirect)}";
break;
case 0b1100: // n,PCR (eight-bit)
case 0b1100: // n,PCR (eight-bit)
byte8 = this.GetByte(++this.address);
output += $"{byte8:x2}\t{mnemomic}\t{WrapIndirect("${(byte)byte8:D},PCR", indirect)}";
break;
case 0b1101: // n,PCR (sixteen-bit)
case 0b1101: // n,PCR (sixteen-bit)
word = this.GetWord(++this.address);
output += $"{word:x4}\t{mnemomic}\t{WrapIndirect("${(short)word:D},PCR", indirect)}";
break;
case 0b1111: // [n]
case 0b1111: // [n]
if (!indirect)
{
throw new InvalidOperationException("Index specification cannot be direct");
@ -671,7 +686,7 @@
else
{
// EA = ,R + 5-bit offset
output += $"\t{mnemomic}\t{Processor.SignExtend(5, type & (byte)Mask.Mask5)},{r}";
output += $"\t{mnemomic}\t{Processor.SignExtend(5, type & (byte)Mask.Five)},{r}";
}
return output;
@ -711,44 +726,6 @@
private string BranchLong(string mnemomic) => this.Address_relative_word(mnemomic);
private static string ReferenceTransfer8(int specifier)
{
switch (specifier)
{
case 0b1000:
return "A";
case 0b1001:
return "B";
case 0b1010:
return "CC";
case 0b1011:
return "DP";
default:
throw new ArgumentOutOfRangeException(nameof(specifier), specifier, "8bit register specification is unknown");
}
}
private static string ReferenceTransfer16(int specifier)
{
switch (specifier)
{
case 0b0000:
return "D";
case 0b0001:
return "X";
case 0b0010:
return "Y";
case 0b0011:
return "U";
case 0b0100:
return "S";
case 0b0101:
return "PC";
default:
throw new ArgumentOutOfRangeException(nameof(specifier), specifier, "16bit register specification is unknown");
}
}
private string TFR(string mnemomic)
{
var data = this.GetByte(++this.address);
@ -763,7 +740,7 @@
: $"{output}{ReferenceTransfer16(reg1)},{ReferenceTransfer16(reg2)}";
}
//
////
private string PulS() => this.PulX("PULS", "U");

View File

@ -40,20 +40,20 @@ namespace EightBit
{
if (absolute < 0x8000)
{
return new MemoryMapping(this.ram, 0x0000, Mask.Mask16, AccessLevel.ReadWrite);
return new MemoryMapping(this.ram, 0x0000, Mask.Sixteen, AccessLevel.ReadWrite);
}
if (absolute < 0xa000)
{
return new MemoryMapping(this.unused2000, 0x8000, Mask.Mask16, AccessLevel.ReadOnly);
return new MemoryMapping(this.unused2000, 0x8000, Mask.Sixteen, AccessLevel.ReadOnly);
}
if (absolute < 0xc000)
{
return new MemoryMapping(this.io, 0xa000, Mask.Mask16, AccessLevel.ReadWrite);
return new MemoryMapping(this.io, 0xa000, Mask.Sixteen, AccessLevel.ReadWrite);
}
return new MemoryMapping(this.rom, 0xc000, Mask.Mask16, AccessLevel.ReadOnly);
return new MemoryMapping(this.rom, 0xc000, Mask.Sixteen, AccessLevel.ReadOnly);
}
public override void RaisePOWER()

View File

@ -1,4 +1,7 @@
namespace EightBit
// <copyright file="MC6809.cs" company="Adrian Conlon">
// Copyright (c) Adrian Conlon. All rights reserved.
// </copyright>
namespace EightBit
{
using System;
@ -6,16 +9,18 @@
// http://www.cpu-world.com/Arch/6809.html
// http://atjs.mbnet.fi/mc6809/Information/6809.htm
// |---------------|-----------------------------------|
// | MPU State | |
// |_______________| MPU State Definition |
// | BA | BS | |
// |_______|_______|___________________________________|
// | 0 | 0 | Normal (running) |
// | 0 | 1 | Interrupt or RESET Acknowledge |
// | 1 | 0 | SYNC Acknowledge |
// | 1 | 1 | HALT Acknowledge |
// |-------|-------|-----------------------------------|
/*
|---------------|-----------------------------------|
| MPU State | |
|_______________| MPU State Definition |
| BA | BS | |
|_______|_______|___________________________________|
| 0 | 0 | Normal (running) |
| 0 | 1 | Interrupt or RESET Acknowledge |
| 1 | 0 | SYNC Acknowledge |
| 1 | 1 | HALT Acknowledge |
|-------|-------|-----------------------------------|
*/
public sealed class MC6809 : BigEndianProcessor
{
@ -26,7 +31,6 @@
private const byte FIRQvector = 0xf6; // FIRQ vector
private const byte SWI2vector = 0xf4; // SWI2 vector
private const byte SWI3vector = 0xf2; // SWI3 vector
// private const byte RESERVEDvector = 0xf0; // RESERVED vector
private byte cc = 0;
private byte dp = 0;
@ -118,6 +122,18 @@
public bool Halted => this.HALT.Lowered();
public ref PinLevel NMI => ref this.nmiLine;
public ref PinLevel FIRQ => ref this.firqLine;
public ref PinLevel HALT => ref this.haltLine;
public ref PinLevel BA => ref this.baLine;
public ref PinLevel BS => ref this.bsLine;
public ref PinLevel RW => ref this.rwLine;
public int EntireRegisterSet => this.CC & (byte)StatusBits.EF;
public int FastInterruptMasked => this.CC & (byte)StatusBits.FF;
@ -146,18 +162,6 @@
private bool GT => !this.LE; // !(Z OR (N XOR V))
public ref PinLevel NMI => ref this.nmiLine;
public ref PinLevel FIRQ => ref this.firqLine;
public ref PinLevel HALT => ref this.haltLine;
public ref PinLevel BA => ref this.baLine;
public ref PinLevel BS => ref this.bsLine;
public ref PinLevel RW => ref this.rwLine;
public void Halt()
{
--this.PC.Word;
@ -400,6 +404,16 @@
return base.BusRead();
}
private static byte SetBit(byte f, StatusBits flag) => SetBit(f, (byte)flag);
private static byte SetBit(byte f, StatusBits flag, int condition) => SetBit(f, (byte)flag, condition);
private static byte SetBit(byte f, StatusBits flag, bool condition) => SetBit(f, (byte)flag, condition);
private static byte ClearBit(byte f, StatusBits flag) => ClearBit(f, (byte)flag);
private static byte ClearBit(byte f, StatusBits flag, int condition) => ClearBit(f, (byte)flag, condition);
private void HandleHALT()
{
this.RaiseBA();
@ -482,16 +496,6 @@
private void OnExecutedInstruction() => this.ExecutedInstruction?.Invoke(this, EventArgs.Empty);
private static byte SetBit(byte f, StatusBits flag) => SetBit(f, (byte)flag);
private static byte SetBit(byte f, StatusBits flag, int condition) => SetBit(f, (byte)flag, condition);
private static byte SetBit(byte f, StatusBits flag, bool condition) => SetBit(f, (byte)flag, condition);
private static byte ClearBit(byte f, StatusBits flag) => ClearBit(f, (byte)flag);
private static byte ClearBit(byte f, StatusBits flag, int condition) => ClearBit(f, (byte)flag, condition);
private void Push(Register16 stack, byte value) => this.BusWrite(--stack.Word, value);
private void PushS(byte value) => this.Push(this.S, value);
@ -515,7 +519,8 @@
private Register16 RR(int which)
{
switch (which) {
switch (which)
{
case 0b00:
return this.X;
case 0b01:
@ -553,58 +558,58 @@
var address = new Register16();
if ((type & (byte)Bits.Bit7) != 0)
{
switch (type & (byte)Mask.Mask4)
switch (type & (byte)Mask.Four)
{
case 0b0000: // ,R+
case 0b0000: // ,R+
this.Tick(2);
address.Word = r.Word++;
break;
case 0b0001: // ,R++
case 0b0001: // ,R++
this.Tick(3);
address.Word = r.Word;
r.Word += 2;
break;
case 0b0010: // ,-R
case 0b0010: // ,-R
this.Tick(2);
address.Word = --r.Word;
break;
case 0b0011: // ,--R
case 0b0011: // ,--R
this.Tick(3);
r.Word -= 2;
address.Word = r.Word;
break;
case 0b0100: // ,R
case 0b0100: // ,R
address.Word = r.Word;
break;
case 0b0101: // B,R
case 0b0101: // B,R
this.Tick();
address.Word = (ushort)(r.Word + (sbyte)this.B);
break;
case 0b0110: // A,R
case 0b0110: // A,R
this.Tick();
address.Word = (ushort)(r.Word + (sbyte)this.A);
break;
case 0b1000: // n,R (eight-bit)
case 0b1000: // n,R (eight-bit)
this.Tick();
address.Word = (ushort)(r.Word + (sbyte)this.FetchByte());
break;
case 0b1001: // n,R (sixteen-bit)
case 0b1001: // n,R (sixteen-bit)
this.Tick(4);
address.Word = (ushort)(r.Word + (short)this.FetchWord().Word);
break;
case 0b1011: // D,R
case 0b1011: // D,R
this.Tick(4);
address.Word = (ushort)(r.Word + this.D.Word);
break;
case 0b1100: // n,PCR (eight-bit)
case 0b1100: // n,PCR (eight-bit)
this.Tick();
address.Word = this.Address_relative_byte().Word;
break;
case 0b1101: // n,PCR (sixteen-bit)
case 0b1101: // n,PCR (sixteen-bit)
this.Tick(2);
address.Word = this.Address_relative_word().Word;
break;
case 0b1111: // [n]
case 0b1111: // [n]
this.Tick(2);
address.Word = this.Address_extended().Word;
break;
@ -623,8 +628,9 @@
{
// EA = ,R + 5-bit offset
this.Tick();
address.Word = new Register16(r.Word + SignExtend(5, (byte)(type & (byte)Mask.Mask5))).Word;
address.Word = new Register16(r.Word + SignExtend(5, (byte)(type & (byte)Mask.Five))).Word;
}
return address;
}
@ -683,7 +689,7 @@
private byte AdjustOverflow(ushort before, ushort data, uint after)
{
var lowAfter = (ushort)(after & (uint)Mask.Mask16);
var lowAfter = (ushort)(after & (uint)Mask.Sixteen);
var highAfter = (ushort)(after >> 16);
return SetBit(this.CC, StatusBits.VF, (before ^ data ^ lowAfter ^ (highAfter << 15)) & (int)Bits.Bit15);
}
@ -701,7 +707,7 @@
private byte AdjustAddition(ushort before, ushort data, uint after)
{
var result = new Register16(after & (uint)Mask.Mask16);
var result = new Register16(after & (uint)Mask.Sixteen);
this.CC = this.AdjustNZ(result);
this.CC = this.AdjustCarry(after);
return this.AdjustOverflow(before, data, after);
@ -719,7 +725,7 @@
private byte AdjustSubtraction(ushort before, ushort data, uint after)
{
var result = new Register16(after & (uint)Mask.Mask16);
var result = new Register16(after & (uint)Mask.Sixteen);
this.CC = this.AdjustNZ(result);
this.CC = this.AdjustCarry(after);
return this.AdjustOverflow(before, data, after);
@ -785,9 +791,9 @@
this.SaveRegisterState();
}
private void SaveRegisterState() => this.PSH(this.S, this.EntireRegisterSet != 0 ? (byte)Mask.Mask8 : (byte)0b10000001);
private void SaveRegisterState() => this.PSH(this.S, this.EntireRegisterSet != 0 ? (byte)Mask.Eight : (byte)0b10000001);
private void RestoreRegisterState() => this.PUL(this.S, this.EntireRegisterSet != 0 ? (byte)Mask.Mask8 : (byte)0b10000001);
private void RestoreRegisterState() => this.PUL(this.S, this.EntireRegisterSet != 0 ? (byte)Mask.Eight : (byte)0b10000001);
private ref byte ReferenceTransfer8(int specifier)
{
@ -808,7 +814,8 @@
private Register16 ReferenceTransfer16(int specifier)
{
switch (specifier) {
switch (specifier)
{
case 0b0000:
return this.D;
case 0b0001:
@ -1166,7 +1173,6 @@
case 0x7d: this.Tick(7); this.TST(this.AM_extended_byte()); break; // TST (extended)
// Branching
case 0x16: this.Tick(5); this.Jump(this.Address_relative_word()); break; // BRA (LBRA relative)
case 0x17: this.Tick(9); this.JSR(this.Address_relative_word()); break; // BSR (LBSR relative)
case 0x20: this.Tick(3); this.Jump(this.Address_relative_byte()); break; // BRA (relative)
@ -1226,7 +1232,6 @@
case 0xbe: this.Tick(7); this.Y.Word = this.LD(this.AM_extended_word()).Word; break; // LD (LDY extended)
// Branching
case 0x21: this.Tick(5); this.Address_relative_word(); break; // BRN (LBRN relative)
case 0x22: this.Tick(5); this.BranchLong(this.HI); break; // BHI (LBHI relative)
case 0x23: this.Tick(5); this.BranchLong(this.LS); break; // BLS (LBLS relative)
@ -1300,7 +1305,7 @@
{
var addition = (uint)(operand.Word + data.Word);
this.CC = this.AdjustAddition(operand, data, addition);
return new Register16(addition & (uint)Mask.Mask16);
return new Register16(addition & (uint)Mask.Sixteen);
}
private byte AndR(byte operand, byte data) => this.Through((byte)(operand & data));
@ -1398,7 +1403,7 @@
{
ref var rightRegister = ref this.ReferenceTransfer8(rightSpecifier);
(leftRegister.Low, rightRegister) = (rightRegister, leftRegister.Low);
leftRegister.High = (byte)Mask.Mask8;
leftRegister.High = (byte)Mask.Eight;
}
}
else
@ -1408,7 +1413,7 @@
{
var rightRegister = this.ReferenceTransfer16(rightSpecifier);
(leftRegister, rightRegister.Low) = (rightRegister.Low, leftRegister);
rightRegister.High =(byte)Mask.Mask8;
rightRegister.High =(byte)Mask.Eight;
}
else
{
@ -1470,6 +1475,7 @@
if ((data & (byte)Bits.Bit6) != 0)
{
this.Tick(2);
// Pushing to the S stack means we must be pushing U
this.PushWord(stack, object.ReferenceEquals(stack, this.S) ? this.U : this.S);
}
@ -1552,6 +1558,7 @@
if ((data & (byte)Bits.Bit6) != 0)
{
this.Tick(2);
// Pulling from the S stack means we must be pulling U
(object.ReferenceEquals(stack, this.S) ? this.U : this.S).Word = this.PopWord(stack).Word;
}
@ -1599,13 +1606,13 @@
{
var subtraction = (uint)(operand.Word - data.Word);
this.CC = this.AdjustSubtraction(operand, data, subtraction);
return new Register16(subtraction & (uint)Mask.Mask16);
return new Register16(subtraction & (uint)Mask.Sixteen);
}
private byte SEX(byte from)
{
this.CC = this.AdjustNZ(from);
return (from & (byte)Bits.Bit7) != 0 ? (byte)Mask.Mask8 : (byte)0;
return (from & (byte)Bits.Bit7) != 0 ? (byte)Mask.Eight : (byte)0;
}
private void SWI()
@ -1657,7 +1664,7 @@
{
var destinationRegister = this.ReferenceTransfer16(destinationSpecifier);
destinationRegister.Low = sourceRegister;
destinationRegister.High = (byte)Mask.Mask8;
destinationRegister.High = (byte)Mask.Eight;
}
else
{

View File

@ -1,4 +1,7 @@
namespace EightBit
// <copyright file="ProfileEventArgs.cs" company="Adrian Conlon">
// Copyright (c) Adrian Conlon. All rights reserved.
// </copyright>
namespace EightBit
{
using System;

View File

@ -1,4 +1,7 @@
namespace EightBit
// <copyright file="ProfileLineEventArgs.cs" company="Adrian Conlon">
// Copyright (c) Adrian Conlon. All rights reserved.
// </copyright>
namespace EightBit
{
using System;

View File

@ -1,4 +1,7 @@
namespace EightBit
// <copyright file="ProfileScopeEventArgs.cs" company="Adrian Conlon">
// Copyright (c) Adrian Conlon. All rights reserved.
// </copyright>
namespace EightBit
{
using System;

View File

@ -1,4 +1,7 @@
namespace EightBit
// <copyright file="Profiler.cs" company="Adrian Conlon">
// Copyright (c) Adrian Conlon. All rights reserved.
// </copyright>
namespace EightBit
{
using System;
@ -8,12 +11,12 @@
private readonly ulong[] addressProfiles;
private readonly ulong[] addressCounts;
private ushort address;
private readonly Bus board;
private readonly MC6809 processor;
private readonly Disassembler disassembler;
private ushort address;
public Profiler(Bus board, MC6809 processor, Disassembler disassembler)
{
this.board = board;

View File

@ -1,4 +1,7 @@
using System.Reflection;
// <copyright file="AssemblyInfo.cs" company="Adrian Conlon">
// Copyright (c) Adrian Conlon. All rights reserved.
// </copyright>
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

View File

@ -284,6 +284,7 @@ namespace EightBit
specification = "IM 2";
break;
}
break;
case 7:
switch (y)

View File

@ -12,7 +12,7 @@ namespace EightBit
public RefreshRegister(byte value)
{
this.high = (byte)(value & (byte)Bits.Bit7);
this.variable = (byte)(value & (byte)Mask.Mask7);
this.variable = (byte)(value & (byte)Mask.Seven);
}
public static implicit operator byte(RefreshRegister input) => ToByte(input);
@ -25,7 +25,7 @@ namespace EightBit
public static bool operator !=(RefreshRegister left, RefreshRegister right) => !(left == right);
public static byte ToByte(RefreshRegister input) => (byte)(input.high | (input.variable & (byte)Mask.Mask7));
public static byte ToByte(RefreshRegister input) => (byte)(input.high | (input.variable & (byte)Mask.Seven));
public static RefreshRegister Increment(RefreshRegister value)
{

View File

@ -27,7 +27,7 @@ namespace EightBit
// Parity
PF = Bits.Bit2,
// Zero
// Overflow
VF = Bits.Bit2,
// Negative?

View File

@ -44,7 +44,7 @@ namespace Fuse
foreach (var e in result.Events.Container)
{
// Ignore contention events
if (!e.Specifier.EndsWith("C"))
if (!e.Specifier.EndsWith("C", System.StringComparison.Ordinal))
{
this.expectedEvents.Add(e);
}
@ -55,7 +55,7 @@ namespace Fuse
public bool Unimplemented { get; private set; } = false;
public override EightBit.MemoryMapping Mapping(ushort address) => new EightBit.MemoryMapping(this.ram, 0, EightBit.Mask.Mask16, EightBit.AccessLevel.ReadWrite);
public override EightBit.MemoryMapping Mapping(ushort address) => new EightBit.MemoryMapping(this.ram, 0, EightBit.Mask.Sixteen, EightBit.AccessLevel.ReadWrite);
public void Run()
{
@ -446,7 +446,7 @@ namespace Fuse
private static string ToString(TestEvent e)
{
var output = $"Cycles = {e.Cycles}, Specifier = {e.Specifier}, Address = {e.Address:X4}";
if (!e.Specifier.EndsWith("C"))
if (!e.Specifier.EndsWith("C", System.StringComparison.Ordinal))
{
output += $", Value={e.Value:X2}";
}

View File

@ -23,7 +23,7 @@ namespace Z80.Test
this.ports = new InputOutput();
this.CPU = new Z80(this, this.ports);
this.disassembler = new Disassembler(this);
this.mapping = new MemoryMapping(this.ram, 0x0000, (ushort)Mask.Mask16, AccessLevel.ReadWrite);
this.mapping = new MemoryMapping(this.ram, 0x0000, (ushort)Mask.Sixteen, AccessLevel.ReadWrite);
}
public Z80 CPU { get; }

View File

@ -417,12 +417,12 @@ namespace EightBit
this.IM = 0;
this.REFRESH = new RefreshRegister(0);
this.IV = (byte)Mask.Mask8;
this.IV = (byte)Mask.Eight;
this.ExxAF();
this.Exx();
this.AF.Word = this.IX.Word = this.IY.Word = this.BC.Word = this.DE.Word = this.HL.Word = (ushort)Mask.Mask16;
this.AF.Word = this.IX.Word = this.IY.Word = this.BC.Word = this.DE.Word = this.HL.Word = (ushort)Mask.Sixteen;
this.prefixCB = this.prefixDD = this.prefixED = this.prefixFD = false;
@ -519,7 +519,7 @@ namespace EightBit
base.HandleRESET();
this.DisableInterrupts();
this.IV = this.REFRESH = 0;
this.SP.Word = this.AF.Word = (ushort)Mask.Mask16;
this.SP.Word = this.AF.Word = (ushort)Mask.Sixteen;
this.Tick(3);
}
@ -1035,6 +1035,7 @@ namespace EightBit
this.PC.Word -= 2;
this.Tick(5);
}
this.Tick(3);
break;
case 7: // OTDR
@ -1043,6 +1044,7 @@ namespace EightBit
this.PC.Word -= 2;
this.Tick(5);
}
this.Tick(3);
break;
}
@ -1200,6 +1202,7 @@ namespace EightBit
this.R(y, this.Increment(original));
break;
}
case 5: // 8-bit DEC
{
if (memoryY && this.displaced)
@ -1230,6 +1233,7 @@ namespace EightBit
this.R(y, value); // LD r,n
break;
}
case 7: // Assorted operations on accumulator/flags
switch (y)
{
@ -1634,7 +1638,7 @@ namespace EightBit
this.F = ClearBit(this.F, StatusBits.HC, LowNibble(operand));
var result = --operand;
this.F = AdjustSZXY(this.F, result);
this.F = SetBit(this.F, StatusBits.VF, result == (byte)Mask.Mask7);
this.F = SetBit(this.F, StatusBits.VF, result == (byte)Mask.Seven);
return result;
}
@ -1697,7 +1701,7 @@ namespace EightBit
return this.intermediate.Word;
}
private ushort ADC(Register16 operand ,Register16 value)
private ushort ADC(Register16 operand, Register16 value)
{
this.Add(operand, value, this.F & (byte)StatusBits.CF); // Leaves result in intermediate anyway
this.F = ClearBit(this.F, StatusBits.ZF, this.intermediate.Word);
@ -2049,7 +2053,7 @@ namespace EightBit
this.MEMPTR.Word = destination.Word;
this.F = SetBit(this.F, StatusBits.NF, value & (byte)Bits.Bit7);
this.F = SetBit(this.F, StatusBits.HC | StatusBits.CF, (this.L + value) > 0xff);
this.F = AdjustParity(this.F, (byte)(((value + this.L) & (int)Mask.Mask3) ^ this.B));
this.F = AdjustParity(this.F, (byte)(((value + this.L) & (int)Mask.Three) ^ this.B));
}
private void OUTI()