summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Assembler/Assembler.cs221
-rw-r--r--Assembler/Disassembler.cs87
-rw-r--r--Chip/Bus.cs2
-rw-r--r--Chip/DisplayDevice.cs15
-rw-r--r--Chip/Q1Cpu.cs3
-rw-r--r--Chip/Q1CpuAddressingModes.cs130
-rw-r--r--DisplayEngine.cs6
-rw-r--r--Make.cs5
-rw-r--r--Program.cs12
-rw-r--r--Q1Emu.csproj3
-rw-r--r--Q1Emu.sln.DotSettings.user2
-rw-r--r--ROMs/script.dat24
-rw-r--r--ROMs/script.q1bin0 -> 67 bytes
-rw-r--r--ROMs/test.q1bin10 -> 10 bytes
14 files changed, 451 insertions, 59 deletions
diff --git a/Assembler/Assembler.cs b/Assembler/Assembler.cs
index 14a33fd..5df068d 100644
--- a/Assembler/Assembler.cs
+++ b/Assembler/Assembler.cs
@@ -10,6 +10,9 @@ public class Assembler
public readonly BinaryWriter Writer;
public readonly StringReader Reader;
+ private Dictionary<string, u16> _labels = new();
+ private u16 _addressOffset = 0;
+
public Assembler(StringReader reader, BinaryWriter writer)
{
this.Reader = reader;
@@ -20,11 +23,23 @@ public class Assembler
{
while (this.Reader.ReadLine() is { } line)
{
- string trimmedLine = line.Trim();
+ string trimmedLine = line.Split(";")[0].Trim(); // Remove comments
if (string.IsNullOrEmpty(trimmedLine) || trimmedLine.StartsWith(';'))
continue;
- this.ParseInstruction(trimmedLine);
+ if (trimmedLine.StartsWith(".org"))
+ {
+ // Handle .org directive
+ string orgValue = trimmedLine[5..].Trim();
+ this._addressOffset = this.GetConstant(orgValue);
+ Console.WriteLine($"Setting address offset to {this._addressOffset:X4}");
+ }
+
+ else if (trimmedLine.EndsWith(":"))
+ this._labels[trimmedLine[..^1]] = (u16) (this.Writer.BaseStream.Position + this._addressOffset);
+
+ else
+ this.ParseInstruction(trimmedLine);
}
}
@@ -37,28 +52,40 @@ public class Assembler
if (parts.Length > 2)
throw new ArgumentException($"Invalid instruction format: {instruction}");
+ u8 opcodeValue = this.ParseOpcode(opcode);
+
u8 m1 = 0, m2 = 0;
if (parts.Length > 0)
- {
- m1 = this.ParseOperand(parts[0]);
- if (parts.Length > 1)
- m2 = this.ParseOperand(parts[1]);
- }
+ m1 = this.ParseMode(parts[0]);
+ if (parts.Length > 1)
+ m2 = this.ParseMode(parts[1]);
- switch (opcode)
- {
- case "NOP":
- this.Writer.Write((u8) 0x00);
- break;
+ Console.WriteLine($"Parsed instruction: {opcode} with modes {m1:X2}, {m2:X2} (at address {this.Writer.BaseStream.Position + this._addressOffset:X4})");
+ this.WriteInstruction(opcodeValue, m1, m2);
+ if (parts.Length > 0)
+ this.WriteMode(m1, parts[0]);
+ if (parts.Length > 1)
+ this.WriteMode(m2, parts[1]);
+ }
- default:
- throw new NotSupportedException($"Unsupported opcode: {opcode}");
- }
+ private u8 ParseOpcode(string opcode)
+ {
+ return opcode switch
+ {
+ "NOP" => 0x00, "JMP" => 0x00, "MOV" => 0x00,
+ "RET" => 0x01, "CALL" => 0x01, "CMP" => 0x02,
+ "BR" => 0x02, "BZ" => 0x02, "LT" => 0x02,
+ "GT" => 0x03,
+ "INC" => 0x08, "ADD" => 0x08,
+ "DEC" => 0x09,
+ "MUL" => 0x0B,
+ _ => throw new ArgumentException($"Unknown opcode: {opcode}")
+ };
}
- private u8 ParseOperand(string operand)
+ private u8 ParseMode(string mode)
{
- operand = operand.Trim();
+ mode = mode.Trim();
bool IsRegister(string text)
{
@@ -81,26 +108,176 @@ public class Assembler
return hardcodedRegisters.Contains(text);
}
- if (operand.StartsWith("@"))
+ if (this._labels.ContainsKey(mode))
+ {
+ return 0x01; // Immediate
+ }
+
+ if (mode.StartsWith("@"))
{
return 0x03; // Indirect
}
- if (operand.StartsWith("[") && operand.EndsWith("]"))
+ if (mode.StartsWith("[") && mode.EndsWith("]"))
{
- string inner = operand[1..^1].Trim();
+ string inner = mode[1..^1].Trim();
if (inner.Contains("+"))
return 0x07; // Register indirect with offset
-
+
if (IsRegister(inner))
return 0x06; // Register indirect
return 0x02; // Direct
}
- if (IsRegister(operand))
+ if (IsRegister(mode))
return 0x05; // Register
return 0x01; // Immediate
}
+
+ private void WriteInstruction(u8 opcode, u8 m1, u8 m2)
+ {
+ Write(opcode);
+ Write((u8) (m1 << 4 | m2)); // Combine m1 and m2 into a single byte
+ }
+
+ private void WriteMode(u8 mode, string operand)
+ {
+ operand = operand.Trim();
+
+ switch (mode)
+ {
+ case 0x00: // Implicit
+ // No additional data needed
+ break;
+
+ case 0x01: // Immediate
+ u16 immediateValue = this.GetConstant(operand);
+ this.Write(immediateValue);
+ break;
+
+ case 0x02: // Direct
+ u16 directAddress = this.GetConstant(operand); // Remove brackets
+ this.Write(directAddress);
+ break;
+
+ case 0x03: // Indirect
+ u16 indirectAddress = this.GetConstant(operand); // Remove brackets and @
+ this.Write(indirectAddress);
+ break;
+
+ case 0x04: // Relative
+ i16 relativeOffset = this.GetSignedConstant(operand);
+ Write(relativeOffset);
+ break;
+
+ case 0x05: // Register
+ u8 regIndex = this.GetRegisterIndex(operand);
+ Write(regIndex);
+ break;
+
+ case 0x06: // Register Indirect
+ u8 indirectRegIndex = this.GetRegisterIndex(operand); // Remove brackets
+ Write(indirectRegIndex);
+ break;
+
+ case 0x07: // Register Indirect with Offset
+ u8 offsetRegIndex = this.GetRegisterIndex(operand[1..^1].Split('+')[0].Trim());
+ i16 offsetValue = this.GetSignedConstant(operand[1..^1].Split('+')[1].Trim());
+ Write(offsetRegIndex);
+ Write(offsetValue);
+ break;
+ }
+ }
+ private i16 GetSignedConstant(string value)
+ {
+ value = this.Clean(value);
+
+ if (value.StartsWith("$"))
+ {
+ // Hexadecimal offset
+ return Convert.ToInt16(value[1..], 16);
+ }
+ else if (i16.TryParse(value, out i16 result))
+ // Decimal offset
+ return result;
+ else
+ {
+ throw new ArgumentException($"Invalid offset value: {value}");
+ }
+ }
+ private u8 GetRegisterIndex(string reg)
+ {
+ reg = this.Clean(reg);
+
+ if (reg.StartsWith("V"))
+ if (u8.TryParse(reg[1..], out u8 index) && index < 0x3F)
+ return index;
+
+ return reg switch
+ {
+ "AX" => 0x40,
+ "AH" => 0x41,
+ "AL" => 0x42,
+ "DX" => 0x43,
+ "DH" => 0x44,
+ "DL" => 0x45,
+ "LX" => 0x46,
+ "PC" => 0x50,
+ "SP" => 0x51,
+ _ => throw new ArgumentException($"Invalid register index: {reg}")
+ };
+ }
+ private u16 GetConstant(string value)
+ {
+ value = this.Clean(value);
+
+ if (this._labels.ContainsKey(value))
+ {
+ // Label reference
+ return this._labels[value];
+ }
+ if (value.StartsWith("$"))
+ {
+ // Hexadecimal constant (backwards) $1FFF
+ u16 x = Convert.ToUInt16(value[1..], 16);
+ return x;
+ }
+ else if (u16.TryParse(value, out u16 result))
+ // Decimal constant
+ return result;
+ else
+ {
+ throw new ArgumentException($"Invalid constant value: {value}");
+ }
+ }
+
+ private string Clean(string value)
+ {
+ if (value.StartsWith("@"))
+ value = value[1..]; // Remove @ for indirect addressing
+
+ if (value.StartsWith("[") && value.EndsWith("]"))
+ value = value[1..^1].Trim(); // Remove brackets for direct addressing
+
+ return value.Trim();
+ }
+
+ private void Write(u16 value)
+ {
+ u16 swappedValue = (u16) ((value >> 8) | (value << 8));
+ this.Writer.Write(swappedValue);
+ }
+
+ private void Write(u8 value)
+ {
+ this.Writer.Write(value);
+ }
+
+ private void Write(i16 value)
+ {
+ u16 swappedValue = (u16) ((value >> 8) | (value << 8));
+ this.Writer.Write(swappedValue);
+ }
} \ No newline at end of file
diff --git a/Assembler/Disassembler.cs b/Assembler/Disassembler.cs
new file mode 100644
index 0000000..9b1c44d
--- /dev/null
+++ b/Assembler/Disassembler.cs
@@ -0,0 +1,87 @@
+namespace Q1Emu.Assembler;
+
+using System;
+using System.Collections.Generic;
+
+public class Disassembler
+{
+ public static Dictionary<u8, string[]> InstructionLookup = new()
+ {
+ { 0x00, ["NOP", "JMP", "HALT", "MOV"] },
+ { 0x01, ["RET", "CALL", "SUS", "CMP"] },
+ { 0x02, ["BR", "BZ", "BZ_LX", "LT"] },
+ { 0x03, ["NOP", "NOP", "NOP", "GT"] },
+
+ { 0x04, ["NOT_LX", "NOT", "NOP", "AND"] },
+ { 0x05, ["INV_DX", "INV", "NOP", "OR"] },
+ { 0x06, ["SHL_DX", "SHL", "NOP", "XOR"] },
+ { 0x07, ["SHR_DX", "SHR", "NOP", "NOP"] },
+
+ { 0x08, ["INC_AX", "INC", "NOP", "ADD"] },
+ { 0x09, ["DEC_AX", "DEC", "NOP", "SUB"] },
+ { 0x0A, ["NOP", "NOP", "NOP", "DIV"] },
+ { 0x0B, ["NOP", "NOP", "NOP", "MUL"] },
+ { 0x0C, ["NOP", "NOP", "NOP", "MOD"] },
+ };
+
+ public static Dictionary<u8, string> ModeLookup = new()
+ {
+ { 0x00, "" },
+ { 0x01, "c" },
+ { 0x02, "[a]" },
+ { 0x03, "@[a]" },
+ { 0x04, "pc + c" },
+ { 0x05, "r" },
+ { 0x06, "[r]" },
+ { 0x07, "[r + c]" },
+ };
+
+ public static string ParseInstruction(u16 instruction)
+ {
+ u8 op = (u8) ((instruction >> 8) & 0xFF); // 256 opcodes
+ u8 m1 = (u8) ((instruction >> 4) & 0x0F); // 16 modes
+ u8 m2 = (u8) (instruction & 0x0F); // 16 modes
+
+ u8 i = (m1, m2) switch
+ {
+ (0x00, 0x00) => 0, // Implicit
+ (0x00, _) => 2, // Extended implicit
+ (_, 0x00) => 1, // Simple addressing mode
+ _ => 3 // Extended addressing mode
+ };
+
+ string opcodeName = GetOpcodeName(op, i);
+ string mode1 = GetModeName(m1);
+ string mode2 = GetModeName(m2);
+
+ if (i == 0)
+ return opcodeName;
+
+ if (i == 2)
+ return $"{opcodeName}";
+
+ if (i == 1)
+ return $"{opcodeName} {mode1}";
+
+ if (i == 3)
+ return $"{opcodeName} {mode1}, {mode2}";
+
+ throw new InvalidOperationException($"Unknown instruction format for opcode {op:X2} with modes {m1:X2}, {m2:X2}");
+ }
+
+ private static string GetOpcodeName(u8 opcode, u8 i)
+ {
+ if (!InstructionLookup.ContainsKey(opcode) || i >= InstructionLookup[opcode].Length)
+ return $"{opcode:X2}";
+
+ return InstructionLookup[opcode][i];
+ }
+
+ private static string GetModeName(u8 mode)
+ {
+ if (ModeLookup.TryGetValue(mode, out string modeName))
+ return modeName;
+
+ return $"[{mode:X2}]"; // Fallback for unknown modes
+ }
+} \ No newline at end of file
diff --git a/Chip/Bus.cs b/Chip/Bus.cs
index e8cf5ad..951d23f 100644
--- a/Chip/Bus.cs
+++ b/Chip/Bus.cs
@@ -39,7 +39,7 @@ public class Bus : BusDevice
{
BusDevice? device = this.GetDevice(address);
if (device == null)
- return [];
+ return new u8[length];
return device.ReadSeq(address, length);
}
diff --git a/Chip/DisplayDevice.cs b/Chip/DisplayDevice.cs
index ea34cfb..28bf4e0 100644
--- a/Chip/DisplayDevice.cs
+++ b/Chip/DisplayDevice.cs
@@ -2,6 +2,7 @@ namespace Q1Emu.Chip;
using System;
using System.Collections.Generic;
+using System.Threading;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
@@ -11,6 +12,7 @@ public class DisplayDevice : RamDevice
private readonly u16 _paletteSize;
private readonly u16 _displayWidth;
private readonly u16 _displayHeight;
+ private Color[] textureData;
public DisplayDevice(u16 paletteSize, u16 displayWidth, u16 displayHeight, u16 addressableStart)
: base(addressableStart, DisplayDevice.DetermineSize(paletteSize, displayWidth, displayHeight))
@@ -18,6 +20,7 @@ public class DisplayDevice : RamDevice
this._paletteSize = paletteSize;
this._displayWidth = displayWidth;
this._displayHeight = displayHeight;
+ this.textureData = new Color[this._displayWidth * this._displayHeight];
}
private static u16 DetermineSize(u16 paletteSize, u16 displayWidth, u16 displayHeight)
@@ -30,7 +33,6 @@ public class DisplayDevice : RamDevice
Color[] palette = this.ReadPalette();
ref8 pixelData = this.ReadSeq((u16) (this.AddressableStart + this._paletteSize * 3), (u16) (this._displayWidth * this._displayHeight));
- Color[] textureData = new Color[this._displayWidth * this._displayHeight];
for (u16 i = 0; i < textureData.Length; i++)
{
u8 pixelValue = pixelData[i];
@@ -73,4 +75,15 @@ public class DisplayDevice : RamDevice
paletteData[offset + 2] = palette[i].B;
}
}
+
+ public override void Write(u16 address, u8 value)
+ {
+ Console.WriteLine($"DisplayDevice.Write: {address:X4} = {value:X2}");
+ base.Write(address, value);
+ }
+ public override void WriteSeq(u16 address, u16 length, ref8 value)
+ {
+ Console.WriteLine($"DisplayDevice.WriteSeq: {address:X4} length={length} value={Make.u16(value)}");
+ base.WriteSeq(address, length, value);
+ }
} \ No newline at end of file
diff --git a/Chip/Q1Cpu.cs b/Chip/Q1Cpu.cs
index 1124578..910ad64 100644
--- a/Chip/Q1Cpu.cs
+++ b/Chip/Q1Cpu.cs
@@ -3,6 +3,7 @@
namespace Q1Emu.Chip;
using System.Collections.Generic;
+using Assembler;
public partial class Q1Cpu
{
@@ -42,7 +43,9 @@ public partial class Q1Cpu
public void Clock()
{
+ var pc = this.PC;
u16 instruction = this.FetchInstruction(out u8 op, out u8 m1, out u8 m2, out _);
+ Console.WriteLine($"{pc:X4}: {Disassembler.ParseInstruction(instruction)}");
bool ex = m2 > 0;
switch (m1, ex)
diff --git a/Chip/Q1CpuAddressingModes.cs b/Chip/Q1CpuAddressingModes.cs
index 0d664f7..f809ff3 100644
--- a/Chip/Q1CpuAddressingModes.cs
+++ b/Chip/Q1CpuAddressingModes.cs
@@ -23,40 +23,55 @@ public partial class Q1Cpu
public void StoreData(u8 mode, u16 value)
{
- Console.WriteLine($"StoreData: mode={mode:X8}, value={value:X16}");
- if (mode != 0x05)
+ switch (mode)
{
- u16 address = this.FetchData(mode);
- Console.WriteLine($"StoreData: address={address:X16}");
- this.Bus.WriteWord(address, value);
- }
- else
- {
- u8 regIndex = this.Bus.Read(this.PC);
- this.PC += 1;
-
- this.StoreRegister(regIndex, value);
+ case 0x0:
+ throw new InvalidOperationException("Cannot store data in implicit mode.");
+ case 0x1:
+ throw new InvalidOperationException("Cannot store data in immediate mode.");
+ case 0x2:
+ this.AddressingMode_Direct_Store(value);
+ break;
+ case 0x3:
+ this.AddressingMode_Indirect_Store(value);
+ break;
+ case 0x4:
+ this.AddressingMode_Relative_Store(value);
+ break;
+ case 0x5:
+ this.AddressingMode_Register_Store(value);
+ break;
+ case 0x6:
+ this.AddressingMode_RegisterIndirect_Store(value);
+ break;
+ case 0x7:
+ this.AddressingMode_RegisterIndirectOffset_Store(value);
+ break;
+ default:
+ throw new InvalidOperationException($"Unknown addressing mode: {mode:X2}");
}
}
public void TransformData(u8 mode, Func<u16, u16> transform)
{
- if (mode != 0x05)
- {
- u16 address = this.FetchData(mode);
- u16 value = this.Bus.ReadWord(address);
- u16 transformedValue = transform(value);
- this.Bus.WriteWord(address, transformedValue);
- }
- else
- {
- u8 regIndex = this.Bus.Read(this.PC);
- this.PC += 1;
-
- u16 value = this.FetchRegister(regIndex);
- u16 transformedValue = transform(value);
- this.StoreRegister(regIndex, transformedValue);
- }
+ // if (mode != 0x05)
+ // {
+ // u16 address = this.FetchData(mode);
+ // u16 value = this.Bus.ReadWord(address);
+ // u16 transformedValue = transform(value);
+ // this.Bus.WriteWord(address, transformedValue);
+ // }
+ // else
+ // {
+ // u8 regIndex = this.Bus.Read(this.PC);
+ // this.PC += 1;
+ //
+ // u16 value = this.FetchRegister(regIndex);
+ // u16 transformedValue = transform(value);
+ // this.StoreRegister(regIndex, transformedValue);
+ // }
+
+ throw new NotImplementedException("TransformData is not implemented yet.");
}
public u8 AddressingModeLength(u8 mode)
@@ -132,6 +147,7 @@ public partial class Q1Cpu
u16 address = this.FetchRegister(regIndex);
u16 value = this.Bus.ReadWord(address);
+ Console.WriteLine($"Value at {address:X4}: {value:X4}");
return value;
}
@@ -140,11 +156,67 @@ public partial class Q1Cpu
u8 regIndex = this.Bus.Read(this.PC);
this.PC += 1;
- u16 offset = this.Bus.ReadWord(this.PC);
+ i16 offset = Make.i16(this.Bus.ReadSeq(this.PC, 2));
+ Console.WriteLine("Offset: " + offset);
this.PC += 2;
u16 address = (u16) (this.FetchRegister(regIndex) + offset);
u16 value = this.Bus.ReadWord(address);
return value;
}
+
+ public void AddressingMode_Direct_Store(u16 data)
+ {
+ u16 address = this.Bus.ReadWord(this.PC);
+ this.PC += 2;
+
+ this.Bus.WriteWord(address, data);
+ }
+
+ public void AddressingMode_Indirect_Store(u16 data)
+ {
+ u16 address = this.Bus.ReadWord(this.PC);
+ this.PC += 2;
+
+ u16 indirectAddress = this.Bus.ReadWord(address);
+ this.Bus.WriteWord(indirectAddress, data);
+ }
+
+ public void AddressingMode_Relative_Store(u16 data)
+ {
+ u16 offset = this.Bus.ReadWord(this.PC);
+ this.PC += 2;
+
+ u16 address = (u16) (this.PC + offset);
+ this.Bus.WriteWord(address, data);
+ }
+
+ public void AddressingMode_Register_Store(u16 data)
+ {
+ u8 regIndex = this.Bus.Read(this.PC);
+ this.PC += 1;
+
+ this.StoreRegister(regIndex, data);
+ }
+
+ public void AddressingMode_RegisterIndirect_Store(u16 data)
+ {
+ u8 regIndex = this.Bus.Read(this.PC);
+ this.PC += 1;
+
+ u16 address = this.FetchRegister(regIndex);
+ this.Bus.WriteWord(address, data);
+ }
+
+ public void AddressingMode_RegisterIndirectOffset_Store(u16 data)
+ {
+ u8 regIndex = this.Bus.Read(this.PC);
+ this.PC += 1;
+
+ i16 offset = Make.i16(this.Bus.ReadSeq(this.PC, 2));
+ this.PC += 2;
+
+ u16 address = (u16) (this.FetchRegister(regIndex) + offset);
+ this.Bus.WriteWord(address, data);
+ }
} \ No newline at end of file
diff --git a/DisplayEngine.cs b/DisplayEngine.cs
index f77598f..f983226 100644
--- a/DisplayEngine.cs
+++ b/DisplayEngine.cs
@@ -10,6 +10,7 @@ namespace Q1Emu;
public class DisplayEngine : Game
{
private readonly Action<Texture2D> _onScreenTextureLoaded;
+ private readonly Action _requestUpdate;
private GraphicsDeviceManager _graphics;
private SpriteBatch _spriteBatch;
@@ -18,12 +19,13 @@ public class DisplayEngine : Game
public int Width { get; }
public int Height { get; }
- public DisplayEngine(int width, int height, int scaling, Action<Texture2D> onScreenTextureLoaded)
+ public DisplayEngine(int width, int height, int scaling, Action<Texture2D> onScreenTextureLoaded, Action requestUpdate)
{
this.Width = width;
this.Height = height;
this.Scaling = scaling;
this._onScreenTextureLoaded = onScreenTextureLoaded;
+ this._requestUpdate = requestUpdate;
_graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
@@ -61,6 +63,8 @@ public class DisplayEngine : Game
{
GraphicsDevice.Clear(Color.CornflowerBlue);
+ this._requestUpdate();
+
_spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, SamplerState.PointClamp, DepthStencilState.None, RasterizerState.CullNone);
// Draw the texture to the screen
_spriteBatch.Draw(_texture, new Rectangle(0, 0, Width * Scaling, Height * Scaling), Color.White);
diff --git a/Make.cs b/Make.cs
index 6999c4d..293312e 100644
--- a/Make.cs
+++ b/Make.cs
@@ -1,6 +1,7 @@
namespace Q1Emu;
using System;
+using System.Buffers.Binary;
public static class Make
{
@@ -45,4 +46,8 @@ public static class Make
u8 b4 = (u8) (value & 0xFF);
return new ref8([b1, b2, b3, b4], 0, 4);
}
+ public static i16 i16(ref8 value)
+ {
+ return BinaryPrimitives.ReadInt16BigEndian(value);
+ }
} \ No newline at end of file
diff --git a/Program.cs b/Program.cs
index fab84f7..63906a0 100644
--- a/Program.cs
+++ b/Program.cs
@@ -5,6 +5,7 @@ using System.Threading;
using Microsoft.Xna.Framework;
using Q1Emu.Chip;
using Q1Emu;
+using Q1Emu.Assembler;
internal class Program
{
@@ -31,7 +32,14 @@ internal class Program
}
private static void AssembleAndRun(string filePath)
{
+ StringReader reader = new(File.ReadAllText(filePath));
+ BinaryWriter writer = new(File.Create(Path.ChangeExtension(filePath, ".q1")));
+ Assembler assembler = new(reader, writer);
+ assembler.Assemble();
+ writer.Close();
+ Console.WriteLine($"Assembled {filePath} to {Path.ChangeExtension(filePath, ".q1")}");
+ Run(Path.ChangeExtension(filePath, ".q1"));
}
private static void Run(string filePath)
{
@@ -51,6 +59,7 @@ internal class Program
cpu.Bus = bus;
ram.AttachToBus(bus);
+ display.AttachToBus(bus);
int frameRate = 600;
Thread t = new(() =>
@@ -58,7 +67,6 @@ internal class Program
while (true)
{
cpu.Clock();
- display.Clock();
Thread.Sleep(1000 / frameRate);
}
});
@@ -70,7 +78,7 @@ internal class Program
{
display.OutputTexture = tex;
Console.WriteLine("Display texture initialized.");
- });
+ }, () => display.Clock());
game.Run();
}
} \ No newline at end of file
diff --git a/Q1Emu.csproj b/Q1Emu.csproj
index f57964b..035139a 100644
--- a/Q1Emu.csproj
+++ b/Q1Emu.csproj
@@ -28,9 +28,6 @@
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.2.1105"/>
<PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.2.1105"/>
</ItemGroup>
- <ItemGroup>
- <Folder Include="ROMs\" />
- </ItemGroup>
<Target Name="RestoreDotnetTools" BeforeTargets="Restore">
<Message Text="Restoring dotnet tools" Importance="High"/>
<Exec Command="dotnet tool restore"/>
diff --git a/Q1Emu.sln.DotSettings.user b/Q1Emu.sln.DotSettings.user
index 1f447ab..e3f7764 100644
--- a/Q1Emu.sln.DotSettings.user
+++ b/Q1Emu.sln.DotSettings.user
@@ -1,2 +1,4 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
+ <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ABinaryWriter_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003Fb5ea9bfdffa3204580857642ef06a8c5c8bf9e1e0cba3035b23ebccbdf92_003FBinaryWriter_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
+ <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AConvert_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003F68661b21b92f5da34c8d2e71bca89037a38df2db50765d2a8c0ccd638188e7c_003FConvert_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AGame_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F49bab08708434a08802510b75a8ea3691b3400_003F26_003F86c71a55_003FGame_002Ecs/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary> \ No newline at end of file
diff --git a/ROMs/script.dat b/ROMs/script.dat
new file mode 100644
index 0000000..c2c5dc2
--- /dev/null
+++ b/ROMs/script.dat
@@ -0,0 +1,24 @@
+.org $1FFF
+
+program:
+MOV $0000, V0
+MUL 32, 64 ; Set V1 to 32 * 64
+MOV AX, V1 ; Copy V1 to AX
+MOV 1, V2 ; Color value 1
+
+reset:
+INC
+MOV $0000, V0 ;
+ADD V2, 1 ; Increment color value V2
+MOV AX, V2 ; Copy V2 to AX
+
+draw:
+ADD V0, 2 ; Increment V0 by 1
+MOV AX, V0 ; Copy AX to V0
+
+GT V0, V1 ; V0 > V1?
+BZ
+JMP reset
+
+MOV $06, [V0+$3FFF] ; Set pixel at V0 to color 6
+JMP draw ; Repeat drawing \ No newline at end of file
diff --git a/ROMs/script.q1 b/ROMs/script.q1
new file mode 100644
index 0000000..3de4840
--- /dev/null
+++ b/ROMs/script.q1
Binary files differ
diff --git a/ROMs/test.q1 b/ROMs/test.q1
index d0c089f..b166c7a 100644
--- a/ROMs/test.q1
+++ b/ROMs/test.q1
Binary files differ