diff options
| author | Melodi <62381002+Melodi17@users.noreply.github.com> | 2025-08-04 12:07:39 +1000 |
|---|---|---|
| committer | Melodi <62381002+Melodi17@users.noreply.github.com> | 2025-08-04 12:07:39 +1000 |
| commit | 72f297a479b6749674ec80e91be53b8c482123d2 (patch) | |
| tree | 05465784b2b5b5adbd695b50e8394c6f78e3a455 | |
| parent | 86452af2d48e2d1883dbfd67316e371f2a593bfe (diff) | |
crowbar
| -rw-r--r-- | Assembler/Assembler.cs | 221 | ||||
| -rw-r--r-- | Assembler/Disassembler.cs | 87 | ||||
| -rw-r--r-- | Chip/Bus.cs | 2 | ||||
| -rw-r--r-- | Chip/DisplayDevice.cs | 15 | ||||
| -rw-r--r-- | Chip/Q1Cpu.cs | 3 | ||||
| -rw-r--r-- | Chip/Q1CpuAddressingModes.cs | 130 | ||||
| -rw-r--r-- | DisplayEngine.cs | 6 | ||||
| -rw-r--r-- | Make.cs | 5 | ||||
| -rw-r--r-- | Program.cs | 12 | ||||
| -rw-r--r-- | Q1Emu.csproj | 3 | ||||
| -rw-r--r-- | Q1Emu.sln.DotSettings.user | 2 | ||||
| -rw-r--r-- | ROMs/script.dat | 24 | ||||
| -rw-r--r-- | ROMs/script.q1 | bin | 0 -> 67 bytes | |||
| -rw-r--r-- | ROMs/test.q1 | bin | 10 -> 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); @@ -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 @@ -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 Binary files differnew file mode 100644 index 0000000..3de4840 --- /dev/null +++ b/ROMs/script.q1 diff --git a/ROMs/test.q1 b/ROMs/test.q1 Binary files differindex d0c089f..b166c7a 100644 --- a/ROMs/test.q1 +++ b/ROMs/test.q1 |
