From 7a8d2bcd75d88a5429937bf551878c55e1dcf0fd Mon Sep 17 00:00:00 2001
From: Melodi <62381002+Melodi17@users.noreply.github.com>
Date: Wed, 6 Aug 2025 22:36:34 +1000
Subject: moved everything to seperate projects, and started compiler work +
push and pop instructions added
---
.DS_Store | Bin 8196 -> 10244 bytes
.fleet/run.json | 11 -
.idea/.idea.Q1/.idea/.gitignore | 13 +
.../.idea/ANTLRv4ToolGrammarProperties.xml | 42 +
.idea/.idea.Q1/.idea/encodings.xml | 4 +
.idea/.idea.Q1/.idea/indexLayout.xml | 8 +
.idea/.idea.Q1/.idea/misc.xml | 10 +
.idea/.idea.Q1/.idea/vcs.xml | 6 +
Assembler/Assembler.cs | 328 ++++---
Assembler/Assembler.csproj | 19 +
Assembler/Disassembler.cs | 74 --
Assembler/Extensions.cs | 15 +
Assembler/GlobalUsings.cs | 12 +
Assembler/Options.cs | 12 +
Assembler/Program.cs | 38 +
Chip/Bus.cs | 37 -
Chip/BusDevice.cs | 56 --
Chip/DisplayDevice.cs | 78 --
Chip/Q1Cpu.cs | 156 ---
Chip/Q1CpuAddressingModes.cs | 188 ----
Chip/Q1CpuInstructions.cs | 266 ------
Chip/RamDevice.cs | 36 -
Chip8Emu2.sln.DotSettings.user | 2 -
Compiler/CCompilerVisitor.cs | 172 ++++
Compiler/CGrammar.g4 | 50 +
Compiler/Compiler.csproj | 20 +
Compiler/CompilerException.cs | 4 +
Compiler/Options.cs | 12 +
Compiler/Program.cs | 31 +
Compiler/gen/CGrammar.interp | 70 ++
Compiler/gen/CGrammar.tokens | 52 +
Compiler/gen/CGrammarBaseVisitor.cs | 299 ++++++
Compiler/gen/CGrammarLexer.cs | 149 +++
Compiler/gen/CGrammarLexer.interp | 98 ++
Compiler/gen/CGrammarLexer.tokens | 52 +
Compiler/gen/CGrammarParser.cs | 1006 ++++++++++++++++++++
Compiler/gen/CGrammarVisitor.cs | 200 ++++
Content/Content.mgcb | 15 -
DisplayEngine.cs | 76 --
Emulator/.DS_Store | Bin 0 -> 6148 bytes
Emulator/Assembler/Disassembler.cs | 74 ++
Emulator/Chip/Bus.cs | 37 +
Emulator/Chip/BusDevice.cs | 49 +
Emulator/Chip/DebugDevice.cs | 13 +
Emulator/Chip/DisplayDevice.cs | 76 ++
Emulator/Chip/Q1Cpu.cs | 171 ++++
Emulator/Chip/Q1CpuAddressingModes.cs | 187 ++++
Emulator/Chip/Q1CpuInstructions.cs | 282 ++++++
Emulator/Chip/RamDevice.cs | 33 +
Emulator/Content/Content.mgcb | 15 +
Emulator/DisplayEngine.cs | 76 ++
Emulator/Emulator.csproj | 32 +
Emulator/Extensions.cs | 23 +
Emulator/GlobalUsings.cs | 12 +
Emulator/Icon.bmp | Bin 0 -> 262282 bytes
Emulator/Icon.ico | Bin 0 -> 147541 bytes
Emulator/Make.cs | 58 ++
Emulator/Options.cs | 7 +
Emulator/Program.cs | 82 ++
Extensions.cs | 23 -
GlobalUsings.cs | 12 -
Icon.bmp | Bin 262282 -> 0 bytes
Icon.ico | Bin 147541 -> 0 bytes
Make.cs | 58 --
Program.cs | 106 ---
Q1.sln | 28 +
Q1.sln.DotSettings.user | 2 +
Q1Emu.csproj | 35 -
Q1Emu.sln | 16 -
Q1Emu.sln.DotSettings.user | 4 -
ROMs/.DS_Store | Bin 6148 -> 6148 bytes
ROMs/font copy.bin | Bin 32768 -> 0 bytes
ROMs/font.bin | Bin 32768 -> 2048 bytes
ROMs/hello_c.asm | 7 +
ROMs/hello_c.c | 4 +
ROMs/hello_c.q1 | Bin 0 -> 22 bytes
ROMs/hello_world.asm | 42 +
ROMs/hello_world.dat | 33 -
ROMs/hello_world.q1 | Bin 32842 -> 2151 bytes
ROMs/write_display_direct.asm | 21 +
ROMs/write_display_direct.dat | 21 -
app.manifest | 43 -
82 files changed, 3908 insertions(+), 1491 deletions(-)
delete mode 100644 .fleet/run.json
create mode 100644 .idea/.idea.Q1/.idea/.gitignore
create mode 100644 .idea/.idea.Q1/.idea/ANTLRv4ToolGrammarProperties.xml
create mode 100644 .idea/.idea.Q1/.idea/encodings.xml
create mode 100644 .idea/.idea.Q1/.idea/indexLayout.xml
create mode 100644 .idea/.idea.Q1/.idea/misc.xml
create mode 100644 .idea/.idea.Q1/.idea/vcs.xml
create mode 100644 Assembler/Assembler.csproj
delete mode 100644 Assembler/Disassembler.cs
create mode 100644 Assembler/Extensions.cs
create mode 100644 Assembler/GlobalUsings.cs
create mode 100644 Assembler/Options.cs
create mode 100644 Assembler/Program.cs
delete mode 100644 Chip/Bus.cs
delete mode 100644 Chip/BusDevice.cs
delete mode 100644 Chip/DisplayDevice.cs
delete mode 100644 Chip/Q1Cpu.cs
delete mode 100644 Chip/Q1CpuAddressingModes.cs
delete mode 100644 Chip/Q1CpuInstructions.cs
delete mode 100644 Chip/RamDevice.cs
delete mode 100644 Chip8Emu2.sln.DotSettings.user
create mode 100644 Compiler/CCompilerVisitor.cs
create mode 100644 Compiler/CGrammar.g4
create mode 100644 Compiler/Compiler.csproj
create mode 100644 Compiler/CompilerException.cs
create mode 100644 Compiler/Options.cs
create mode 100644 Compiler/Program.cs
create mode 100644 Compiler/gen/CGrammar.interp
create mode 100644 Compiler/gen/CGrammar.tokens
create mode 100644 Compiler/gen/CGrammarBaseVisitor.cs
create mode 100644 Compiler/gen/CGrammarLexer.cs
create mode 100644 Compiler/gen/CGrammarLexer.interp
create mode 100644 Compiler/gen/CGrammarLexer.tokens
create mode 100644 Compiler/gen/CGrammarParser.cs
create mode 100644 Compiler/gen/CGrammarVisitor.cs
delete mode 100644 Content/Content.mgcb
delete mode 100644 DisplayEngine.cs
create mode 100644 Emulator/.DS_Store
create mode 100644 Emulator/Assembler/Disassembler.cs
create mode 100644 Emulator/Chip/Bus.cs
create mode 100644 Emulator/Chip/BusDevice.cs
create mode 100644 Emulator/Chip/DebugDevice.cs
create mode 100644 Emulator/Chip/DisplayDevice.cs
create mode 100644 Emulator/Chip/Q1Cpu.cs
create mode 100644 Emulator/Chip/Q1CpuAddressingModes.cs
create mode 100644 Emulator/Chip/Q1CpuInstructions.cs
create mode 100644 Emulator/Chip/RamDevice.cs
create mode 100644 Emulator/Content/Content.mgcb
create mode 100644 Emulator/DisplayEngine.cs
create mode 100644 Emulator/Emulator.csproj
create mode 100644 Emulator/Extensions.cs
create mode 100644 Emulator/GlobalUsings.cs
create mode 100644 Emulator/Icon.bmp
create mode 100644 Emulator/Icon.ico
create mode 100644 Emulator/Make.cs
create mode 100644 Emulator/Options.cs
create mode 100644 Emulator/Program.cs
delete mode 100644 Extensions.cs
delete mode 100644 GlobalUsings.cs
delete mode 100644 Icon.bmp
delete mode 100644 Icon.ico
delete mode 100644 Make.cs
delete mode 100644 Program.cs
create mode 100644 Q1.sln
create mode 100644 Q1.sln.DotSettings.user
delete mode 100644 Q1Emu.csproj
delete mode 100644 Q1Emu.sln
delete mode 100644 Q1Emu.sln.DotSettings.user
delete mode 100644 ROMs/font copy.bin
create mode 100644 ROMs/hello_c.asm
create mode 100644 ROMs/hello_c.c
create mode 100644 ROMs/hello_c.q1
create mode 100644 ROMs/hello_world.asm
delete mode 100644 ROMs/hello_world.dat
create mode 100644 ROMs/write_display_direct.asm
delete mode 100644 ROMs/write_display_direct.dat
delete mode 100644 app.manifest
diff --git a/.DS_Store b/.DS_Store
index b56fb2b..a997d4b 100644
Binary files a/.DS_Store and b/.DS_Store differ
diff --git a/.fleet/run.json b/.fleet/run.json
deleted file mode 100644
index 5ae6c96..0000000
--- a/.fleet/run.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "configurations": [
- {
- "type": "dotnet",
- "name": "Dotnet configuration",
- "projectPath": "$PROJECT_DIR$",
- "solutionPath": "$PROJECT_DIR$",
- "args": []
- }
- ]
-}
\ No newline at end of file
diff --git a/.idea/.idea.Q1/.idea/.gitignore b/.idea/.idea.Q1/.idea/.gitignore
new file mode 100644
index 0000000..842bf41
--- /dev/null
+++ b/.idea/.idea.Q1/.idea/.gitignore
@@ -0,0 +1,13 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Rider ignored files
+/contentModel.xml
+/projectSettingsUpdater.xml
+/.idea.Q1.iml
+/modules.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/.idea.Q1/.idea/ANTLRv4ToolGrammarProperties.xml b/.idea/.idea.Q1/.idea/ANTLRv4ToolGrammarProperties.xml
new file mode 100644
index 0000000..bb8d49b
--- /dev/null
+++ b/.idea/.idea.Q1/.idea/ANTLRv4ToolGrammarProperties.xml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.Q1/.idea/encodings.xml b/.idea/.idea.Q1/.idea/encodings.xml
new file mode 100644
index 0000000..df87cf9
--- /dev/null
+++ b/.idea/.idea.Q1/.idea/encodings.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.Q1/.idea/indexLayout.xml b/.idea/.idea.Q1/.idea/indexLayout.xml
new file mode 100644
index 0000000..7b08163
--- /dev/null
+++ b/.idea/.idea.Q1/.idea/indexLayout.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.Q1/.idea/misc.xml b/.idea/.idea.Q1/.idea/misc.xml
new file mode 100644
index 0000000..5207dea
--- /dev/null
+++ b/.idea/.idea.Q1/.idea/misc.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.Q1/.idea/vcs.xml b/.idea/.idea.Q1/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/.idea.Q1/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Assembler/Assembler.cs b/Assembler/Assembler.cs
index 09ac30e..7c172e7 100644
--- a/Assembler/Assembler.cs
+++ b/Assembler/Assembler.cs
@@ -1,21 +1,11 @@
-namespace Q1Emu.Assembler;
+namespace Q1.Assembler;
-using System;
-using System.Collections.Generic;
using System.Diagnostics;
-using System.IO;
-using System.Linq;
-using Chip;
+using Emulator;
+using Emulator.Chip;
public class Assembler
{
- public readonly BinaryWriter Writer;
- public readonly StringReader Reader;
-
- private Dictionary _labels = new();
- private Dictionary _unloadedLabels = new();
- private u16 _addressOffset = 0;
-
public static Dictionary RegisterLookup = new()
{
{ 0x40, "AX" },
@@ -26,30 +16,31 @@ public class Assembler
{ 0x45, "DL" },
{ 0x46, "LX" },
{ 0x50, "PC" },
- { 0x51, "SP" },
+ { 0x51, "SP" }
};
+ private readonly string[] InputLines;
+
+ private readonly Dictionary _labels = new();
- public Assembler(StringReader reader, BinaryWriter writer)
+ public Assembler(string[] inputLines)
{
- this.Reader = reader;
- this.Writer = writer;
+ this.InputLines = inputLines;
}
- public void Assemble()
+ private void ResolveLabels()
{
- int lineNumber = 0;
- while (this.Reader.ReadLine() is { } line)
+ int offset = 0;
+ int pos = 0;
+ foreach (string line in this.InputLines)
{
- lineNumber++;
- string trimmedLine = line.Split(";")[0].Trim(); // Remove comments
+ string trimmedLine = line.Split(";")[0].Trim();
if (string.IsNullOrEmpty(trimmedLine) || trimmedLine.StartsWith(';'))
continue;
if (trimmedLine.StartsWith(".org"))
{
- // Handle .org directive
string orgValue = trimmedLine[5..].Trim();
- this._addressOffset = this.GetConstant(orgValue);
+ offset = this.GetConstant(orgValue);
}
else if (trimmedLine.StartsWith(".ascii"))
@@ -61,6 +52,7 @@ public class Assembler
{
char c = asciiValue[i];
if (c == '\\')
+ {
c = asciiValue[++i] switch
{
'n' => '\n',
@@ -68,90 +60,173 @@ public class Assembler
'\\' => '\\',
'\'' => '\'',
'"' => '"',
- _ => throw new AssemblerException($"Unknown escape sequence: \\{asciiValue[i]}"),
+ _ => throw new AssemblerException($"Unknown escape sequence: \\{asciiValue[i]}")
};
+ }
- this.Write((u8) c);
+ pos++;
}
}
else if (trimmedLine.StartsWith(".raw"))
{
string[] values = trimmedLine[5..].Split(',');
- foreach (string value in values)
- this.Write(GetConstant(value.Trim()));
+ pos += values.Length * 2; // Each value is 2 bytes
}
-
+
else if (trimmedLine.StartsWith(".include"))
{
string includeFile = trimmedLine[9..].Trim()[1..^1];
if (!File.Exists(includeFile))
- {
- WriteError(line, lineNumber, $"Include file '{includeFile}' not found");
- return;
- }
+ throw new AssemblerException($"Include file '{includeFile}' not found");
- foreach (byte b in File.ReadAllBytes(includeFile))
- this.Writer.Write(b);
+ pos += File.ReadAllBytes(includeFile).Length;
}
else if (trimmedLine.EndsWith(":"))
- this._labels[trimmedLine[..^1]] = (u16) (this.Writer.BaseStream.Position + this._addressOffset);
+ {
+ string label = trimmedLine[..^1].Trim();
+ if (this._labels.ContainsKey(label))
+ throw new AssemblerException($"Label '{label}' already defined");
+ this._labels[label] = (u16) (pos + offset);
+ }
else
+ pos += this.GetInstructionLength(trimmedLine);
+ }
+ }
+
+ public IEnumerable Assemble()
+ {
+ this.ResolveLabels();
+
+ foreach (string line in this.InputLines)
+ {
+ string trimmedLine = line.Split(";")[0].Trim(); // Remove comments
+ if (string.IsNullOrEmpty(trimmedLine) || trimmedLine.StartsWith(';'))
+ continue;
+
+ if (trimmedLine.StartsWith(".org"))
+ {
+ // Already handled in ResolveLabels
+ }
+
+ else if (trimmedLine.StartsWith(".ascii"))
{
- try
+ string asciiValue = trimmedLine[7..].Trim()
+ [1..^1]; // Remove quotes
+
+ for (int i = 0; i < asciiValue.Length; i++)
{
- this.ParseInstruction(trimmedLine);
+ char c = asciiValue[i];
+ if (c == '\\')
+ {
+ c = asciiValue[++i] switch
+ {
+ 'n' => '\n',
+ 't' => '\t',
+ '\\' => '\\',
+ '\'' => '\'',
+ '"' => '"',
+ _ => throw new AssemblerException($"Unknown escape sequence: \\{asciiValue[i]}")
+ };
+ }
+
+ yield return (byte) c;
}
- catch (AssemblerException ex)
+ }
+
+ else if (trimmedLine.StartsWith(".raw"))
+ {
+ string[] values = trimmedLine[5..].Split(',');
+ foreach (string value in values)
{
- WriteError(line, lineNumber, ex.Message);
- return;
+ u16 c = this.GetConstant(value.Trim());
+
+ yield return c.High();
+ yield return c.Low();
}
}
- }
- foreach ((u16 key, string value) in this._unloadedLabels)
- {
- if (this._labels.TryGetValue(value, out u16 address))
+ else if (trimmedLine.StartsWith(".include"))
{
- Console.WriteLine($"Resolving label '{value}' at address {address:X4} for key {key:X4}");
- this.Writer.BaseStream.Seek(key, SeekOrigin.Begin);
- this.Write(address);
+ string includeFile = trimmedLine[9..].Trim()[1..^1];
+ if (!File.Exists(includeFile))
+ throw new AssemblerException($"Include file '{includeFile}' not found");
+
+ foreach (byte b in File.ReadAllBytes(includeFile))
+ yield return b;
}
- else
+
+ else if (trimmedLine.EndsWith(":"))
{
- WriteError($"", 0, "Label not defined");
+ // Handled in ResolveLabels
}
+
+ else
+ foreach (byte b in this.GetInstructionBytes(trimmedLine))
+ yield return b;
}
}
- private void WriteError(string line, int lineNumber, string message)
+ private int GetInstructionLength(string instruction)
{
- Console.ForegroundColor = ConsoleColor.Red;
- Console.WriteLine($"Error on line {lineNumber}: {message}");
- Console.WriteLine($" --> {line}");
- Console.ResetColor();
+ string[] parts = instruction.Split(' ', 2);
+ string opcode = parts[0].ToUpperInvariant();
+
+ parts = parts.Length > 1 ? parts[1].Split(',') : [];
+ if (parts.Length > 2)
+ throw new AssemblerException("Invalid instruction format");
+
+ u8 opcodeValue = this.ResolveOpcode(opcode, parts.Length, out u8 addressingIndex);
+ (u8 m1, u8 m2) = this.ResolveAddressingModes(addressingIndex, parts);
+
+ int length = 2; // Opcode + mode byte
+
+ if (parts.Length > 0)
+ length += this.GetModeLength(m1);
+
+ if (parts.Length > 1)
+ length += this.GetModeLength(m2);
+
+ return length;
}
- private void ParseInstruction(string instruction)
+ private IEnumerable GetInstructionBytes(string instruction)
{
string[] parts = instruction.Split(' ', 2);
string opcode = parts[0].ToUpperInvariant();
parts = parts.Length > 1 ? parts[1].Split(',') : [];
if (parts.Length > 2)
- throw new AssemblerException($"Invalid instruction format");
+ throw new AssemblerException("Invalid instruction format");
+
+ u8 opcodeValue = this.ResolveOpcode(opcode, parts.Length, out u8 addressingIndex);
+ (u8 m1, u8 m2) = this.ResolveAddressingModes(addressingIndex, parts);
+
+ yield return opcodeValue;
+ yield return (u8) ((m1 << 4) | m2); // Combine m1 and m2 into a single byte
- u8 opcodeValue = this.ParseOpcode(opcode, parts.Length, out u8 addressingIndex);
+ if (parts.Length > 0)
+ {
+ foreach (byte b in this.GetModeBytes(m1, parts[0]))
+ yield return b;
+ }
+ if (parts.Length > 1)
+ {
+ foreach (byte b in this.GetModeBytes(m2, parts[1]))
+ yield return b;
+ }
+ }
+ private (u8 m1, u8 m2) ResolveAddressingModes(u8 addressingIndex, string[] parts)
+ {
u8 m1, m2;
switch (addressingIndex)
{
case 0: // Implicit
if (parts.Length > 0)
- throw new AssemblerException($"Implicit instruction should not have operands");
+ throw new AssemblerException("Implicit instruction should not have operands");
m1 = 0x00;
m2 = 0x00;
@@ -159,17 +234,17 @@ public class Assembler
case 1: // Simple addressing mode
if (parts.Length > 2)
- throw new AssemblerException($"Simple addressing mode should have at most one operand");
+ throw new AssemblerException("Simple addressing mode should have at most one operand");
if (parts.Length == 0)
- throw new AssemblerException($"Simple addressing mode requires an operand");
+ throw new AssemblerException("Simple addressing mode requires an operand");
- m1 = this.ParseMode(parts[0]);
+ m1 = this.ResolveMode(parts[0]);
m2 = 0x00;
break;
case 2: // Extended implicit
if (parts.Length > 0)
- throw new AssemblerException($"Extended implicit instruction should not have operands");
+ throw new AssemblerException("Extended implicit instruction should not have operands");
m1 = 0x00;
m2 = 0x01;
@@ -177,25 +252,19 @@ public class Assembler
case 3: // Dual addressing mode
if (parts.Length != 2)
- throw new AssemblerException($"Dual addressing mode requires exactly two operands");
+ throw new AssemblerException("Dual addressing mode requires exactly two operands");
- m1 = this.ParseMode(parts[0]);
- m2 = this.ParseMode(parts[1]);
+ m1 = this.ResolveMode(parts[0]);
+ m2 = this.ResolveMode(parts[1]);
break;
default:
throw new UnreachableException("Invalid addressing index: " + addressingIndex);
}
-
- this.WriteInstruction(opcodeValue, m1, m2);
-
- if (parts.Length > 0)
- this.WriteMode(m1, parts[0]);
- if (parts.Length > 1)
- this.WriteMode(m2, parts[1]);
+ return (m1, m2);
}
- private u8 ParseOpcode(string opcode, int parts, out u8 addressingIndex)
+ private u8 ResolveOpcode(string opcode, int parts, out u8 addressingIndex)
{
List addressingIndices = new();
u8? opCode = null;
@@ -231,7 +300,7 @@ public class Assembler
return opCode.Value;
}
- private u8 ParseMode(string mode)
+ private u8 ResolveMode(string mode)
{
mode = mode.Trim();
@@ -244,14 +313,10 @@ public class Assembler
}
if (this._labels.ContainsKey(mode))
- {
return 0x01; // Immediate
- }
if (mode.StartsWith("@"))
- {
return 0x03; // Indirect
- }
if (mode.StartsWith("[") && mode.EndsWith("]"))
{
@@ -271,13 +336,7 @@ public class Assembler
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)
+ private byte[] GetModeBytes(u8 mode, string operand)
{
operand = operand.Trim();
@@ -285,53 +344,66 @@ public class Assembler
{
case 0x00: // Implicit
// No additional data needed
- break;
+ return [];
case 0x01: // Immediate
u16 immediateValue = this.GetConstant(operand);
- this.Write(immediateValue);
- break;
+ return [immediateValue.High(), immediateValue.Low()];
case 0x02: // Direct
u16 directAddress = this.GetConstant(operand); // Remove brackets
- this.Write(directAddress);
- break;
+ return [directAddress.High(), directAddress.Low()];
case 0x03: // Indirect
u16 indirectAddress = this.GetConstant(operand); // Remove brackets and @
- this.Write(indirectAddress);
- break;
+ return [indirectAddress.High(), indirectAddress.Low()];
case 0x04: // Relative
- i16 relativeOffset = this.GetSignedConstant(operand);
- Write(relativeOffset);
- break;
+ u16 relativeOffset = this.GetConstant(operand);
+ return [relativeOffset.High(), relativeOffset.Low()];
case 0x05: // Register
u8 regIndex = this.GetRegisterIndex(operand);
- Write(regIndex);
- break;
+ return [regIndex];
case 0x06: // Register Indirect
u8 indirectRegIndex = this.GetRegisterIndex(operand); // Remove brackets
- Write(indirectRegIndex);
- break;
+ return [indirectRegIndex];
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;
+ u16 offsetValue = this.GetConstant(operand[1..^1].Split('+')[1].Trim());
+ return [offsetRegIndex, offsetValue.High(), offsetValue.Low()];
+
+ default:
+ throw new AssemblerException($"Unknown addressing mode: {mode:X2}");
}
}
+
+ private int GetModeLength(u8 mode)
+ {
+ return mode switch
+ {
+ 0x00 => 0, // Implicit
+ 0x01 => 2, // Immediate
+ 0x02 => 2, // Direct
+ 0x03 => 2, // Indirect
+ 0x04 => 2, // Relative
+ 0x05 => 1, // Register
+ 0x06 => 1, // Register indirect
+ 0x07 => 3, // Register indirect with offset
+ _ => throw new AssemblerException($"Unknown addressing mode: {mode:X2}")
+ };
+ }
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;
+ }
if (Assembler.RegisterLookup.ContainsValue(reg))
{
@@ -351,32 +423,15 @@ public class Assembler
u16 x = Convert.ToUInt16(value[1..], 16);
return x;
}
- else if (u16.TryParse(value, out u16 result))
+ if (u16.TryParse(value, out u16 result))
// Decimal constant
return result;
- else
- {
- this._unloadedLabels[(u16) this.Writer.BaseStream.Position] = value;
- return 0;
- }
- }
- 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
- {
- this._unloadedLabels[(u16) this.Writer.BaseStream.Position] = value;
- return 0;
- }
+
+ if (this._labels.TryGetValue(value, out u16 labelAddress))
+ // Label reference
+ return labelAddress;
+
+ return 0;
}
private string Clean(string value)
@@ -389,23 +444,6 @@ public class Assembler
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);
- }
}
public class AssemblerException(string message)
diff --git a/Assembler/Assembler.csproj b/Assembler/Assembler.csproj
new file mode 100644
index 0000000..fd4f4fa
--- /dev/null
+++ b/Assembler/Assembler.csproj
@@ -0,0 +1,19 @@
+
+
+
+ Exe
+ net9.0
+ enable
+ enable
+ Q1.Assembler
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Assembler/Disassembler.cs b/Assembler/Disassembler.cs
deleted file mode 100644
index 816ddbc..0000000
--- a/Assembler/Disassembler.cs
+++ /dev/null
@@ -1,74 +0,0 @@
-namespace Q1Emu.Assembler;
-
-using System;
-using System.Collections.Generic;
-using System.IO;
-using Chip;
-
-public class Disassembler
-{
- public readonly StringWriter Writer;
- public readonly BinaryReader Reader;
-
- public Disassembler(StringWriter writer, BinaryReader reader)
- {
- this.Writer = writer;
- this.Reader = reader;
- }
-
- private static Dictionary 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, 0x01) => 2, // Extended implicit
- (_, 0x00) => 1, // Simple addressing mode
- _ => 3 // Extended addressing mode
- };
-
- string opcodeName = GetOpcodeName(op, i);
-
- if (i == 0 || i == 2)
- return opcodeName;
-
- if (i == 1)
- return $"{opcodeName} {GetModeName(m1)}";
-
- if (i == 3)
- return $"{opcodeName} {GetModeName(m1)}, {GetModeName(m2)}";
-
- 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 (!Q1Cpu.InstructionLookupStrings.TryGetValue(opcode, out string[]? opNames))
- return $"[{opcode:X2}]"; // Fallback for unknown opcodes
-
- return opNames[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/Assembler/Extensions.cs b/Assembler/Extensions.cs
new file mode 100644
index 0000000..fd4ea1f
--- /dev/null
+++ b/Assembler/Extensions.cs
@@ -0,0 +1,15 @@
+namespace Q1.Assembler;
+
+public static class Extensions
+{
+
+ public static u8 High(this u16 value)
+ {
+ return (u8)(value >> 8);
+ }
+
+ public static u8 Low(this u16 value)
+ {
+ return (u8)(value & 0xFF);
+ }
+}
\ No newline at end of file
diff --git a/Assembler/GlobalUsings.cs b/Assembler/GlobalUsings.cs
new file mode 100644
index 0000000..ff38a75
--- /dev/null
+++ b/Assembler/GlobalUsings.cs
@@ -0,0 +1,12 @@
+// Integer type aliases
+global using i8 = sbyte; // -128 to 127
+global using u8 = byte; // 0 to 255
+global using i16 = short; // -32,768 to 32,767
+global using u16 = ushort; // 0 to 65,535
+global using i32 = int; // -2,147,483,648 to 2,147,483,647
+global using u32 = uint; // 0 to 4,294,967,295
+global using i64 = long; // -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
+global using u64 = ulong; // 0 to 18,446,744,073,709,551,615
+
+global using ref8 = System.Span;
+global using data8 = byte[];
diff --git a/Assembler/Options.cs b/Assembler/Options.cs
new file mode 100644
index 0000000..dc4efc2
--- /dev/null
+++ b/Assembler/Options.cs
@@ -0,0 +1,12 @@
+namespace Q1.Assembler;
+
+using CommandLine;
+
+public class Options
+{
+ [Option('i', "input", Required = true, HelpText = "Input file to assemble.")]
+ public string InputFile { get; set; }
+
+ [Option('o', "output", Required = true, HelpText = "Output file to write the assembled code.")]
+ public string OutputFile { get; set; }
+}
\ No newline at end of file
diff --git a/Assembler/Program.cs b/Assembler/Program.cs
new file mode 100644
index 0000000..b30df1e
--- /dev/null
+++ b/Assembler/Program.cs
@@ -0,0 +1,38 @@
+namespace Q1.Assembler;
+
+using CommandLine;
+
+public class Program
+{
+ static void Main(string[] args)
+ {
+ Parser.Default.ParseArguments(args).WithParsed(Program.Main);
+ }
+
+ static void Main(Options options)
+ {
+ Environment.CurrentDirectory = Path.GetDirectoryName(options.InputFile) ?? Environment.CurrentDirectory;
+ options.InputFile = Path.GetFileName(options.InputFile);
+
+ string[] input = File.ReadAllLines(options.InputFile);
+
+ try
+ {
+ Assembler assembler = new(input);
+ byte[] bin = assembler.Assemble().ToArray();
+ if (bin.Length > 8 * 1024)
+ throw new AssemblerException("Assembled binary exceeds maximum size of 8KB.");
+
+ File.WriteAllBytes(options.OutputFile, bin);
+
+ Console.WriteLine($"Assembled {options.InputFile} to {options.OutputFile} ({bin.Length} bytes)");
+ }
+ catch (AssemblerException ex)
+ {
+ Console.ForegroundColor = ConsoleColor.Red;
+ Console.Error.WriteLine($"Error: {ex.Message}");
+ Console.ResetColor();
+ Environment.Exit(1);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Chip/Bus.cs b/Chip/Bus.cs
deleted file mode 100644
index 3578ad6..0000000
--- a/Chip/Bus.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-namespace Q1Emu.Chip;
-
-using System.Collections.Generic;
-using System.Linq;
-
-public class Bus : BusDevice
-{
- public List Devices;
-
- public Bus(u16 addressableStart, u16 addressableEnd) : base(addressableStart, addressableEnd)
- {
- this.Devices = [];
- }
- private BusDevice? GetDevice(u16 address)
- {
- BusDevice? device = this.Devices.FirstOrDefault(x => address >= x.AddressableStart && address < x.AddressableEnd);
- return device;
- }
-
- public override u8 Read(u16 address)
- {
- BusDevice? device = GetDevice(address);
- if (device == null)
- return 0;
-
- return device.Read(address);
- }
-
- public override void Write(u16 address, u8 value)
- {
- BusDevice? device = GetDevice(address);
- if (device == null)
- return;
-
- device.Write(address, value);
- }
-}
\ No newline at end of file
diff --git a/Chip/BusDevice.cs b/Chip/BusDevice.cs
deleted file mode 100644
index 8b677c5..0000000
--- a/Chip/BusDevice.cs
+++ /dev/null
@@ -1,56 +0,0 @@
-namespace Q1Emu.Chip;
-
-using System.Runtime.CompilerServices;
-
-public abstract class BusDevice
-{
- public BusDevice(u16 addressableStart, u16 addressableEnd)
- {
- this.AddressableStart = addressableStart;
- this.AddressableEnd = addressableEnd;
- }
-
- public Bus Bus { get; set; }
- public abstract u8 Read(u16 address);
- public abstract void Write(u16 address, u8 value);
-
- public u16 ReadWord(u16 address)
- {
- u8 high = this.Read(address);
- u8 low = this.Read((u16) (address + 1));
- u16 value = Make.u16(high, low);
- return value;
- }
-
- public void WriteWord(u16 address, u16 value)
- {
- ref8 data = Make.ref8(value);
- this.Write(address, data[0]);
- this.Write((u16) (address + 1), data[1]);
- }
-
- public i16 ReadSignedWord(u16 address)
- {
- u8 high = this.Read(address);
- u8 low = this.Read((u16) (address + 1));
- return Make.i16(high, low);
- }
-
- public virtual void Clock() { }
- public virtual void Reset() { }
-
- public void AttachToBus(Bus bus)
- {
- this.Bus = bus;
- bus.Devices.Add(this);
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- protected u16 GetRelativeAddress(u16 address)
- {
- return (u16) (address - this.AddressableStart);
- }
-
- public u16 AddressableStart { get; }
- public u16 AddressableEnd { get; }
-}
\ No newline at end of file
diff --git a/Chip/DisplayDevice.cs b/Chip/DisplayDevice.cs
deleted file mode 100644
index 1bf4f14..0000000
--- a/Chip/DisplayDevice.cs
+++ /dev/null
@@ -1,78 +0,0 @@
-namespace Q1Emu.Chip;
-
-using System;
-using System.Collections.Generic;
-using System.Threading;
-using Microsoft.Xna.Framework;
-using Microsoft.Xna.Framework.Graphics;
-
-public class DisplayDevice : RamDevice
-{
- public Texture2D? OutputTexture;
- 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))
- {
- 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)
- {
- return (u16) ((paletteSize * 3) + (displayWidth * displayHeight));
- }
-
- public override void Clock()
- {
- Color[] palette = this.ReadPalette();
- ref8 pixelData = this.Memory.AsSpan((u16) (this._paletteSize * 3), (u16) (this._displayWidth * this._displayHeight));
- // Console.WriteLine($"DisplayDevice.Clock: @{(this.AddressableStart + this._paletteSize * 3):X4} palette size={this._paletteSize} display size={this._displayWidth}x{this._displayHeight}");
- for (u16 i = 0; i < textureData.Length; i++)
- {
- u8 pixelValue = pixelData[i];
- textureData[i] = palette[pixelValue % this._paletteSize];
- }
-
- if (this.OutputTexture != null)
- this.OutputTexture.SetData(textureData);
- }
-
- private Color[] ReadPalette()
- {
- ref8 paletteData = this.Memory.AsSpan(0, (u16) (this._paletteSize * 3));
- Color[] colors = new Color[this._paletteSize + 1];
- colors[0] = Color.Transparent;
-
- for (u16 i = 0; i < this._paletteSize; i++)
- {
- u16 offset = (u16) (i * 3);
- byte r = paletteData[offset];
- byte g = paletteData[offset + 1];
- byte b = paletteData[offset + 2];
- colors[(u16) (i + 1)] = new Color(r, g, b);
- }
-
- return colors;
- }
-
- public void SetPalette(Color[] palette)
- {
- if (palette.Length != this._paletteSize)
- throw new ArgumentException($"Palette must have {this._paletteSize} colors.");
-
- ref8 paletteData = this.Memory.AsSpan(0, (u16) (this._paletteSize * 3));
- for (u16 i = 0; i < this._paletteSize; i++)
- {
- u16 offset = (u16) (i * 3);
- paletteData[offset] = palette[i].R;
- paletteData[offset + 1] = palette[i].G;
- paletteData[offset + 2] = palette[i].B;
- }
- }
-}
\ No newline at end of file
diff --git a/Chip/Q1Cpu.cs b/Chip/Q1Cpu.cs
deleted file mode 100644
index eefc61c..0000000
--- a/Chip/Q1Cpu.cs
+++ /dev/null
@@ -1,156 +0,0 @@
-using System;
-
-namespace Q1Emu.Chip;
-
-using System.Collections.Generic;
-using Assembler;
-
-public partial class Q1Cpu
-{
- public const u16 StackStart = 0x2FFF;
- public const u16 StackLength = 16 * 2; // 16 16-bit values
-
- public Random Random;
-
- public u16 AX = 0; // Accumulator register
- public u16 DX = 0; // Data register
- public u16 LX = 0; // Logical register
-
- public u16 SP { get; set; } // Stack pointer
- public u16 PC { get; set; } // Program counter
-
- public u16[] V { get; set; } // Variable registers (64 total)
- public u16 I { get; set; } // Index register
- public u16 Cycles { get; set; } // Number of cycles
-
- public Bus Bus { get; set; }
-
- public Q1Cpu()
- {
- this.LoadInstructionLookup();
-
- this.Reset();
- }
-
- public void Reset()
- {
- this.V = new u16[16];
-
- this.SP = StackStart;
-
- this.I = 0;
- }
-
- public void Clock()
- {
- var pc = this.PC;
- u16 instruction = this.FetchInstruction(out u8 op, out u8 m1, out u8 m2, out _);
- Console.WriteLine($"CPU.Clock: {pc:X4} | {Disassembler.ParseInstruction(instruction)}");
- // Console.WriteLine($"{V[0]:X4} {V[1]:X4} {V[2]:X4} {V[3]:X4} {V[4]:X4} {V[5]:X4} {V[6]:X4} {V[7]:X4}");
-
- bool ex = m2 > 0;
- switch (m1, ex)
- {
- case (0x00, false):
- this.InstructionLookup[op].Item1(); // Implicit
- break;
- case (> 0x00, false):
- this.InstructionLookup[op].Item2(m1); // Simple addressing mode
- break;
- case (0x00, true):
- this.InstructionLookup[op].Item3(); // Extended implicit
- break;
- case (> 0x00, true):
- this.InstructionLookup[op].Item4(m1, m2); // Extended addressing mode
- break;
- }
-
- this.Cycles++;
- }
- public u16 FetchInstruction(out u8 op, out u8 m1, out u8 m2, out u8 length)
- {
- u16 instruction = this.Bus.ReadWord(this.PC);
- this.PC += 2;
-
- op = (u8) ((instruction >> 8) & 0xFF); // 256 opcodes
- m1 = (u8) ((instruction >> 4) & 0x0F); // 16 modes
- m2 = (u8) (instruction & 0x0F); // 16 modes
-
- length = (u8) (this.AddressingModeLength(m1) + this.AddressingModeLength(m2));
- return instruction;
- }
-
- private void PushStack(u16 value)
- {
- if (this.SP + 2 >= StackStart + StackLength)
- throw new InvalidOperationException("Stack overflow");
-
- this.Bus.WriteWord(this.SP, value);
- this.SP += 2;
- }
-
- private u16 PopStack()
- {
- if (this.SP - 2 < StackStart)
- throw new InvalidOperationException("Stack underflow");
-
- this.SP -= 2;
- return this.Bus.ReadWord(this.SP);
- }
-
- private u16 FetchRegister(u8 regIndex)
- {
- return regIndex switch
- {
- <= 0x3F => this.V[regIndex],
-
- 0x40 => this.AX,
- 0x41 => (u16) (this.AX >> 8), // High byte of AX
- 0x42 => (u16) (this.AX & 0xFF), // Low byte of AX
-
- 0x43 => this.DX,
- 0x44 => (u16) (this.DX >> 8), // High byte of DX
- 0x45 => (u16) (this.DX & 0xFF), // Low byte of DX
-
- 0x46 => this.LX,
- 0x50 => this.PC,
- 0x51 => this.SP,
-
- _ => throw new InvalidOperationException($"Unknown register index: {regIndex:X2}"),
- };
- }
-
- private void StoreRegister(u8 regIndex, u16 value)
- {
- switch (regIndex)
- {
- case <= 0x3F:
- this.V[regIndex] = value;
- break;
-
- case 0x40:
- this.AX = value; break;
- case 0x41:
- this.AX = (u16) ((this.AX & 0x00FF) | (value << 8)); break; // Set high byte
- case 0x42:
- this.AX = (u16) ((this.AX & 0xFF00) | (value & 0x00FF)); break; // Set low byte
-
- case 0x43:
- this.DX = value; break;
- case 0x44:
- this.DX = (u16) ((this.DX & 0x00FF) | (value << 8)); break; // Set high byte
- case 0x45:
- this.DX = (u16) ((this.DX & 0xFF00) | (value & 0x00FF)); break; // Set low byte
-
- case 0x46:
- this.LX = value; break;
- case 0x50:
- this.PC = value; break;
- case 0x51:
- this.SP = value; break;
-
- default:
- throw new InvalidOperationException($"Unknown register index: {regIndex:X2}");
- }
- }
-}
\ No newline at end of file
diff --git a/Chip/Q1CpuAddressingModes.cs b/Chip/Q1CpuAddressingModes.cs
deleted file mode 100644
index 2b79db7..0000000
--- a/Chip/Q1CpuAddressingModes.cs
+++ /dev/null
@@ -1,188 +0,0 @@
-namespace Q1Emu.Chip;
-
-using System;
-using System.Collections.Generic;
-
-public partial class Q1Cpu
-{
- public (Func read, Action write, Action writeByte) Address(u8 mode)
- {
- return mode switch
- {
- 0x0 => this.AddressingMode_Implicit(),
- 0x1 => this.AddressingMode_Immediate(),
- 0x2 => this.AddressingMode_Direct(),
- 0x3 => this.AddressingMode_Indirect(),
- 0x4 => this.AddressingMode_Relative(),
- 0x5 => this.AddressingMode_Register(),
- 0x6 => this.AddressingMode_RegisterIndirect(),
- 0x7 => this.AddressingMode_RegisterIndirectOffset(),
- _ => throw new InvalidOperationException($"Unknown addressing mode: {mode:X2}"),
- };
- }
-
- private u8 AddressingModeLength(u8 mode)
- {
- return mode switch
- {
- 0x0 => 0, // Implicit
- 0x1 => 2, // Immediate
- 0x2 => 2, // Direct
- 0x3 => 2, // Indirect
- 0x4 => 2, // Relative
- 0x5 => 1, // Register
- 0x6 => 1, // Register indirect
- 0x7 => 3, // Register indirect with offset
- _ => throw new InvalidOperationException($"Unknown addressing mode: {mode:X2}"),
- };
- }
-
- public (Func read, Action write, Action writeByte) AddressingMode_Implicit()
- {
- u16 Read() => throw new InvalidOperationException("Cannot read from implicit mode.");
- void Write(u16 value) => throw new InvalidOperationException("Cannot write to implicit mode.");
- void WriteByte(u8 value) => throw new InvalidOperationException("Cannot write byte to implicit mode.");
-
- return (Read, Write, WriteByte);
- }
-
-
- public (Func read, Action write, Action writeByte) AddressingMode_Immediate()
- {
- u16 value = this.Bus.ReadWord(this.PC);
- this.PC += 2;
-
- u16 Read() => value;
- void Write(u16 v) => throw new InvalidOperationException("Cannot write to immediate mode.");
- void WriteByte(u8 v) => throw new InvalidOperationException("Cannot write byte to immediate mode.");
-
- return (Read, Write, WriteByte);
- }
-
- public (Func read, Action write, Action writeByte) AddressingMode_Direct()
- {
- u16 address = this.Bus.ReadWord(this.PC);
- this.PC += 2;
-
- u16 Read() => this.Bus.ReadWord(address);
- void Write(u16 value) => this.Bus.WriteWord(address, value);
- void WriteByte(u8 value) => this.Bus.Write(address, value);
-
- return (Read, Write, WriteByte);
- }
-
- public (Func read, Action write, Action writeByte) AddressingMode_Indirect()
- {
- u16 address = this.Bus.ReadWord(this.PC);
- this.PC += 2;
-
- u16 Read()
- {
- u16 indirectAddress = this.Bus.ReadWord(address);
- u16 value = this.Bus.ReadWord(indirectAddress);
- return value;
- }
-
- void Write(u16 value)
- {
- u16 indirectAddress = this.Bus.ReadWord(address);
- this.Bus.WriteWord(indirectAddress, value);
- }
-
- void WriteByte(u8 value)
- {
- u16 indirectAddress = this.Bus.ReadWord(address);
- this.Bus.Write(indirectAddress, value);
- }
-
- return (Read, Write, WriteByte);
- }
-
- public (Func read, Action write, Action writeByte) AddressingMode_Relative()
- {
- u16 offset = this.Bus.ReadWord(this.PC);
- this.PC += 2;
-
- u16 address = (u16) (this.PC + offset);
-
- u16 Read() => address;
- void Write(u16 value) => throw new InvalidOperationException("Cannot write to relative mode.");
- void WriteByte(u8 value) => throw new InvalidOperationException("Cannot write byte to relative mode.");
-
- return (Read, Write, WriteByte);
- }
-
- public (Func read, Action write, Action writeByte) AddressingMode_Register()
- {
- u8 regIndex = this.Bus.Read(this.PC);
- this.PC += 1;
-
- u16 Read() => this.FetchRegister(regIndex);
- void Write(u16 value) => this.StoreRegister(regIndex, value);
- void WriteByte(u8 value)
- {
- u16 currentValue = this.FetchRegister(regIndex);
- u16 newValue = (u16) ((currentValue & 0xFF00) | (value & 0x00FF)); // Update low byte
- this.StoreRegister(regIndex, newValue);
- }
-
- return (Read, Write, WriteByte);
- }
-
- public (Func read, Action write, Action writeByte) AddressingMode_RegisterIndirect()
- {
- u8 regIndex = this.Bus.Read(this.PC);
- this.PC += 1;
-
- u16 Read()
- {
- u16 address = this.FetchRegister(regIndex);
- u16 value = this.Bus.ReadWord(address);
- return value;
- }
-
- void Write(u16 value)
- {
- u16 address = this.FetchRegister(regIndex);
- this.Bus.WriteWord(address, value);
- }
-
- void WriteByte(u8 value)
- {
- u16 address = this.FetchRegister(regIndex);
- this.Bus.Write(address, value);
- }
-
- return (Read, Write, WriteByte);
- }
-
- public (Func read, Action write, Action writeByte) AddressingMode_RegisterIndirectOffset()
- {
- u8 regIndex = this.Bus.Read(this.PC);
- this.PC += 1;
-
- i16 offset = this.Bus.ReadSignedWord(this.PC);
- this.PC += 2;
-
- u16 Read()
- {
- u16 address = (u16) (this.FetchRegister(regIndex) + offset);
- u16 value = this.Bus.ReadWord(address);
- return value;
- }
-
- void Write(u16 value)
- {
- u16 address = (u16) (this.FetchRegister(regIndex) + offset);
- this.Bus.WriteWord(address, value);
- }
-
- void WriteByte(u8 value)
- {
- u16 address = (u16) (this.FetchRegister(regIndex) + offset);
- this.Bus.Write(address, value);
- }
-
- return (Read, Write, WriteByte);
- }
-}
\ No newline at end of file
diff --git a/Chip/Q1CpuInstructions.cs b/Chip/Q1CpuInstructions.cs
deleted file mode 100644
index b31a102..0000000
--- a/Chip/Q1CpuInstructions.cs
+++ /dev/null
@@ -1,266 +0,0 @@
-namespace Q1Emu.Chip;
-
-using System;
-using System.Collections.Generic;
-
-public partial class Q1Cpu
-{
- public static Dictionary InstructionLookupStrings = new()
- {
- { 0x00, ["NOP", "JMP", "HALT", "MOV"] },
- { 0x01, ["RET", "CALL", "SUS", "MOVB"] },
- { 0x02, ["BZ", "BZ", "BR", "NOP"] },
-
- { 0x10, ["INV", "INV", "NOP", "AND"] },
- { 0x11, ["SHL", "SHL", "NOP", "OR"] },
- { 0x12, ["SHR", "SHR", "NOP", "XOR"] },
-
- { 0x20, ["NOT", "NOT", "NOP", "CMP"] },
- { 0x21, ["NOP", "NOP", "NOP", "LT"] },
- { 0x22, ["NOP", "NOP", "NOP", "GT"] },
-
- { 0x30, ["INC_AX", "INC", "NOP", "ADD"] },
- { 0x31, ["DEC_AX", "DEC", "NOP", "SUB"] },
- { 0x32, ["NOP", "NOP", "NOP", "DIV"] },
- { 0x33, ["NOP", "NOP", "NOP", "MUL"] },
- { 0x34, ["NOP", "NOP", "NOP", "MOD"] },
- };
-
- public Dictionary, Action, Action)> InstructionLookup;
- private void LoadInstructionLookup()
- {
- this.InstructionLookup = new Dictionary, Action, Action)>
- {
- { 0x00, (this.Instruction_NOP, this.Instruction_JMP, this.Instruction_HALT, this.Instruction_MOV) },
- { 0x01, (this.Instruction_RET, this.Instruction_CALL, this.Instruction_SUS, this.Instruction_MOVB) },
- { 0x02, (this.Instruction_BZ_LX, this.Instruction_BZ, this.Instruction_BR, this.Instruction_NOP) },
-
- { 0x10, (this.Instruction_INV_DX, this.Instruction_INV, this.Instruction_NOP, this.Instruction_AND) },
- { 0x11, (this.Instruction_SHL_DX, this.Instruction_SHL, this.Instruction_NOP, this.Instruction_OR) },
- { 0x12, (this.Instruction_SHR_DX, this.Instruction_SHR, this.Instruction_NOP, this.Instruction_XOR) },
-
- { 0x20, (this.Instruction_NOT_LX, this.Instruction_NOT, this.Instruction_NOP, this.Instruction_CMP) },
- { 0x21, (this.Instruction_NOP, this.Instruction_NOP, this.Instruction_NOP, this.Instruction_LT) },
- { 0x22, (this.Instruction_NOP, this.Instruction_NOP, this.Instruction_NOP, this.Instruction_GT) },
-
- { 0x30, (this.Instruction_INC_AX, this.Instruction_INC, this.Instruction_NOP, this.Instruction_ADD) },
- { 0x31, (this.Instruction_DEC_AX, this.Instruction_DEC, this.Instruction_NOP, this.Instruction_SUB) },
- { 0x32, (this.Instruction_NOP, this.Instruction_NOP, this.Instruction_NOP, this.Instruction_DIV) },
- { 0x33, (this.Instruction_NOP, this.Instruction_NOP, this.Instruction_NOP, this.Instruction_MUL) },
- { 0x34, (this.Instruction_NOP, this.Instruction_NOP, this.Instruction_NOP, this.Instruction_MOD) },
- };
- }
- private void Instruction_ADD(u8 m1, u8 m2)
- {
- u16 v1 = this.Address(m1).read();
- u16 v2 = this.Address(m2).read();
-
- u16 result = (u16) (v1 + v2);
- this.AX = result;
- }
- private void Instruction_SUB(u8 m1, u8 m2)
- {
- u16 v1 = this.Address(m1).read();
- u16 v2 = this.Address(m2).read();
-
- u16 result = (u16)(v1 - v2);
- this.AX = result;
- }
- private void Instruction_MUL(u8 m1, u8 m2)
- {
- u16 v1 = this.Address(m1).read();
- u16 v2 = this.Address(m2).read();
-
- u16 result = (u16) (v1 * v2);
- this.AX = result;
- }
- private void Instruction_DIV(u8 m1, u8 m2)
- {
- u16 v1 = this.Address(m1).read();
- u16 v2 = this.Address(m2).read();
-
- if (v2 == 0)
- throw new DivideByZeroException("Cannot perform division by zero.");
- u16 result = (u16)(v1 / v2);
- this.AX = result;
- }
- private void Instruction_MOD(u8 m1, u8 m2)
- {
- u16 v1 = this.Address(m1).read();
- u16 v2 = this.Address(m2).read();
-
- if (v2 == 0)
- throw new DivideByZeroException("Cannot perform modulo operation with divisor zero.");
- u16 result = (u16)(v1 % v2);
- this.AX = result;
- }
- private void Instruction_INC(u8 obj)
- {
- var address = this.Address(obj);
- u16 value = address.read();
- address.write((u16)(value + 1));
- }
- private void Instruction_DEC(u8 obj)
- {
- var address = this.Address(obj);
- u16 value = address.read();
- address.write((u16)(value - 1));
- }
- private void Instruction_INC_AX()
- {
- this.AX = (u16)(this.AX + 1);
- }
- private void Instruction_DEC_AX()
- {
- this.AX = (u16)(this.AX - 1);
- }
- private void Instruction_SHL(u8 obj)
- {
- var address = this.Address(obj);
- u16 value = address.read();
- u16 result = (u16)(value << 1);
- address.write(result);
- }
- private void Instruction_SHR(u8 obj)
- {
- var address = this.Address(obj);
- u16 value = address.read();
- u16 result = (u16)(value >> 1);
- address.write(result);
- }
- private void Instruction_SHL_DX()
- {
- this.DX = (u16)(this.DX << 1);
- }
- private void Instruction_SHR_DX()
- {
- this.DX = (u16)(this.DX >> 1);
- }
- private void Instruction_XOR(u8 m1, u8 m2)
- {
- u16 v1 = this.Address(m1).read();
- u16 v2 = this.Address(m2).read();
-
- u16 result = (u16)(v1 ^ v2);
- this.DX = result;
- }
- private void Instruction_OR(u8 m1, u8 m2)
- {
- u16 v1 = this.Address(m1).read();
- u16 v2 = this.Address(m2).read();
-
- u16 result = (u16)(v1 | v2);
- this.DX = result;
- }
- private void Instruction_INV(u8 obj)
- {
- var address = this.Address(obj);
- u16 value = address.read();
- u16 result = (u16)~value;
- address.write(result);
- }
- private void Instruction_INV_DX()
- {
- this.DX = (u16)~this.DX;
- }
- private void Instruction_AND(u8 m1, u8 m2)
- {
- u16 v1 = this.Address(m1).read();
- u16 v2 = this.Address(m2).read();
-
- u16 result = (u16)(v1 & v2);
- this.DX = result;
- }
- private void Instruction_NOT(u8 obj)
- {
- u16 value = this.Address(obj).read();
- u16 result = value == 0 ? (u16)1 : (u16)0;
- this.LX = result;
- }
- private void Instruction_NOT_LX()
- {
- this.LX = this.LX == 0 ? (u16)1 : (u16)0;
- }
- private void Instruction_GT(u8 m1, u8 m2)
- {
- u16 v1 = this.Address(m1).read();
- u16 v2 = this.Address(m2).read();
-
- this.LX = (u16)(v1 > v2 ? 1 : 0);
- }
- private void Instruction_LT(u8 m1, u8 m2)
- {
- u16 v1 = this.Address(m1).read();
- u16 v2 = this.Address(m2).read();
-
- this.LX = (u16)(v1 < v2 ? 1 : 0);
- }
-
- private void Instruction_BR()
- {
- this.FetchInstruction(out _, out _, out _, out u8 length);
- this.PC += length;
- }
- private void Instruction_BZ_LX()
- {
- if (this.LX == 0)
- this.Instruction_BR();
- }
- private void Instruction_BZ(u8 obj)
- {
- u16 value = this.Address(obj).read();
- if (value == 0)
- this.Instruction_BR();
- }
- private void Instruction_CMP(u8 m1, u8 m2)
- {
- u16 v1 = this.Address(m1).read();
- u16 v2 = this.Address(m2).read();
-
- // Set LX based on comparison
- this.LX = (u16)(v1 == v2 ? 1 : 0);
- }
- private void Instruction_MOV(u8 m1, u8 m2)
- {
- u16 value = this.Address(m1).read();
- this.Address(m2).write(value);
- }
-
- private void Instruction_MOVB(u8 m1, u8 m2)
- {
- u16 value = this.Address(m1).read();
- u8 low = Make.ref8(value)[1];
- this.Address(m2).writeByte(low);
- }
-
- public void Instruction_NOP() { }
- public void Instruction_NOP(u8 m1) { }
- public void Instruction_NOP(u8 m1, u8 m2) { }
-
- public void Instruction_JMP(u8 m1)
- {
- this.PC = this.Address(m1).read();
- }
-
- public void Instruction_RET()
- {
- this.PC = this.PopStack();
- }
-
- public void Instruction_CALL(u8 m1)
- {
- u16 address = this.Address(m1).read();
- this.PushStack(this.PC);
- this.PC = address;
- }
-
- public void Instruction_HALT()
- {
- throw new NotImplementedException("Halt instruction not implemented yet.");
- }
-
- public void Instruction_SUS()
- {
- this.PC -= 2;
- }
-}
\ No newline at end of file
diff --git a/Chip/RamDevice.cs b/Chip/RamDevice.cs
deleted file mode 100644
index 509a2df..0000000
--- a/Chip/RamDevice.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-namespace Q1Emu.Chip;
-
-using System;
-using System.Runtime.CompilerServices;
-
-public class RamDevice : BusDevice
-{
- public u8[] Memory;
-
- public RamDevice(u16 start, u16 size) : base(start, (u16) (start + size))
- {
- this.Memory = new u8[size];
- }
-
- public override void Reset()
- {
- this.Memory = new u8[this.AddressableEnd - this.AddressableStart];
- }
-
- public override void Clock()
- {
- // No clocking needed for RAM
- }
-
- public override u8 Read(u16 address)
- {
- u16 relativeAddress = this.GetRelativeAddress(address);
- return this.Memory[relativeAddress];
- }
-
- public override void Write(u16 address, u8 value)
- {
- u16 relativeAddress = this.GetRelativeAddress(address);
- this.Memory[relativeAddress] = value;
- }
-}
\ No newline at end of file
diff --git a/Chip8Emu2.sln.DotSettings.user b/Chip8Emu2.sln.DotSettings.user
deleted file mode 100644
index d66483f..0000000
--- a/Chip8Emu2.sln.DotSettings.user
+++ /dev/null
@@ -1,2 +0,0 @@
-
- ForceIncluded
\ No newline at end of file
diff --git a/Compiler/CCompilerVisitor.cs b/Compiler/CCompilerVisitor.cs
new file mode 100644
index 0000000..cee69f4
--- /dev/null
+++ b/Compiler/CCompilerVisitor.cs
@@ -0,0 +1,172 @@
+namespace Q1.Compiler;
+
+public class CCompilerVisitor : CGrammarBaseVisitor
+{
+ private List Instructions = new();
+ public IEnumerable Compile(CGrammarParser.ProgramContext program)
+ {
+ this.Visit(program);
+ return this.Instructions;
+ }
+
+ public override string? VisitFunction(CGrammarParser.FunctionContext context)
+ {
+ string functionName = context.ID().GetText();
+ Instructions.Add($"_{functionName}:");
+ this.VisitChildren(context);
+ this.Instructions.Add("");
+
+ return null;
+ }
+ public override string? VisitParenthesizedExpression(CGrammarParser.ParenthesizedExpressionContext context)
+ {
+ return this.Visit(context.expression());
+ }
+ public override string? VisitReturnStatement(CGrammarParser.ReturnStatementContext context)
+ {
+ if (context.expression() != null)
+ {
+ string? expression = this.Visit(context.expression());
+ if (expression != null)
+ {
+ this.Instructions.Add($"MOV {expression}, V0");
+ Instructions.Add($"RET");
+ }
+ else
+ throw new CompilerException("Return value was not an expression.");
+ }
+ else
+ Instructions.Add("RET");
+
+ return null;
+ }
+ public override string? VisitIntConstant(CGrammarParser.IntConstantContext context)
+ {
+ string valueString = context.INT().GetText();
+ if (int.TryParse(valueString, out int value))
+ return $"{value}";
+ else
+ throw new CompilerException($"Invalid integer value: {valueString}");
+ }
+
+ public override string? VisitNotExpression(CGrammarParser.NotExpressionContext context)
+ {
+ string? value = this.Visit(context.expression());
+ if (value == null)
+ throw new CompilerException("Value for negating was not an expression.");
+
+ this.Instructions.Add($"NOT {value}");
+ return "LX";
+ }
+
+ public override string? VisitInvertExpression(CGrammarParser.InvertExpressionContext context)
+ {
+ string? value = this.Visit(context.expression());
+ if (value == null)
+ throw new CompilerException("Value for inversion was not an expression.");
+
+ this.Instructions.Add($"INV {value}");
+ return "DX";
+ }
+
+ public override string? VisitAddExpression(CGrammarParser.AddExpressionContext context)
+ {
+ string? left = this.Visit(context.left);
+ string? right = this.Visit(context.right);
+
+ if (left == null || right == null)
+ throw new CompilerException("Left or right operand for addition was not an expression.");
+
+ this.Instructions.Add($"ADD {left}, {right}");
+ return "AX";
+ }
+ public override string? VisitSubtractExpression(CGrammarParser.SubtractExpressionContext context)
+ {
+ string? left = this.Visit(context.left);
+ string? right = this.Visit(context.right);
+
+ if (left == null || right == null)
+ throw new CompilerException("Left or right operand for subtraction was not an expression.");
+
+ this.Instructions.Add($"SUB {left}, {right}");
+ return "AX";
+ }
+ public override string? VisitMultiplyExpression(CGrammarParser.MultiplyExpressionContext context)
+ {
+ string? left = this.Visit(context.left);
+ string? right = this.Visit(context.right);
+
+ if (left == null || right == null)
+ throw new CompilerException("Left or right operand for multiplication was not an expression.");
+
+ this.Instructions.Add($"MUL {left}, {right}");
+ return "AX";
+ }
+ public override string? VisitDivideExpression(CGrammarParser.DivideExpressionContext context)
+ {
+ string? left = this.Visit(context.left);
+ string? right = this.Visit(context.right);
+
+ if (left == null || right == null)
+ throw new CompilerException("Left or right operand for division was not an expression.");
+
+ this.Instructions.Add($"DIV {left}, {right}");
+ return "AX";
+ }
+ public override string? VisitModulusExpression(CGrammarParser.ModulusExpressionContext context)
+ {
+ string? left = this.Visit(context.left);
+ string? right = this.Visit(context.right);
+
+ if (left == null || right == null)
+ throw new CompilerException("Left or right operand for modulus was not an expression.");
+
+ this.Instructions.Add($"MOD {left}, {right}");
+ return "AX";
+ }
+
+ public override string? VisitBitwiseXorExpression(CGrammarParser.BitwiseXorExpressionContext context)
+ {
+ throw new NotImplementedException();
+ }
+ public override string? VisitLessThanOrEqualExpression(CGrammarParser.LessThanOrEqualExpressionContext context)
+ {
+ throw new NotImplementedException();
+ }
+ public override string? VisitNotEqualExpression(CGrammarParser.NotEqualExpressionContext context)
+ {
+ throw new NotImplementedException();
+ }
+ public override string? VisitGreaterThanExpression(CGrammarParser.GreaterThanExpressionContext context)
+ {
+ throw new NotImplementedException();
+ }
+ public override string? VisitLogicalOrExpression(CGrammarParser.LogicalOrExpressionContext context)
+ {
+ throw new NotImplementedException();
+ }
+ public override string? VisitGreaterThanOrEqualExpression(CGrammarParser.GreaterThanOrEqualExpressionContext context)
+ {
+ throw new NotImplementedException();
+ }
+ public override string? VisitBitwiseOrExpression(CGrammarParser.BitwiseOrExpressionContext context)
+ {
+ throw new NotImplementedException();
+ }
+ public override string? VisitBitwiseAndExpression(CGrammarParser.BitwiseAndExpressionContext context)
+ {
+ throw new NotImplementedException();
+ }
+ public override string? VisitLessThanExpression(CGrammarParser.LessThanExpressionContext context)
+ {
+ throw new NotImplementedException();
+ }
+ public override string? VisitLogicalAndExpression(CGrammarParser.LogicalAndExpressionContext context)
+ {
+ throw new NotImplementedException();
+ }
+ public override string? VisitEqualExpression(CGrammarParser.EqualExpressionContext context)
+ {
+ throw new NotImplementedException();
+ }
+}
\ No newline at end of file
diff --git a/Compiler/CGrammar.g4 b/Compiler/CGrammar.g4
new file mode 100644
index 0000000..69b2c0a
--- /dev/null
+++ b/Compiler/CGrammar.g4
@@ -0,0 +1,50 @@
+grammar CGrammar;
+
+ID: [a-zA-Z_][a-zA-Z0-9_]*;
+INT: [0-9]+;
+
+program
+ : function EOF
+ ;
+
+function
+ : 'int' ID '(' ')' '{' statement* '}'
+ ;
+
+statement
+ : 'return' expression ';' #returnStatement
+ ;
+
+expression
+ : '(' expression ')' #parenthesizedExpression
+
+ | '!' expression #notExpression
+ | '~' expression #invertExpression
+
+ | left=expression '*' right=expression #multiplyExpression
+ | left=expression '/' right=expression #divideExpression
+ | left=expression '%' right=expression #modulusExpression
+
+ | left=expression '+' right=expression #addExpression
+ | left=expression '-' right=expression #subtractExpression
+
+ | left=expression '<' right=expression #lessThanExpression
+ | left=expression '>' right=expression #greaterThanExpression
+ | left=expression '<=' right=expression #lessThanOrEqualExpression
+ | left=expression '>=' right=expression #greaterThanOrEqualExpression
+ | left=expression '==' right=expression #equalExpression
+ | left=expression '!=' right=expression #notEqualExpression
+
+ | left=expression '&' right=expression #bitwiseAndExpression
+ | left=expression '|' right=expression #bitwiseOrExpression
+ | left=expression '^' right=expression #bitwiseXorExpression
+
+ | left=expression '&&' right=expression #logicalAndExpression
+ | left=expression '||' right=expression #logicalOrExpression
+
+ | constant #constantExpression
+ ;
+
+constant
+ : INT # intConstant
+ ;
\ No newline at end of file
diff --git a/Compiler/Compiler.csproj b/Compiler/Compiler.csproj
new file mode 100644
index 0000000..042331e
--- /dev/null
+++ b/Compiler/Compiler.csproj
@@ -0,0 +1,20 @@
+
+
+
+ Exe
+ net9.0
+ enable
+ enable
+ Q1.Compiler
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Compiler/CompilerException.cs b/Compiler/CompilerException.cs
new file mode 100644
index 0000000..f5a78f1
--- /dev/null
+++ b/Compiler/CompilerException.cs
@@ -0,0 +1,4 @@
+namespace Q1.Compiler;
+
+public class CompilerException(string message)
+ : Exception(message);
\ No newline at end of file
diff --git a/Compiler/Options.cs b/Compiler/Options.cs
new file mode 100644
index 0000000..c12a4c6
--- /dev/null
+++ b/Compiler/Options.cs
@@ -0,0 +1,12 @@
+namespace Q1.Compiler;
+
+using CommandLine;
+
+public class Options
+{
+ [Option('i', "input", Required = true, HelpText = "Input file to compile.")]
+ public string InputFile { get; set; }
+
+ [Option('o', "output", Required = true, HelpText = "Output file to write the compiled code.")]
+ public string OutputFile { get; set; }
+}
\ No newline at end of file
diff --git a/Compiler/Program.cs b/Compiler/Program.cs
new file mode 100644
index 0000000..b832a53
--- /dev/null
+++ b/Compiler/Program.cs
@@ -0,0 +1,31 @@
+namespace Q1.Compiler;
+
+using Antlr4.Runtime;
+using CommandLine;
+using Parser = CommandLine.Parser;
+
+class Program
+{
+ static void Main(string[] args)
+ {
+ Parser.Default.ParseArguments(args).WithParsed(Program.Main);
+ }
+
+ static void Main(Options options)
+ {
+ Environment.CurrentDirectory = Path.GetDirectoryName(options.InputFile) ?? Environment.CurrentDirectory;
+ options.InputFile = Path.GetFileName(options.InputFile);
+
+ AntlrFileStream inputStream = new(options.InputFile);
+ CGrammarLexer lexer = new(inputStream);
+ lexer.RemoveErrorListeners();
+
+ CommonTokenStream tokenStream = new(lexer);
+ CGrammarParser parser = new(tokenStream);
+ parser.RemoveErrorListeners();
+
+ CCompilerVisitor compiler = new();
+ var result = compiler.Compile(parser.program());
+ File.WriteAllLines(options.OutputFile, result);
+ }
+}
\ No newline at end of file
diff --git a/Compiler/gen/CGrammar.interp b/Compiler/gen/CGrammar.interp
new file mode 100644
index 0000000..d5453b2
--- /dev/null
+++ b/Compiler/gen/CGrammar.interp
@@ -0,0 +1,70 @@
+token literal names:
+null
+'int'
+'('
+')'
+'{'
+'}'
+'return'
+';'
+'!'
+'~'
+'*'
+'/'
+'%'
+'+'
+'-'
+'<'
+'>'
+'<='
+'>='
+'=='
+'!='
+'&'
+'|'
+'^'
+'&&'
+'||'
+null
+null
+
+token symbolic names:
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+ID
+INT
+
+rule names:
+program
+function
+statement
+expression
+constant
+
+
+atn:
+[4, 1, 27, 98, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 20, 8, 1, 10, 1, 12, 1, 23, 9, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 3, 3, 41, 8, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 5, 3, 91, 8, 3, 10, 3, 12, 3, 94, 9, 3, 1, 4, 1, 4, 1, 4, 0, 1, 6, 5, 0, 2, 4, 6, 8, 0, 0, 112, 0, 10, 1, 0, 0, 0, 2, 13, 1, 0, 0, 0, 4, 26, 1, 0, 0, 0, 6, 40, 1, 0, 0, 0, 8, 95, 1, 0, 0, 0, 10, 11, 3, 2, 1, 0, 11, 12, 5, 0, 0, 1, 12, 1, 1, 0, 0, 0, 13, 14, 5, 1, 0, 0, 14, 15, 5, 26, 0, 0, 15, 16, 5, 2, 0, 0, 16, 17, 5, 3, 0, 0, 17, 21, 5, 4, 0, 0, 18, 20, 3, 4, 2, 0, 19, 18, 1, 0, 0, 0, 20, 23, 1, 0, 0, 0, 21, 19, 1, 0, 0, 0, 21, 22, 1, 0, 0, 0, 22, 24, 1, 0, 0, 0, 23, 21, 1, 0, 0, 0, 24, 25, 5, 5, 0, 0, 25, 3, 1, 0, 0, 0, 26, 27, 5, 6, 0, 0, 27, 28, 3, 6, 3, 0, 28, 29, 5, 7, 0, 0, 29, 5, 1, 0, 0, 0, 30, 31, 6, 3, -1, 0, 31, 32, 5, 2, 0, 0, 32, 33, 3, 6, 3, 0, 33, 34, 5, 3, 0, 0, 34, 41, 1, 0, 0, 0, 35, 36, 5, 8, 0, 0, 36, 41, 3, 6, 3, 19, 37, 38, 5, 9, 0, 0, 38, 41, 3, 6, 3, 18, 39, 41, 3, 8, 4, 0, 40, 30, 1, 0, 0, 0, 40, 35, 1, 0, 0, 0, 40, 37, 1, 0, 0, 0, 40, 39, 1, 0, 0, 0, 41, 92, 1, 0, 0, 0, 42, 43, 10, 17, 0, 0, 43, 44, 5, 10, 0, 0, 44, 91, 3, 6, 3, 18, 45, 46, 10, 16, 0, 0, 46, 47, 5, 11, 0, 0, 47, 91, 3, 6, 3, 17, 48, 49, 10, 15, 0, 0, 49, 50, 5, 12, 0, 0, 50, 91, 3, 6, 3, 16, 51, 52, 10, 14, 0, 0, 52, 53, 5, 13, 0, 0, 53, 91, 3, 6, 3, 15, 54, 55, 10, 13, 0, 0, 55, 56, 5, 14, 0, 0, 56, 91, 3, 6, 3, 14, 57, 58, 10, 12, 0, 0, 58, 59, 5, 15, 0, 0, 59, 91, 3, 6, 3, 13, 60, 61, 10, 11, 0, 0, 61, 62, 5, 16, 0, 0, 62, 91, 3, 6, 3, 12, 63, 64, 10, 10, 0, 0, 64, 65, 5, 17, 0, 0, 65, 91, 3, 6, 3, 11, 66, 67, 10, 9, 0, 0, 67, 68, 5, 18, 0, 0, 68, 91, 3, 6, 3, 10, 69, 70, 10, 8, 0, 0, 70, 71, 5, 19, 0, 0, 71, 91, 3, 6, 3, 9, 72, 73, 10, 7, 0, 0, 73, 74, 5, 20, 0, 0, 74, 91, 3, 6, 3, 8, 75, 76, 10, 6, 0, 0, 76, 77, 5, 21, 0, 0, 77, 91, 3, 6, 3, 7, 78, 79, 10, 5, 0, 0, 79, 80, 5, 22, 0, 0, 80, 91, 3, 6, 3, 6, 81, 82, 10, 4, 0, 0, 82, 83, 5, 23, 0, 0, 83, 91, 3, 6, 3, 5, 84, 85, 10, 3, 0, 0, 85, 86, 5, 24, 0, 0, 86, 91, 3, 6, 3, 4, 87, 88, 10, 2, 0, 0, 88, 89, 5, 25, 0, 0, 89, 91, 3, 6, 3, 3, 90, 42, 1, 0, 0, 0, 90, 45, 1, 0, 0, 0, 90, 48, 1, 0, 0, 0, 90, 51, 1, 0, 0, 0, 90, 54, 1, 0, 0, 0, 90, 57, 1, 0, 0, 0, 90, 60, 1, 0, 0, 0, 90, 63, 1, 0, 0, 0, 90, 66, 1, 0, 0, 0, 90, 69, 1, 0, 0, 0, 90, 72, 1, 0, 0, 0, 90, 75, 1, 0, 0, 0, 90, 78, 1, 0, 0, 0, 90, 81, 1, 0, 0, 0, 90, 84, 1, 0, 0, 0, 90, 87, 1, 0, 0, 0, 91, 94, 1, 0, 0, 0, 92, 90, 1, 0, 0, 0, 92, 93, 1, 0, 0, 0, 93, 7, 1, 0, 0, 0, 94, 92, 1, 0, 0, 0, 95, 96, 5, 27, 0, 0, 96, 9, 1, 0, 0, 0, 4, 21, 40, 90, 92]
\ No newline at end of file
diff --git a/Compiler/gen/CGrammar.tokens b/Compiler/gen/CGrammar.tokens
new file mode 100644
index 0000000..fc1a392
--- /dev/null
+++ b/Compiler/gen/CGrammar.tokens
@@ -0,0 +1,52 @@
+T__0=1
+T__1=2
+T__2=3
+T__3=4
+T__4=5
+T__5=6
+T__6=7
+T__7=8
+T__8=9
+T__9=10
+T__10=11
+T__11=12
+T__12=13
+T__13=14
+T__14=15
+T__15=16
+T__16=17
+T__17=18
+T__18=19
+T__19=20
+T__20=21
+T__21=22
+T__22=23
+T__23=24
+T__24=25
+ID=26
+INT=27
+'int'=1
+'('=2
+')'=3
+'{'=4
+'}'=5
+'return'=6
+';'=7
+'!'=8
+'~'=9
+'*'=10
+'/'=11
+'%'=12
+'+'=13
+'-'=14
+'<'=15
+'>'=16
+'<='=17
+'>='=18
+'=='=19
+'!='=20
+'&'=21
+'|'=22
+'^'=23
+'&&'=24
+'||'=25
diff --git a/Compiler/gen/CGrammarBaseVisitor.cs b/Compiler/gen/CGrammarBaseVisitor.cs
new file mode 100644
index 0000000..1f864c3
--- /dev/null
+++ b/Compiler/gen/CGrammarBaseVisitor.cs
@@ -0,0 +1,299 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// ANTLR Version: 4.13.2
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+// Generated from /Users/melodidey/Source/csharp/Q1/Compiler/CGrammar.g4 by ANTLR 4.13.2
+
+// Unreachable code detected
+#pragma warning disable 0162
+// The variable '...' is assigned but its value is never used
+#pragma warning disable 0219
+// Missing XML comment for publicly visible type or member '...'
+#pragma warning disable 1591
+// Ambiguous reference in cref attribute
+#pragma warning disable 419
+
+using Antlr4.Runtime.Misc;
+using Antlr4.Runtime.Tree;
+using IToken = Antlr4.Runtime.IToken;
+using ParserRuleContext = Antlr4.Runtime.ParserRuleContext;
+
+///
+/// This class provides an empty implementation of ,
+/// which can be extended to create a visitor which only needs to handle a subset
+/// of the available methods.
+///
+/// The return type of the visit operation.
+[System.CodeDom.Compiler.GeneratedCode("ANTLR", "4.13.2")]
+[System.Diagnostics.DebuggerNonUserCode]
+[System.CLSCompliant(false)]
+public partial class CGrammarBaseVisitor : AbstractParseTreeVisitor, ICGrammarVisitor {
+ ///
+ /// Visit a parse tree produced by .
+ ///
+ /// The default implementation returns the result of calling
+ /// on .
+ ///
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ public virtual Result VisitProgram([NotNull] CGrammarParser.ProgramContext context) { return VisitChildren(context); }
+ ///
+ /// Visit a parse tree produced by .
+ ///
+ /// The default implementation returns the result of calling
+ /// on .
+ ///
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ public virtual Result VisitFunction([NotNull] CGrammarParser.FunctionContext context) { return VisitChildren(context); }
+ ///
+ /// Visit a parse tree produced by the returnStatement
+ /// labeled alternative in .
+ ///
+ /// The default implementation returns the result of calling
+ /// on .
+ ///
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ public virtual Result VisitReturnStatement([NotNull] CGrammarParser.ReturnStatementContext context) { return VisitChildren(context); }
+ ///
+ /// Visit a parse tree produced by the bitwiseXorExpression
+ /// labeled alternative in .
+ ///
+ /// The default implementation returns the result of calling
+ /// on .
+ ///
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ public virtual Result VisitBitwiseXorExpression([NotNull] CGrammarParser.BitwiseXorExpressionContext context) { return VisitChildren(context); }
+ ///
+ /// Visit a parse tree produced by the constantExpression
+ /// labeled alternative in .
+ ///
+ /// The default implementation returns the result of calling
+ /// on .
+ ///
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ public virtual Result VisitConstantExpression([NotNull] CGrammarParser.ConstantExpressionContext context) { return VisitChildren(context); }
+ ///
+ /// Visit a parse tree produced by the lessThanOrEqualExpression
+ /// labeled alternative in .
+ ///
+ /// The default implementation returns the result of calling
+ /// on .
+ ///
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ public virtual Result VisitLessThanOrEqualExpression([NotNull] CGrammarParser.LessThanOrEqualExpressionContext context) { return VisitChildren(context); }
+ ///
+ /// Visit a parse tree produced by the modulusExpression
+ /// labeled alternative in .
+ ///
+ /// The default implementation returns the result of calling
+ /// on .
+ ///
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ public virtual Result VisitModulusExpression([NotNull] CGrammarParser.ModulusExpressionContext context) { return VisitChildren(context); }
+ ///
+ /// Visit a parse tree produced by the notExpression
+ /// labeled alternative in .
+ ///
+ /// The default implementation returns the result of calling
+ /// on .
+ ///
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ public virtual Result VisitNotExpression([NotNull] CGrammarParser.NotExpressionContext context) { return VisitChildren(context); }
+ ///
+ /// Visit a parse tree produced by the notEqualExpression
+ /// labeled alternative in .
+ ///
+ /// The default implementation returns the result of calling
+ /// on .
+ ///
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ public virtual Result VisitNotEqualExpression([NotNull] CGrammarParser.NotEqualExpressionContext context) { return VisitChildren(context); }
+ ///
+ /// Visit a parse tree produced by the multiplyExpression
+ /// labeled alternative in .
+ ///
+ /// The default implementation returns the result of calling
+ /// on .
+ ///
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ public virtual Result VisitMultiplyExpression([NotNull] CGrammarParser.MultiplyExpressionContext context) { return VisitChildren(context); }
+ ///
+ /// Visit a parse tree produced by the greaterThanExpression
+ /// labeled alternative in .
+ ///
+ /// The default implementation returns the result of calling
+ /// on .
+ ///
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ public virtual Result VisitGreaterThanExpression([NotNull] CGrammarParser.GreaterThanExpressionContext context) { return VisitChildren(context); }
+ ///
+ /// Visit a parse tree produced by the logicalOrExpression
+ /// labeled alternative in .
+ ///
+ /// The default implementation returns the result of calling
+ /// on .
+ ///
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ public virtual Result VisitLogicalOrExpression([NotNull] CGrammarParser.LogicalOrExpressionContext context) { return VisitChildren(context); }
+ ///
+ /// Visit a parse tree produced by the greaterThanOrEqualExpression
+ /// labeled alternative in .
+ ///
+ /// The default implementation returns the result of calling
+ /// on .
+ ///
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ public virtual Result VisitGreaterThanOrEqualExpression([NotNull] CGrammarParser.GreaterThanOrEqualExpressionContext context) { return VisitChildren(context); }
+ ///
+ /// Visit a parse tree produced by the divideExpression
+ /// labeled alternative in .
+ ///
+ /// The default implementation returns the result of calling
+ /// on .
+ ///
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ public virtual Result VisitDivideExpression([NotNull] CGrammarParser.DivideExpressionContext context) { return VisitChildren(context); }
+ ///
+ /// Visit a parse tree produced by the bitwiseOrExpression
+ /// labeled alternative in .
+ ///
+ /// The default implementation returns the result of calling
+ /// on .
+ ///
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ public virtual Result VisitBitwiseOrExpression([NotNull] CGrammarParser.BitwiseOrExpressionContext context) { return VisitChildren(context); }
+ ///
+ /// Visit a parse tree produced by the parenthesizedExpression
+ /// labeled alternative in .
+ ///
+ /// The default implementation returns the result of calling
+ /// on .
+ ///
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ public virtual Result VisitParenthesizedExpression([NotNull] CGrammarParser.ParenthesizedExpressionContext context) { return VisitChildren(context); }
+ ///
+ /// Visit a parse tree produced by the addExpression
+ /// labeled alternative in .
+ ///
+ /// The default implementation returns the result of calling
+ /// on .
+ ///
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ public virtual Result VisitAddExpression([NotNull] CGrammarParser.AddExpressionContext context) { return VisitChildren(context); }
+ ///
+ /// Visit a parse tree produced by the subtractExpression
+ /// labeled alternative in .
+ ///
+ /// The default implementation returns the result of calling
+ /// on .
+ ///
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ public virtual Result VisitSubtractExpression([NotNull] CGrammarParser.SubtractExpressionContext context) { return VisitChildren(context); }
+ ///
+ /// Visit a parse tree produced by the bitwiseAndExpression
+ /// labeled alternative in .
+ ///
+ /// The default implementation returns the result of calling
+ /// on .
+ ///
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ public virtual Result VisitBitwiseAndExpression([NotNull] CGrammarParser.BitwiseAndExpressionContext context) { return VisitChildren(context); }
+ ///
+ /// Visit a parse tree produced by the lessThanExpression
+ /// labeled alternative in .
+ ///
+ /// The default implementation returns the result of calling
+ /// on .
+ ///
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ public virtual Result VisitLessThanExpression([NotNull] CGrammarParser.LessThanExpressionContext context) { return VisitChildren(context); }
+ ///
+ /// Visit a parse tree produced by the logicalAndExpression
+ /// labeled alternative in .
+ ///
+ /// The default implementation returns the result of calling
+ /// on .
+ ///
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ public virtual Result VisitLogicalAndExpression([NotNull] CGrammarParser.LogicalAndExpressionContext context) { return VisitChildren(context); }
+ ///
+ /// Visit a parse tree produced by the invertExpression
+ /// labeled alternative in .
+ ///
+ /// The default implementation returns the result of calling
+ /// on .
+ ///
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ public virtual Result VisitInvertExpression([NotNull] CGrammarParser.InvertExpressionContext context) { return VisitChildren(context); }
+ ///
+ /// Visit a parse tree produced by the equalExpression
+ /// labeled alternative in .
+ ///
+ /// The default implementation returns the result of calling
+ /// on .
+ ///
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ public virtual Result VisitEqualExpression([NotNull] CGrammarParser.EqualExpressionContext context) { return VisitChildren(context); }
+ ///
+ /// Visit a parse tree produced by the intConstant
+ /// labeled alternative in .
+ ///
+ /// The default implementation returns the result of calling
+ /// on .
+ ///
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ public virtual Result VisitIntConstant([NotNull] CGrammarParser.IntConstantContext context) { return VisitChildren(context); }
+}
diff --git a/Compiler/gen/CGrammarLexer.cs b/Compiler/gen/CGrammarLexer.cs
new file mode 100644
index 0000000..3bb49f2
--- /dev/null
+++ b/Compiler/gen/CGrammarLexer.cs
@@ -0,0 +1,149 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// ANTLR Version: 4.13.2
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+// Generated from /Users/melodidey/Source/csharp/Q1/Compiler/CGrammar.g4 by ANTLR 4.13.2
+
+// Unreachable code detected
+#pragma warning disable 0162
+// The variable '...' is assigned but its value is never used
+#pragma warning disable 0219
+// Missing XML comment for publicly visible type or member '...'
+#pragma warning disable 1591
+// Ambiguous reference in cref attribute
+#pragma warning disable 419
+
+using System;
+using System.IO;
+using System.Text;
+using Antlr4.Runtime;
+using Antlr4.Runtime.Atn;
+using Antlr4.Runtime.Misc;
+using DFA = Antlr4.Runtime.Dfa.DFA;
+
+[System.CodeDom.Compiler.GeneratedCode("ANTLR", "4.13.2")]
+[System.CLSCompliant(false)]
+public partial class CGrammarLexer : Lexer {
+ protected static DFA[] decisionToDFA;
+ protected static PredictionContextCache sharedContextCache = new PredictionContextCache();
+ public const int
+ T__0=1, T__1=2, T__2=3, T__3=4, T__4=5, T__5=6, T__6=7, T__7=8, T__8=9,
+ T__9=10, T__10=11, T__11=12, T__12=13, T__13=14, T__14=15, T__15=16, T__16=17,
+ T__17=18, T__18=19, T__19=20, T__20=21, T__21=22, T__22=23, T__23=24,
+ T__24=25, ID=26, INT=27;
+ public static string[] channelNames = {
+ "DEFAULT_TOKEN_CHANNEL", "HIDDEN"
+ };
+
+ public static string[] modeNames = {
+ "DEFAULT_MODE"
+ };
+
+ public static readonly string[] ruleNames = {
+ "T__0", "T__1", "T__2", "T__3", "T__4", "T__5", "T__6", "T__7", "T__8",
+ "T__9", "T__10", "T__11", "T__12", "T__13", "T__14", "T__15", "T__16",
+ "T__17", "T__18", "T__19", "T__20", "T__21", "T__22", "T__23", "T__24",
+ "ID", "INT"
+ };
+
+
+ public CGrammarLexer(ICharStream input)
+ : this(input, Console.Out, Console.Error) { }
+
+ public CGrammarLexer(ICharStream input, TextWriter output, TextWriter errorOutput)
+ : base(input, output, errorOutput)
+ {
+ Interpreter = new LexerATNSimulator(this, _ATN, decisionToDFA, sharedContextCache);
+ }
+
+ private static readonly string[] _LiteralNames = {
+ null, "'int'", "'('", "')'", "'{'", "'}'", "'return'", "';'", "'!'", "'~'",
+ "'*'", "'/'", "'%'", "'+'", "'-'", "'<'", "'>'", "'<='", "'>='", "'=='",
+ "'!='", "'&'", "'|'", "'^'", "'&&'", "'||'"
+ };
+ private static readonly string[] _SymbolicNames = {
+ null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, "ID", "INT"
+ };
+ public static readonly IVocabulary DefaultVocabulary = new Vocabulary(_LiteralNames, _SymbolicNames);
+
+ [NotNull]
+ public override IVocabulary Vocabulary
+ {
+ get
+ {
+ return DefaultVocabulary;
+ }
+ }
+
+ public override string GrammarFileName { get { return "CGrammar.g4"; } }
+
+ public override string[] RuleNames { get { return ruleNames; } }
+
+ public override string[] ChannelNames { get { return channelNames; } }
+
+ public override string[] ModeNames { get { return modeNames; } }
+
+ public override int[] SerializedAtn { get { return _serializedATN; } }
+
+ static CGrammarLexer() {
+ decisionToDFA = new DFA[_ATN.NumberOfDecisions];
+ for (int i = 0; i < _ATN.NumberOfDecisions; i++) {
+ decisionToDFA[i] = new DFA(_ATN.GetDecisionState(i), i);
+ }
+ }
+ private static int[] _serializedATN = {
+ 4,0,27,130,6,-1,2,0,7,0,2,1,7,1,2,2,7,2,2,3,7,3,2,4,7,4,2,5,7,5,2,6,7,
+ 6,2,7,7,7,2,8,7,8,2,9,7,9,2,10,7,10,2,11,7,11,2,12,7,12,2,13,7,13,2,14,
+ 7,14,2,15,7,15,2,16,7,16,2,17,7,17,2,18,7,18,2,19,7,19,2,20,7,20,2,21,
+ 7,21,2,22,7,22,2,23,7,23,2,24,7,24,2,25,7,25,2,26,7,26,1,0,1,0,1,0,1,0,
+ 1,1,1,1,1,2,1,2,1,3,1,3,1,4,1,4,1,5,1,5,1,5,1,5,1,5,1,5,1,5,1,6,1,6,1,
+ 7,1,7,1,8,1,8,1,9,1,9,1,10,1,10,1,11,1,11,1,12,1,12,1,13,1,13,1,14,1,14,
+ 1,15,1,15,1,16,1,16,1,16,1,17,1,17,1,17,1,18,1,18,1,18,1,19,1,19,1,19,
+ 1,20,1,20,1,21,1,21,1,22,1,22,1,23,1,23,1,23,1,24,1,24,1,24,1,25,1,25,
+ 5,25,121,8,25,10,25,12,25,124,9,25,1,26,4,26,127,8,26,11,26,12,26,128,
+ 0,0,27,1,1,3,2,5,3,7,4,9,5,11,6,13,7,15,8,17,9,19,10,21,11,23,12,25,13,
+ 27,14,29,15,31,16,33,17,35,18,37,19,39,20,41,21,43,22,45,23,47,24,49,25,
+ 51,26,53,27,1,0,3,3,0,65,90,95,95,97,122,4,0,48,57,65,90,95,95,97,122,
+ 1,0,48,57,131,0,1,1,0,0,0,0,3,1,0,0,0,0,5,1,0,0,0,0,7,1,0,0,0,0,9,1,0,
+ 0,0,0,11,1,0,0,0,0,13,1,0,0,0,0,15,1,0,0,0,0,17,1,0,0,0,0,19,1,0,0,0,0,
+ 21,1,0,0,0,0,23,1,0,0,0,0,25,1,0,0,0,0,27,1,0,0,0,0,29,1,0,0,0,0,31,1,
+ 0,0,0,0,33,1,0,0,0,0,35,1,0,0,0,0,37,1,0,0,0,0,39,1,0,0,0,0,41,1,0,0,0,
+ 0,43,1,0,0,0,0,45,1,0,0,0,0,47,1,0,0,0,0,49,1,0,0,0,0,51,1,0,0,0,0,53,
+ 1,0,0,0,1,55,1,0,0,0,3,59,1,0,0,0,5,61,1,0,0,0,7,63,1,0,0,0,9,65,1,0,0,
+ 0,11,67,1,0,0,0,13,74,1,0,0,0,15,76,1,0,0,0,17,78,1,0,0,0,19,80,1,0,0,
+ 0,21,82,1,0,0,0,23,84,1,0,0,0,25,86,1,0,0,0,27,88,1,0,0,0,29,90,1,0,0,
+ 0,31,92,1,0,0,0,33,94,1,0,0,0,35,97,1,0,0,0,37,100,1,0,0,0,39,103,1,0,
+ 0,0,41,106,1,0,0,0,43,108,1,0,0,0,45,110,1,0,0,0,47,112,1,0,0,0,49,115,
+ 1,0,0,0,51,118,1,0,0,0,53,126,1,0,0,0,55,56,5,105,0,0,56,57,5,110,0,0,
+ 57,58,5,116,0,0,58,2,1,0,0,0,59,60,5,40,0,0,60,4,1,0,0,0,61,62,5,41,0,
+ 0,62,6,1,0,0,0,63,64,5,123,0,0,64,8,1,0,0,0,65,66,5,125,0,0,66,10,1,0,
+ 0,0,67,68,5,114,0,0,68,69,5,101,0,0,69,70,5,116,0,0,70,71,5,117,0,0,71,
+ 72,5,114,0,0,72,73,5,110,0,0,73,12,1,0,0,0,74,75,5,59,0,0,75,14,1,0,0,
+ 0,76,77,5,33,0,0,77,16,1,0,0,0,78,79,5,126,0,0,79,18,1,0,0,0,80,81,5,42,
+ 0,0,81,20,1,0,0,0,82,83,5,47,0,0,83,22,1,0,0,0,84,85,5,37,0,0,85,24,1,
+ 0,0,0,86,87,5,43,0,0,87,26,1,0,0,0,88,89,5,45,0,0,89,28,1,0,0,0,90,91,
+ 5,60,0,0,91,30,1,0,0,0,92,93,5,62,0,0,93,32,1,0,0,0,94,95,5,60,0,0,95,
+ 96,5,61,0,0,96,34,1,0,0,0,97,98,5,62,0,0,98,99,5,61,0,0,99,36,1,0,0,0,
+ 100,101,5,61,0,0,101,102,5,61,0,0,102,38,1,0,0,0,103,104,5,33,0,0,104,
+ 105,5,61,0,0,105,40,1,0,0,0,106,107,5,38,0,0,107,42,1,0,0,0,108,109,5,
+ 124,0,0,109,44,1,0,0,0,110,111,5,94,0,0,111,46,1,0,0,0,112,113,5,38,0,
+ 0,113,114,5,38,0,0,114,48,1,0,0,0,115,116,5,124,0,0,116,117,5,124,0,0,
+ 117,50,1,0,0,0,118,122,7,0,0,0,119,121,7,1,0,0,120,119,1,0,0,0,121,124,
+ 1,0,0,0,122,120,1,0,0,0,122,123,1,0,0,0,123,52,1,0,0,0,124,122,1,0,0,0,
+ 125,127,7,2,0,0,126,125,1,0,0,0,127,128,1,0,0,0,128,126,1,0,0,0,128,129,
+ 1,0,0,0,129,54,1,0,0,0,3,0,122,128,0
+ };
+
+ public static readonly ATN _ATN =
+ new ATNDeserializer().Deserialize(_serializedATN);
+
+
+}
diff --git a/Compiler/gen/CGrammarLexer.interp b/Compiler/gen/CGrammarLexer.interp
new file mode 100644
index 0000000..d041f13
--- /dev/null
+++ b/Compiler/gen/CGrammarLexer.interp
@@ -0,0 +1,98 @@
+token literal names:
+null
+'int'
+'('
+')'
+'{'
+'}'
+'return'
+';'
+'!'
+'~'
+'*'
+'/'
+'%'
+'+'
+'-'
+'<'
+'>'
+'<='
+'>='
+'=='
+'!='
+'&'
+'|'
+'^'
+'&&'
+'||'
+null
+null
+
+token symbolic names:
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+null
+ID
+INT
+
+rule names:
+T__0
+T__1
+T__2
+T__3
+T__4
+T__5
+T__6
+T__7
+T__8
+T__9
+T__10
+T__11
+T__12
+T__13
+T__14
+T__15
+T__16
+T__17
+T__18
+T__19
+T__20
+T__21
+T__22
+T__23
+T__24
+ID
+INT
+
+channel names:
+DEFAULT_TOKEN_CHANNEL
+HIDDEN
+
+mode names:
+DEFAULT_MODE
+
+atn:
+[4, 0, 27, 130, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 2, 1, 2, 1, 3, 1, 3, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 6, 1, 6, 1, 7, 1, 7, 1, 8, 1, 8, 1, 9, 1, 9, 1, 10, 1, 10, 1, 11, 1, 11, 1, 12, 1, 12, 1, 13, 1, 13, 1, 14, 1, 14, 1, 15, 1, 15, 1, 16, 1, 16, 1, 16, 1, 17, 1, 17, 1, 17, 1, 18, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 20, 1, 20, 1, 21, 1, 21, 1, 22, 1, 22, 1, 23, 1, 23, 1, 23, 1, 24, 1, 24, 1, 24, 1, 25, 1, 25, 5, 25, 121, 8, 25, 10, 25, 12, 25, 124, 9, 25, 1, 26, 4, 26, 127, 8, 26, 11, 26, 12, 26, 128, 0, 0, 27, 1, 1, 3, 2, 5, 3, 7, 4, 9, 5, 11, 6, 13, 7, 15, 8, 17, 9, 19, 10, 21, 11, 23, 12, 25, 13, 27, 14, 29, 15, 31, 16, 33, 17, 35, 18, 37, 19, 39, 20, 41, 21, 43, 22, 45, 23, 47, 24, 49, 25, 51, 26, 53, 27, 1, 0, 3, 3, 0, 65, 90, 95, 95, 97, 122, 4, 0, 48, 57, 65, 90, 95, 95, 97, 122, 1, 0, 48, 57, 131, 0, 1, 1, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 5, 1, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 9, 1, 0, 0, 0, 0, 11, 1, 0, 0, 0, 0, 13, 1, 0, 0, 0, 0, 15, 1, 0, 0, 0, 0, 17, 1, 0, 0, 0, 0, 19, 1, 0, 0, 0, 0, 21, 1, 0, 0, 0, 0, 23, 1, 0, 0, 0, 0, 25, 1, 0, 0, 0, 0, 27, 1, 0, 0, 0, 0, 29, 1, 0, 0, 0, 0, 31, 1, 0, 0, 0, 0, 33, 1, 0, 0, 0, 0, 35, 1, 0, 0, 0, 0, 37, 1, 0, 0, 0, 0, 39, 1, 0, 0, 0, 0, 41, 1, 0, 0, 0, 0, 43, 1, 0, 0, 0, 0, 45, 1, 0, 0, 0, 0, 47, 1, 0, 0, 0, 0, 49, 1, 0, 0, 0, 0, 51, 1, 0, 0, 0, 0, 53, 1, 0, 0, 0, 1, 55, 1, 0, 0, 0, 3, 59, 1, 0, 0, 0, 5, 61, 1, 0, 0, 0, 7, 63, 1, 0, 0, 0, 9, 65, 1, 0, 0, 0, 11, 67, 1, 0, 0, 0, 13, 74, 1, 0, 0, 0, 15, 76, 1, 0, 0, 0, 17, 78, 1, 0, 0, 0, 19, 80, 1, 0, 0, 0, 21, 82, 1, 0, 0, 0, 23, 84, 1, 0, 0, 0, 25, 86, 1, 0, 0, 0, 27, 88, 1, 0, 0, 0, 29, 90, 1, 0, 0, 0, 31, 92, 1, 0, 0, 0, 33, 94, 1, 0, 0, 0, 35, 97, 1, 0, 0, 0, 37, 100, 1, 0, 0, 0, 39, 103, 1, 0, 0, 0, 41, 106, 1, 0, 0, 0, 43, 108, 1, 0, 0, 0, 45, 110, 1, 0, 0, 0, 47, 112, 1, 0, 0, 0, 49, 115, 1, 0, 0, 0, 51, 118, 1, 0, 0, 0, 53, 126, 1, 0, 0, 0, 55, 56, 5, 105, 0, 0, 56, 57, 5, 110, 0, 0, 57, 58, 5, 116, 0, 0, 58, 2, 1, 0, 0, 0, 59, 60, 5, 40, 0, 0, 60, 4, 1, 0, 0, 0, 61, 62, 5, 41, 0, 0, 62, 6, 1, 0, 0, 0, 63, 64, 5, 123, 0, 0, 64, 8, 1, 0, 0, 0, 65, 66, 5, 125, 0, 0, 66, 10, 1, 0, 0, 0, 67, 68, 5, 114, 0, 0, 68, 69, 5, 101, 0, 0, 69, 70, 5, 116, 0, 0, 70, 71, 5, 117, 0, 0, 71, 72, 5, 114, 0, 0, 72, 73, 5, 110, 0, 0, 73, 12, 1, 0, 0, 0, 74, 75, 5, 59, 0, 0, 75, 14, 1, 0, 0, 0, 76, 77, 5, 33, 0, 0, 77, 16, 1, 0, 0, 0, 78, 79, 5, 126, 0, 0, 79, 18, 1, 0, 0, 0, 80, 81, 5, 42, 0, 0, 81, 20, 1, 0, 0, 0, 82, 83, 5, 47, 0, 0, 83, 22, 1, 0, 0, 0, 84, 85, 5, 37, 0, 0, 85, 24, 1, 0, 0, 0, 86, 87, 5, 43, 0, 0, 87, 26, 1, 0, 0, 0, 88, 89, 5, 45, 0, 0, 89, 28, 1, 0, 0, 0, 90, 91, 5, 60, 0, 0, 91, 30, 1, 0, 0, 0, 92, 93, 5, 62, 0, 0, 93, 32, 1, 0, 0, 0, 94, 95, 5, 60, 0, 0, 95, 96, 5, 61, 0, 0, 96, 34, 1, 0, 0, 0, 97, 98, 5, 62, 0, 0, 98, 99, 5, 61, 0, 0, 99, 36, 1, 0, 0, 0, 100, 101, 5, 61, 0, 0, 101, 102, 5, 61, 0, 0, 102, 38, 1, 0, 0, 0, 103, 104, 5, 33, 0, 0, 104, 105, 5, 61, 0, 0, 105, 40, 1, 0, 0, 0, 106, 107, 5, 38, 0, 0, 107, 42, 1, 0, 0, 0, 108, 109, 5, 124, 0, 0, 109, 44, 1, 0, 0, 0, 110, 111, 5, 94, 0, 0, 111, 46, 1, 0, 0, 0, 112, 113, 5, 38, 0, 0, 113, 114, 5, 38, 0, 0, 114, 48, 1, 0, 0, 0, 115, 116, 5, 124, 0, 0, 116, 117, 5, 124, 0, 0, 117, 50, 1, 0, 0, 0, 118, 122, 7, 0, 0, 0, 119, 121, 7, 1, 0, 0, 120, 119, 1, 0, 0, 0, 121, 124, 1, 0, 0, 0, 122, 120, 1, 0, 0, 0, 122, 123, 1, 0, 0, 0, 123, 52, 1, 0, 0, 0, 124, 122, 1, 0, 0, 0, 125, 127, 7, 2, 0, 0, 126, 125, 1, 0, 0, 0, 127, 128, 1, 0, 0, 0, 128, 126, 1, 0, 0, 0, 128, 129, 1, 0, 0, 0, 129, 54, 1, 0, 0, 0, 3, 0, 122, 128, 0]
\ No newline at end of file
diff --git a/Compiler/gen/CGrammarLexer.tokens b/Compiler/gen/CGrammarLexer.tokens
new file mode 100644
index 0000000..fc1a392
--- /dev/null
+++ b/Compiler/gen/CGrammarLexer.tokens
@@ -0,0 +1,52 @@
+T__0=1
+T__1=2
+T__2=3
+T__3=4
+T__4=5
+T__5=6
+T__6=7
+T__7=8
+T__8=9
+T__9=10
+T__10=11
+T__11=12
+T__12=13
+T__13=14
+T__14=15
+T__15=16
+T__16=17
+T__17=18
+T__18=19
+T__19=20
+T__20=21
+T__21=22
+T__22=23
+T__23=24
+T__24=25
+ID=26
+INT=27
+'int'=1
+'('=2
+')'=3
+'{'=4
+'}'=5
+'return'=6
+';'=7
+'!'=8
+'~'=9
+'*'=10
+'/'=11
+'%'=12
+'+'=13
+'-'=14
+'<'=15
+'>'=16
+'<='=17
+'>='=18
+'=='=19
+'!='=20
+'&'=21
+'|'=22
+'^'=23
+'&&'=24
+'||'=25
diff --git a/Compiler/gen/CGrammarParser.cs b/Compiler/gen/CGrammarParser.cs
new file mode 100644
index 0000000..88f1740
--- /dev/null
+++ b/Compiler/gen/CGrammarParser.cs
@@ -0,0 +1,1006 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// ANTLR Version: 4.13.2
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+// Generated from /Users/melodidey/Source/csharp/Q1/Compiler/CGrammar.g4 by ANTLR 4.13.2
+
+// Unreachable code detected
+#pragma warning disable 0162
+// The variable '...' is assigned but its value is never used
+#pragma warning disable 0219
+// Missing XML comment for publicly visible type or member '...'
+#pragma warning disable 1591
+// Ambiguous reference in cref attribute
+#pragma warning disable 419
+
+using System;
+using System.IO;
+using System.Text;
+using System.Diagnostics;
+using System.Collections.Generic;
+using Antlr4.Runtime;
+using Antlr4.Runtime.Atn;
+using Antlr4.Runtime.Misc;
+using Antlr4.Runtime.Tree;
+using DFA = Antlr4.Runtime.Dfa.DFA;
+
+[System.CodeDom.Compiler.GeneratedCode("ANTLR", "4.13.2")]
+[System.CLSCompliant(false)]
+public partial class CGrammarParser : Parser {
+ protected static DFA[] decisionToDFA;
+ protected static PredictionContextCache sharedContextCache = new PredictionContextCache();
+ public const int
+ T__0=1, T__1=2, T__2=3, T__3=4, T__4=5, T__5=6, T__6=7, T__7=8, T__8=9,
+ T__9=10, T__10=11, T__11=12, T__12=13, T__13=14, T__14=15, T__15=16, T__16=17,
+ T__17=18, T__18=19, T__19=20, T__20=21, T__21=22, T__22=23, T__23=24,
+ T__24=25, ID=26, INT=27;
+ public const int
+ RULE_program = 0, RULE_function = 1, RULE_statement = 2, RULE_expression = 3,
+ RULE_constant = 4;
+ public static readonly string[] ruleNames = {
+ "program", "function", "statement", "expression", "constant"
+ };
+
+ private static readonly string[] _LiteralNames = {
+ null, "'int'", "'('", "')'", "'{'", "'}'", "'return'", "';'", "'!'", "'~'",
+ "'*'", "'/'", "'%'", "'+'", "'-'", "'<'", "'>'", "'<='", "'>='", "'=='",
+ "'!='", "'&'", "'|'", "'^'", "'&&'", "'||'"
+ };
+ private static readonly string[] _SymbolicNames = {
+ null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, "ID", "INT"
+ };
+ public static readonly IVocabulary DefaultVocabulary = new Vocabulary(_LiteralNames, _SymbolicNames);
+
+ [NotNull]
+ public override IVocabulary Vocabulary
+ {
+ get
+ {
+ return DefaultVocabulary;
+ }
+ }
+
+ public override string GrammarFileName { get { return "CGrammar.g4"; } }
+
+ public override string[] RuleNames { get { return ruleNames; } }
+
+ public override int[] SerializedAtn { get { return _serializedATN; } }
+
+ static CGrammarParser() {
+ decisionToDFA = new DFA[_ATN.NumberOfDecisions];
+ for (int i = 0; i < _ATN.NumberOfDecisions; i++) {
+ decisionToDFA[i] = new DFA(_ATN.GetDecisionState(i), i);
+ }
+ }
+
+ public CGrammarParser(ITokenStream input) : this(input, Console.Out, Console.Error) { }
+
+ public CGrammarParser(ITokenStream input, TextWriter output, TextWriter errorOutput)
+ : base(input, output, errorOutput)
+ {
+ Interpreter = new ParserATNSimulator(this, _ATN, decisionToDFA, sharedContextCache);
+ }
+
+ public partial class ProgramContext : ParserRuleContext {
+ [System.Diagnostics.DebuggerNonUserCode] public FunctionContext function() {
+ return GetRuleContext(0);
+ }
+ [System.Diagnostics.DebuggerNonUserCode] public ITerminalNode Eof() { return GetToken(CGrammarParser.Eof, 0); }
+ public ProgramContext(ParserRuleContext parent, int invokingState)
+ : base(parent, invokingState)
+ {
+ }
+ public override int RuleIndex { get { return RULE_program; } }
+ [System.Diagnostics.DebuggerNonUserCode]
+ public override TResult Accept(IParseTreeVisitor visitor) {
+ ICGrammarVisitor typedVisitor = visitor as ICGrammarVisitor;
+ if (typedVisitor != null) return typedVisitor.VisitProgram(this);
+ else return visitor.VisitChildren(this);
+ }
+ }
+
+ [RuleVersion(0)]
+ public ProgramContext program() {
+ ProgramContext _localctx = new ProgramContext(Context, State);
+ EnterRule(_localctx, 0, RULE_program);
+ try {
+ EnterOuterAlt(_localctx, 1);
+ {
+ State = 10;
+ function();
+ State = 11;
+ Match(Eof);
+ }
+ }
+ catch (RecognitionException re) {
+ _localctx.exception = re;
+ ErrorHandler.ReportError(this, re);
+ ErrorHandler.Recover(this, re);
+ }
+ finally {
+ ExitRule();
+ }
+ return _localctx;
+ }
+
+ public partial class FunctionContext : ParserRuleContext {
+ [System.Diagnostics.DebuggerNonUserCode] public ITerminalNode ID() { return GetToken(CGrammarParser.ID, 0); }
+ [System.Diagnostics.DebuggerNonUserCode] public StatementContext[] statement() {
+ return GetRuleContexts();
+ }
+ [System.Diagnostics.DebuggerNonUserCode] public StatementContext statement(int i) {
+ return GetRuleContext(i);
+ }
+ public FunctionContext(ParserRuleContext parent, int invokingState)
+ : base(parent, invokingState)
+ {
+ }
+ public override int RuleIndex { get { return RULE_function; } }
+ [System.Diagnostics.DebuggerNonUserCode]
+ public override TResult Accept(IParseTreeVisitor visitor) {
+ ICGrammarVisitor typedVisitor = visitor as ICGrammarVisitor;
+ if (typedVisitor != null) return typedVisitor.VisitFunction(this);
+ else return visitor.VisitChildren(this);
+ }
+ }
+
+ [RuleVersion(0)]
+ public FunctionContext function() {
+ FunctionContext _localctx = new FunctionContext(Context, State);
+ EnterRule(_localctx, 2, RULE_function);
+ int _la;
+ try {
+ EnterOuterAlt(_localctx, 1);
+ {
+ State = 13;
+ Match(T__0);
+ State = 14;
+ Match(ID);
+ State = 15;
+ Match(T__1);
+ State = 16;
+ Match(T__2);
+ State = 17;
+ Match(T__3);
+ State = 21;
+ ErrorHandler.Sync(this);
+ _la = TokenStream.LA(1);
+ while (_la==T__5) {
+ {
+ {
+ State = 18;
+ statement();
+ }
+ }
+ State = 23;
+ ErrorHandler.Sync(this);
+ _la = TokenStream.LA(1);
+ }
+ State = 24;
+ Match(T__4);
+ }
+ }
+ catch (RecognitionException re) {
+ _localctx.exception = re;
+ ErrorHandler.ReportError(this, re);
+ ErrorHandler.Recover(this, re);
+ }
+ finally {
+ ExitRule();
+ }
+ return _localctx;
+ }
+
+ public partial class StatementContext : ParserRuleContext {
+ public StatementContext(ParserRuleContext parent, int invokingState)
+ : base(parent, invokingState)
+ {
+ }
+ public override int RuleIndex { get { return RULE_statement; } }
+
+ public StatementContext() { }
+ public virtual void CopyFrom(StatementContext context) {
+ base.CopyFrom(context);
+ }
+ }
+ public partial class ReturnStatementContext : StatementContext {
+ [System.Diagnostics.DebuggerNonUserCode] public ExpressionContext expression() {
+ return GetRuleContext(0);
+ }
+ public ReturnStatementContext(StatementContext context) { CopyFrom(context); }
+ [System.Diagnostics.DebuggerNonUserCode]
+ public override TResult Accept(IParseTreeVisitor visitor) {
+ ICGrammarVisitor typedVisitor = visitor as ICGrammarVisitor;
+ if (typedVisitor != null) return typedVisitor.VisitReturnStatement(this);
+ else return visitor.VisitChildren(this);
+ }
+ }
+
+ [RuleVersion(0)]
+ public StatementContext statement() {
+ StatementContext _localctx = new StatementContext(Context, State);
+ EnterRule(_localctx, 4, RULE_statement);
+ try {
+ _localctx = new ReturnStatementContext(_localctx);
+ EnterOuterAlt(_localctx, 1);
+ {
+ State = 26;
+ Match(T__5);
+ State = 27;
+ expression(0);
+ State = 28;
+ Match(T__6);
+ }
+ }
+ catch (RecognitionException re) {
+ _localctx.exception = re;
+ ErrorHandler.ReportError(this, re);
+ ErrorHandler.Recover(this, re);
+ }
+ finally {
+ ExitRule();
+ }
+ return _localctx;
+ }
+
+ public partial class ExpressionContext : ParserRuleContext {
+ public ExpressionContext(ParserRuleContext parent, int invokingState)
+ : base(parent, invokingState)
+ {
+ }
+ public override int RuleIndex { get { return RULE_expression; } }
+
+ public ExpressionContext() { }
+ public virtual void CopyFrom(ExpressionContext context) {
+ base.CopyFrom(context);
+ }
+ }
+ public partial class BitwiseXorExpressionContext : ExpressionContext {
+ public ExpressionContext left;
+ public ExpressionContext right;
+ [System.Diagnostics.DebuggerNonUserCode] public ExpressionContext[] expression() {
+ return GetRuleContexts();
+ }
+ [System.Diagnostics.DebuggerNonUserCode] public ExpressionContext expression(int i) {
+ return GetRuleContext(i);
+ }
+ public BitwiseXorExpressionContext(ExpressionContext context) { CopyFrom(context); }
+ [System.Diagnostics.DebuggerNonUserCode]
+ public override TResult Accept(IParseTreeVisitor visitor) {
+ ICGrammarVisitor typedVisitor = visitor as ICGrammarVisitor;
+ if (typedVisitor != null) return typedVisitor.VisitBitwiseXorExpression(this);
+ else return visitor.VisitChildren(this);
+ }
+ }
+ public partial class ConstantExpressionContext : ExpressionContext {
+ [System.Diagnostics.DebuggerNonUserCode] public ConstantContext constant() {
+ return GetRuleContext(0);
+ }
+ public ConstantExpressionContext(ExpressionContext context) { CopyFrom(context); }
+ [System.Diagnostics.DebuggerNonUserCode]
+ public override TResult Accept(IParseTreeVisitor visitor) {
+ ICGrammarVisitor typedVisitor = visitor as ICGrammarVisitor;
+ if (typedVisitor != null) return typedVisitor.VisitConstantExpression(this);
+ else return visitor.VisitChildren(this);
+ }
+ }
+ public partial class LessThanOrEqualExpressionContext : ExpressionContext {
+ public ExpressionContext left;
+ public ExpressionContext right;
+ [System.Diagnostics.DebuggerNonUserCode] public ExpressionContext[] expression() {
+ return GetRuleContexts();
+ }
+ [System.Diagnostics.DebuggerNonUserCode] public ExpressionContext expression(int i) {
+ return GetRuleContext(i);
+ }
+ public LessThanOrEqualExpressionContext(ExpressionContext context) { CopyFrom(context); }
+ [System.Diagnostics.DebuggerNonUserCode]
+ public override TResult Accept(IParseTreeVisitor visitor) {
+ ICGrammarVisitor typedVisitor = visitor as ICGrammarVisitor;
+ if (typedVisitor != null) return typedVisitor.VisitLessThanOrEqualExpression(this);
+ else return visitor.VisitChildren(this);
+ }
+ }
+ public partial class ModulusExpressionContext : ExpressionContext {
+ public ExpressionContext left;
+ public ExpressionContext right;
+ [System.Diagnostics.DebuggerNonUserCode] public ExpressionContext[] expression() {
+ return GetRuleContexts();
+ }
+ [System.Diagnostics.DebuggerNonUserCode] public ExpressionContext expression(int i) {
+ return GetRuleContext(i);
+ }
+ public ModulusExpressionContext(ExpressionContext context) { CopyFrom(context); }
+ [System.Diagnostics.DebuggerNonUserCode]
+ public override TResult Accept(IParseTreeVisitor visitor) {
+ ICGrammarVisitor typedVisitor = visitor as ICGrammarVisitor;
+ if (typedVisitor != null) return typedVisitor.VisitModulusExpression(this);
+ else return visitor.VisitChildren(this);
+ }
+ }
+ public partial class NotExpressionContext : ExpressionContext {
+ [System.Diagnostics.DebuggerNonUserCode] public ExpressionContext expression() {
+ return GetRuleContext(0);
+ }
+ public NotExpressionContext(ExpressionContext context) { CopyFrom(context); }
+ [System.Diagnostics.DebuggerNonUserCode]
+ public override TResult Accept(IParseTreeVisitor visitor) {
+ ICGrammarVisitor typedVisitor = visitor as ICGrammarVisitor;
+ if (typedVisitor != null) return typedVisitor.VisitNotExpression(this);
+ else return visitor.VisitChildren(this);
+ }
+ }
+ public partial class NotEqualExpressionContext : ExpressionContext {
+ public ExpressionContext left;
+ public ExpressionContext right;
+ [System.Diagnostics.DebuggerNonUserCode] public ExpressionContext[] expression() {
+ return GetRuleContexts();
+ }
+ [System.Diagnostics.DebuggerNonUserCode] public ExpressionContext expression(int i) {
+ return GetRuleContext(i);
+ }
+ public NotEqualExpressionContext(ExpressionContext context) { CopyFrom(context); }
+ [System.Diagnostics.DebuggerNonUserCode]
+ public override TResult Accept(IParseTreeVisitor visitor) {
+ ICGrammarVisitor typedVisitor = visitor as ICGrammarVisitor;
+ if (typedVisitor != null) return typedVisitor.VisitNotEqualExpression(this);
+ else return visitor.VisitChildren(this);
+ }
+ }
+ public partial class MultiplyExpressionContext : ExpressionContext {
+ public ExpressionContext left;
+ public ExpressionContext right;
+ [System.Diagnostics.DebuggerNonUserCode] public ExpressionContext[] expression() {
+ return GetRuleContexts();
+ }
+ [System.Diagnostics.DebuggerNonUserCode] public ExpressionContext expression(int i) {
+ return GetRuleContext(i);
+ }
+ public MultiplyExpressionContext(ExpressionContext context) { CopyFrom(context); }
+ [System.Diagnostics.DebuggerNonUserCode]
+ public override TResult Accept(IParseTreeVisitor visitor) {
+ ICGrammarVisitor typedVisitor = visitor as ICGrammarVisitor;
+ if (typedVisitor != null) return typedVisitor.VisitMultiplyExpression(this);
+ else return visitor.VisitChildren(this);
+ }
+ }
+ public partial class GreaterThanExpressionContext : ExpressionContext {
+ public ExpressionContext left;
+ public ExpressionContext right;
+ [System.Diagnostics.DebuggerNonUserCode] public ExpressionContext[] expression() {
+ return GetRuleContexts();
+ }
+ [System.Diagnostics.DebuggerNonUserCode] public ExpressionContext expression(int i) {
+ return GetRuleContext(i);
+ }
+ public GreaterThanExpressionContext(ExpressionContext context) { CopyFrom(context); }
+ [System.Diagnostics.DebuggerNonUserCode]
+ public override TResult Accept(IParseTreeVisitor visitor) {
+ ICGrammarVisitor typedVisitor = visitor as ICGrammarVisitor;
+ if (typedVisitor != null) return typedVisitor.VisitGreaterThanExpression(this);
+ else return visitor.VisitChildren(this);
+ }
+ }
+ public partial class LogicalOrExpressionContext : ExpressionContext {
+ public ExpressionContext left;
+ public ExpressionContext right;
+ [System.Diagnostics.DebuggerNonUserCode] public ExpressionContext[] expression() {
+ return GetRuleContexts();
+ }
+ [System.Diagnostics.DebuggerNonUserCode] public ExpressionContext expression(int i) {
+ return GetRuleContext(i);
+ }
+ public LogicalOrExpressionContext(ExpressionContext context) { CopyFrom(context); }
+ [System.Diagnostics.DebuggerNonUserCode]
+ public override TResult Accept(IParseTreeVisitor visitor) {
+ ICGrammarVisitor typedVisitor = visitor as ICGrammarVisitor;
+ if (typedVisitor != null) return typedVisitor.VisitLogicalOrExpression(this);
+ else return visitor.VisitChildren(this);
+ }
+ }
+ public partial class GreaterThanOrEqualExpressionContext : ExpressionContext {
+ public ExpressionContext left;
+ public ExpressionContext right;
+ [System.Diagnostics.DebuggerNonUserCode] public ExpressionContext[] expression() {
+ return GetRuleContexts();
+ }
+ [System.Diagnostics.DebuggerNonUserCode] public ExpressionContext expression(int i) {
+ return GetRuleContext(i);
+ }
+ public GreaterThanOrEqualExpressionContext(ExpressionContext context) { CopyFrom(context); }
+ [System.Diagnostics.DebuggerNonUserCode]
+ public override TResult Accept(IParseTreeVisitor visitor) {
+ ICGrammarVisitor typedVisitor = visitor as ICGrammarVisitor;
+ if (typedVisitor != null) return typedVisitor.VisitGreaterThanOrEqualExpression(this);
+ else return visitor.VisitChildren(this);
+ }
+ }
+ public partial class DivideExpressionContext : ExpressionContext {
+ public ExpressionContext left;
+ public ExpressionContext right;
+ [System.Diagnostics.DebuggerNonUserCode] public ExpressionContext[] expression() {
+ return GetRuleContexts();
+ }
+ [System.Diagnostics.DebuggerNonUserCode] public ExpressionContext expression(int i) {
+ return GetRuleContext(i);
+ }
+ public DivideExpressionContext(ExpressionContext context) { CopyFrom(context); }
+ [System.Diagnostics.DebuggerNonUserCode]
+ public override TResult Accept(IParseTreeVisitor visitor) {
+ ICGrammarVisitor typedVisitor = visitor as ICGrammarVisitor;
+ if (typedVisitor != null) return typedVisitor.VisitDivideExpression(this);
+ else return visitor.VisitChildren(this);
+ }
+ }
+ public partial class BitwiseOrExpressionContext : ExpressionContext {
+ public ExpressionContext left;
+ public ExpressionContext right;
+ [System.Diagnostics.DebuggerNonUserCode] public ExpressionContext[] expression() {
+ return GetRuleContexts();
+ }
+ [System.Diagnostics.DebuggerNonUserCode] public ExpressionContext expression(int i) {
+ return GetRuleContext(i);
+ }
+ public BitwiseOrExpressionContext(ExpressionContext context) { CopyFrom(context); }
+ [System.Diagnostics.DebuggerNonUserCode]
+ public override TResult Accept(IParseTreeVisitor visitor) {
+ ICGrammarVisitor typedVisitor = visitor as ICGrammarVisitor;
+ if (typedVisitor != null) return typedVisitor.VisitBitwiseOrExpression(this);
+ else return visitor.VisitChildren(this);
+ }
+ }
+ public partial class ParenthesizedExpressionContext : ExpressionContext {
+ [System.Diagnostics.DebuggerNonUserCode] public ExpressionContext expression() {
+ return GetRuleContext(0);
+ }
+ public ParenthesizedExpressionContext(ExpressionContext context) { CopyFrom(context); }
+ [System.Diagnostics.DebuggerNonUserCode]
+ public override TResult Accept(IParseTreeVisitor visitor) {
+ ICGrammarVisitor typedVisitor = visitor as ICGrammarVisitor;
+ if (typedVisitor != null) return typedVisitor.VisitParenthesizedExpression(this);
+ else return visitor.VisitChildren(this);
+ }
+ }
+ public partial class AddExpressionContext : ExpressionContext {
+ public ExpressionContext left;
+ public ExpressionContext right;
+ [System.Diagnostics.DebuggerNonUserCode] public ExpressionContext[] expression() {
+ return GetRuleContexts();
+ }
+ [System.Diagnostics.DebuggerNonUserCode] public ExpressionContext expression(int i) {
+ return GetRuleContext(i);
+ }
+ public AddExpressionContext(ExpressionContext context) { CopyFrom(context); }
+ [System.Diagnostics.DebuggerNonUserCode]
+ public override TResult Accept(IParseTreeVisitor visitor) {
+ ICGrammarVisitor typedVisitor = visitor as ICGrammarVisitor;
+ if (typedVisitor != null) return typedVisitor.VisitAddExpression(this);
+ else return visitor.VisitChildren(this);
+ }
+ }
+ public partial class SubtractExpressionContext : ExpressionContext {
+ public ExpressionContext left;
+ public ExpressionContext right;
+ [System.Diagnostics.DebuggerNonUserCode] public ExpressionContext[] expression() {
+ return GetRuleContexts();
+ }
+ [System.Diagnostics.DebuggerNonUserCode] public ExpressionContext expression(int i) {
+ return GetRuleContext(i);
+ }
+ public SubtractExpressionContext(ExpressionContext context) { CopyFrom(context); }
+ [System.Diagnostics.DebuggerNonUserCode]
+ public override TResult Accept(IParseTreeVisitor visitor) {
+ ICGrammarVisitor typedVisitor = visitor as ICGrammarVisitor;
+ if (typedVisitor != null) return typedVisitor.VisitSubtractExpression(this);
+ else return visitor.VisitChildren(this);
+ }
+ }
+ public partial class BitwiseAndExpressionContext : ExpressionContext {
+ public ExpressionContext left;
+ public ExpressionContext right;
+ [System.Diagnostics.DebuggerNonUserCode] public ExpressionContext[] expression() {
+ return GetRuleContexts();
+ }
+ [System.Diagnostics.DebuggerNonUserCode] public ExpressionContext expression(int i) {
+ return GetRuleContext(i);
+ }
+ public BitwiseAndExpressionContext(ExpressionContext context) { CopyFrom(context); }
+ [System.Diagnostics.DebuggerNonUserCode]
+ public override TResult Accept(IParseTreeVisitor visitor) {
+ ICGrammarVisitor typedVisitor = visitor as ICGrammarVisitor;
+ if (typedVisitor != null) return typedVisitor.VisitBitwiseAndExpression(this);
+ else return visitor.VisitChildren(this);
+ }
+ }
+ public partial class LessThanExpressionContext : ExpressionContext {
+ public ExpressionContext left;
+ public ExpressionContext right;
+ [System.Diagnostics.DebuggerNonUserCode] public ExpressionContext[] expression() {
+ return GetRuleContexts();
+ }
+ [System.Diagnostics.DebuggerNonUserCode] public ExpressionContext expression(int i) {
+ return GetRuleContext(i);
+ }
+ public LessThanExpressionContext(ExpressionContext context) { CopyFrom(context); }
+ [System.Diagnostics.DebuggerNonUserCode]
+ public override TResult Accept(IParseTreeVisitor visitor) {
+ ICGrammarVisitor typedVisitor = visitor as ICGrammarVisitor;
+ if (typedVisitor != null) return typedVisitor.VisitLessThanExpression(this);
+ else return visitor.VisitChildren(this);
+ }
+ }
+ public partial class LogicalAndExpressionContext : ExpressionContext {
+ public ExpressionContext left;
+ public ExpressionContext right;
+ [System.Diagnostics.DebuggerNonUserCode] public ExpressionContext[] expression() {
+ return GetRuleContexts();
+ }
+ [System.Diagnostics.DebuggerNonUserCode] public ExpressionContext expression(int i) {
+ return GetRuleContext(i);
+ }
+ public LogicalAndExpressionContext(ExpressionContext context) { CopyFrom(context); }
+ [System.Diagnostics.DebuggerNonUserCode]
+ public override TResult Accept(IParseTreeVisitor visitor) {
+ ICGrammarVisitor typedVisitor = visitor as ICGrammarVisitor;
+ if (typedVisitor != null) return typedVisitor.VisitLogicalAndExpression(this);
+ else return visitor.VisitChildren(this);
+ }
+ }
+ public partial class InvertExpressionContext : ExpressionContext {
+ [System.Diagnostics.DebuggerNonUserCode] public ExpressionContext expression() {
+ return GetRuleContext(0);
+ }
+ public InvertExpressionContext(ExpressionContext context) { CopyFrom(context); }
+ [System.Diagnostics.DebuggerNonUserCode]
+ public override TResult Accept(IParseTreeVisitor visitor) {
+ ICGrammarVisitor typedVisitor = visitor as ICGrammarVisitor;
+ if (typedVisitor != null) return typedVisitor.VisitInvertExpression(this);
+ else return visitor.VisitChildren(this);
+ }
+ }
+ public partial class EqualExpressionContext : ExpressionContext {
+ public ExpressionContext left;
+ public ExpressionContext right;
+ [System.Diagnostics.DebuggerNonUserCode] public ExpressionContext[] expression() {
+ return GetRuleContexts();
+ }
+ [System.Diagnostics.DebuggerNonUserCode] public ExpressionContext expression(int i) {
+ return GetRuleContext(i);
+ }
+ public EqualExpressionContext(ExpressionContext context) { CopyFrom(context); }
+ [System.Diagnostics.DebuggerNonUserCode]
+ public override TResult Accept(IParseTreeVisitor visitor) {
+ ICGrammarVisitor typedVisitor = visitor as ICGrammarVisitor;
+ if (typedVisitor != null) return typedVisitor.VisitEqualExpression(this);
+ else return visitor.VisitChildren(this);
+ }
+ }
+
+ [RuleVersion(0)]
+ public ExpressionContext expression() {
+ return expression(0);
+ }
+
+ private ExpressionContext expression(int _p) {
+ ParserRuleContext _parentctx = Context;
+ int _parentState = State;
+ ExpressionContext _localctx = new ExpressionContext(Context, _parentState);
+ ExpressionContext _prevctx = _localctx;
+ int _startState = 6;
+ EnterRecursionRule(_localctx, 6, RULE_expression, _p);
+ try {
+ int _alt;
+ EnterOuterAlt(_localctx, 1);
+ {
+ State = 40;
+ ErrorHandler.Sync(this);
+ switch (TokenStream.LA(1)) {
+ case T__1:
+ {
+ _localctx = new ParenthesizedExpressionContext(_localctx);
+ Context = _localctx;
+ _prevctx = _localctx;
+
+ State = 31;
+ Match(T__1);
+ State = 32;
+ expression(0);
+ State = 33;
+ Match(T__2);
+ }
+ break;
+ case T__7:
+ {
+ _localctx = new NotExpressionContext(_localctx);
+ Context = _localctx;
+ _prevctx = _localctx;
+ State = 35;
+ Match(T__7);
+ State = 36;
+ expression(19);
+ }
+ break;
+ case T__8:
+ {
+ _localctx = new InvertExpressionContext(_localctx);
+ Context = _localctx;
+ _prevctx = _localctx;
+ State = 37;
+ Match(T__8);
+ State = 38;
+ expression(18);
+ }
+ break;
+ case INT:
+ {
+ _localctx = new ConstantExpressionContext(_localctx);
+ Context = _localctx;
+ _prevctx = _localctx;
+ State = 39;
+ constant();
+ }
+ break;
+ default:
+ throw new NoViableAltException(this);
+ }
+ Context.Stop = TokenStream.LT(-1);
+ State = 92;
+ ErrorHandler.Sync(this);
+ _alt = Interpreter.AdaptivePredict(TokenStream,3,Context);
+ while ( _alt!=2 && _alt!=global::Antlr4.Runtime.Atn.ATN.INVALID_ALT_NUMBER ) {
+ if ( _alt==1 ) {
+ if ( ParseListeners!=null )
+ TriggerExitRuleEvent();
+ _prevctx = _localctx;
+ {
+ State = 90;
+ ErrorHandler.Sync(this);
+ switch ( Interpreter.AdaptivePredict(TokenStream,2,Context) ) {
+ case 1:
+ {
+ _localctx = new MultiplyExpressionContext(new ExpressionContext(_parentctx, _parentState));
+ ((MultiplyExpressionContext)_localctx).left = _prevctx;
+ PushNewRecursionContext(_localctx, _startState, RULE_expression);
+ State = 42;
+ if (!(Precpred(Context, 17))) throw new FailedPredicateException(this, "Precpred(Context, 17)");
+ State = 43;
+ Match(T__9);
+ State = 44;
+ ((MultiplyExpressionContext)_localctx).right = expression(18);
+ }
+ break;
+ case 2:
+ {
+ _localctx = new DivideExpressionContext(new ExpressionContext(_parentctx, _parentState));
+ ((DivideExpressionContext)_localctx).left = _prevctx;
+ PushNewRecursionContext(_localctx, _startState, RULE_expression);
+ State = 45;
+ if (!(Precpred(Context, 16))) throw new FailedPredicateException(this, "Precpred(Context, 16)");
+ State = 46;
+ Match(T__10);
+ State = 47;
+ ((DivideExpressionContext)_localctx).right = expression(17);
+ }
+ break;
+ case 3:
+ {
+ _localctx = new ModulusExpressionContext(new ExpressionContext(_parentctx, _parentState));
+ ((ModulusExpressionContext)_localctx).left = _prevctx;
+ PushNewRecursionContext(_localctx, _startState, RULE_expression);
+ State = 48;
+ if (!(Precpred(Context, 15))) throw new FailedPredicateException(this, "Precpred(Context, 15)");
+ State = 49;
+ Match(T__11);
+ State = 50;
+ ((ModulusExpressionContext)_localctx).right = expression(16);
+ }
+ break;
+ case 4:
+ {
+ _localctx = new AddExpressionContext(new ExpressionContext(_parentctx, _parentState));
+ ((AddExpressionContext)_localctx).left = _prevctx;
+ PushNewRecursionContext(_localctx, _startState, RULE_expression);
+ State = 51;
+ if (!(Precpred(Context, 14))) throw new FailedPredicateException(this, "Precpred(Context, 14)");
+ State = 52;
+ Match(T__12);
+ State = 53;
+ ((AddExpressionContext)_localctx).right = expression(15);
+ }
+ break;
+ case 5:
+ {
+ _localctx = new SubtractExpressionContext(new ExpressionContext(_parentctx, _parentState));
+ ((SubtractExpressionContext)_localctx).left = _prevctx;
+ PushNewRecursionContext(_localctx, _startState, RULE_expression);
+ State = 54;
+ if (!(Precpred(Context, 13))) throw new FailedPredicateException(this, "Precpred(Context, 13)");
+ State = 55;
+ Match(T__13);
+ State = 56;
+ ((SubtractExpressionContext)_localctx).right = expression(14);
+ }
+ break;
+ case 6:
+ {
+ _localctx = new LessThanExpressionContext(new ExpressionContext(_parentctx, _parentState));
+ ((LessThanExpressionContext)_localctx).left = _prevctx;
+ PushNewRecursionContext(_localctx, _startState, RULE_expression);
+ State = 57;
+ if (!(Precpred(Context, 12))) throw new FailedPredicateException(this, "Precpred(Context, 12)");
+ State = 58;
+ Match(T__14);
+ State = 59;
+ ((LessThanExpressionContext)_localctx).right = expression(13);
+ }
+ break;
+ case 7:
+ {
+ _localctx = new GreaterThanExpressionContext(new ExpressionContext(_parentctx, _parentState));
+ ((GreaterThanExpressionContext)_localctx).left = _prevctx;
+ PushNewRecursionContext(_localctx, _startState, RULE_expression);
+ State = 60;
+ if (!(Precpred(Context, 11))) throw new FailedPredicateException(this, "Precpred(Context, 11)");
+ State = 61;
+ Match(T__15);
+ State = 62;
+ ((GreaterThanExpressionContext)_localctx).right = expression(12);
+ }
+ break;
+ case 8:
+ {
+ _localctx = new LessThanOrEqualExpressionContext(new ExpressionContext(_parentctx, _parentState));
+ ((LessThanOrEqualExpressionContext)_localctx).left = _prevctx;
+ PushNewRecursionContext(_localctx, _startState, RULE_expression);
+ State = 63;
+ if (!(Precpred(Context, 10))) throw new FailedPredicateException(this, "Precpred(Context, 10)");
+ State = 64;
+ Match(T__16);
+ State = 65;
+ ((LessThanOrEqualExpressionContext)_localctx).right = expression(11);
+ }
+ break;
+ case 9:
+ {
+ _localctx = new GreaterThanOrEqualExpressionContext(new ExpressionContext(_parentctx, _parentState));
+ ((GreaterThanOrEqualExpressionContext)_localctx).left = _prevctx;
+ PushNewRecursionContext(_localctx, _startState, RULE_expression);
+ State = 66;
+ if (!(Precpred(Context, 9))) throw new FailedPredicateException(this, "Precpred(Context, 9)");
+ State = 67;
+ Match(T__17);
+ State = 68;
+ ((GreaterThanOrEqualExpressionContext)_localctx).right = expression(10);
+ }
+ break;
+ case 10:
+ {
+ _localctx = new EqualExpressionContext(new ExpressionContext(_parentctx, _parentState));
+ ((EqualExpressionContext)_localctx).left = _prevctx;
+ PushNewRecursionContext(_localctx, _startState, RULE_expression);
+ State = 69;
+ if (!(Precpred(Context, 8))) throw new FailedPredicateException(this, "Precpred(Context, 8)");
+ State = 70;
+ Match(T__18);
+ State = 71;
+ ((EqualExpressionContext)_localctx).right = expression(9);
+ }
+ break;
+ case 11:
+ {
+ _localctx = new NotEqualExpressionContext(new ExpressionContext(_parentctx, _parentState));
+ ((NotEqualExpressionContext)_localctx).left = _prevctx;
+ PushNewRecursionContext(_localctx, _startState, RULE_expression);
+ State = 72;
+ if (!(Precpred(Context, 7))) throw new FailedPredicateException(this, "Precpred(Context, 7)");
+ State = 73;
+ Match(T__19);
+ State = 74;
+ ((NotEqualExpressionContext)_localctx).right = expression(8);
+ }
+ break;
+ case 12:
+ {
+ _localctx = new BitwiseAndExpressionContext(new ExpressionContext(_parentctx, _parentState));
+ ((BitwiseAndExpressionContext)_localctx).left = _prevctx;
+ PushNewRecursionContext(_localctx, _startState, RULE_expression);
+ State = 75;
+ if (!(Precpred(Context, 6))) throw new FailedPredicateException(this, "Precpred(Context, 6)");
+ State = 76;
+ Match(T__20);
+ State = 77;
+ ((BitwiseAndExpressionContext)_localctx).right = expression(7);
+ }
+ break;
+ case 13:
+ {
+ _localctx = new BitwiseOrExpressionContext(new ExpressionContext(_parentctx, _parentState));
+ ((BitwiseOrExpressionContext)_localctx).left = _prevctx;
+ PushNewRecursionContext(_localctx, _startState, RULE_expression);
+ State = 78;
+ if (!(Precpred(Context, 5))) throw new FailedPredicateException(this, "Precpred(Context, 5)");
+ State = 79;
+ Match(T__21);
+ State = 80;
+ ((BitwiseOrExpressionContext)_localctx).right = expression(6);
+ }
+ break;
+ case 14:
+ {
+ _localctx = new BitwiseXorExpressionContext(new ExpressionContext(_parentctx, _parentState));
+ ((BitwiseXorExpressionContext)_localctx).left = _prevctx;
+ PushNewRecursionContext(_localctx, _startState, RULE_expression);
+ State = 81;
+ if (!(Precpred(Context, 4))) throw new FailedPredicateException(this, "Precpred(Context, 4)");
+ State = 82;
+ Match(T__22);
+ State = 83;
+ ((BitwiseXorExpressionContext)_localctx).right = expression(5);
+ }
+ break;
+ case 15:
+ {
+ _localctx = new LogicalAndExpressionContext(new ExpressionContext(_parentctx, _parentState));
+ ((LogicalAndExpressionContext)_localctx).left = _prevctx;
+ PushNewRecursionContext(_localctx, _startState, RULE_expression);
+ State = 84;
+ if (!(Precpred(Context, 3))) throw new FailedPredicateException(this, "Precpred(Context, 3)");
+ State = 85;
+ Match(T__23);
+ State = 86;
+ ((LogicalAndExpressionContext)_localctx).right = expression(4);
+ }
+ break;
+ case 16:
+ {
+ _localctx = new LogicalOrExpressionContext(new ExpressionContext(_parentctx, _parentState));
+ ((LogicalOrExpressionContext)_localctx).left = _prevctx;
+ PushNewRecursionContext(_localctx, _startState, RULE_expression);
+ State = 87;
+ if (!(Precpred(Context, 2))) throw new FailedPredicateException(this, "Precpred(Context, 2)");
+ State = 88;
+ Match(T__24);
+ State = 89;
+ ((LogicalOrExpressionContext)_localctx).right = expression(3);
+ }
+ break;
+ }
+ }
+ }
+ State = 94;
+ ErrorHandler.Sync(this);
+ _alt = Interpreter.AdaptivePredict(TokenStream,3,Context);
+ }
+ }
+ }
+ catch (RecognitionException re) {
+ _localctx.exception = re;
+ ErrorHandler.ReportError(this, re);
+ ErrorHandler.Recover(this, re);
+ }
+ finally {
+ UnrollRecursionContexts(_parentctx);
+ }
+ return _localctx;
+ }
+
+ public partial class ConstantContext : ParserRuleContext {
+ public ConstantContext(ParserRuleContext parent, int invokingState)
+ : base(parent, invokingState)
+ {
+ }
+ public override int RuleIndex { get { return RULE_constant; } }
+
+ public ConstantContext() { }
+ public virtual void CopyFrom(ConstantContext context) {
+ base.CopyFrom(context);
+ }
+ }
+ public partial class IntConstantContext : ConstantContext {
+ [System.Diagnostics.DebuggerNonUserCode] public ITerminalNode INT() { return GetToken(CGrammarParser.INT, 0); }
+ public IntConstantContext(ConstantContext context) { CopyFrom(context); }
+ [System.Diagnostics.DebuggerNonUserCode]
+ public override TResult Accept(IParseTreeVisitor visitor) {
+ ICGrammarVisitor typedVisitor = visitor as ICGrammarVisitor;
+ if (typedVisitor != null) return typedVisitor.VisitIntConstant(this);
+ else return visitor.VisitChildren(this);
+ }
+ }
+
+ [RuleVersion(0)]
+ public ConstantContext constant() {
+ ConstantContext _localctx = new ConstantContext(Context, State);
+ EnterRule(_localctx, 8, RULE_constant);
+ try {
+ _localctx = new IntConstantContext(_localctx);
+ EnterOuterAlt(_localctx, 1);
+ {
+ State = 95;
+ Match(INT);
+ }
+ }
+ catch (RecognitionException re) {
+ _localctx.exception = re;
+ ErrorHandler.ReportError(this, re);
+ ErrorHandler.Recover(this, re);
+ }
+ finally {
+ ExitRule();
+ }
+ return _localctx;
+ }
+
+ public override bool Sempred(RuleContext _localctx, int ruleIndex, int predIndex) {
+ switch (ruleIndex) {
+ case 3: return expression_sempred((ExpressionContext)_localctx, predIndex);
+ }
+ return true;
+ }
+ private bool expression_sempred(ExpressionContext _localctx, int predIndex) {
+ switch (predIndex) {
+ case 0: return Precpred(Context, 17);
+ case 1: return Precpred(Context, 16);
+ case 2: return Precpred(Context, 15);
+ case 3: return Precpred(Context, 14);
+ case 4: return Precpred(Context, 13);
+ case 5: return Precpred(Context, 12);
+ case 6: return Precpred(Context, 11);
+ case 7: return Precpred(Context, 10);
+ case 8: return Precpred(Context, 9);
+ case 9: return Precpred(Context, 8);
+ case 10: return Precpred(Context, 7);
+ case 11: return Precpred(Context, 6);
+ case 12: return Precpred(Context, 5);
+ case 13: return Precpred(Context, 4);
+ case 14: return Precpred(Context, 3);
+ case 15: return Precpred(Context, 2);
+ }
+ return true;
+ }
+
+ private static int[] _serializedATN = {
+ 4,1,27,98,2,0,7,0,2,1,7,1,2,2,7,2,2,3,7,3,2,4,7,4,1,0,1,0,1,0,1,1,1,1,
+ 1,1,1,1,1,1,1,1,5,1,20,8,1,10,1,12,1,23,9,1,1,1,1,1,1,2,1,2,1,2,1,2,1,
+ 3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,3,3,41,8,3,1,3,1,3,1,3,1,3,1,3,1,
+ 3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,
+ 1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,
+ 3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,5,3,91,8,3,10,3,12,3,94,9,3,1,4,1,4,1,4,
+ 0,1,6,5,0,2,4,6,8,0,0,112,0,10,1,0,0,0,2,13,1,0,0,0,4,26,1,0,0,0,6,40,
+ 1,0,0,0,8,95,1,0,0,0,10,11,3,2,1,0,11,12,5,0,0,1,12,1,1,0,0,0,13,14,5,
+ 1,0,0,14,15,5,26,0,0,15,16,5,2,0,0,16,17,5,3,0,0,17,21,5,4,0,0,18,20,3,
+ 4,2,0,19,18,1,0,0,0,20,23,1,0,0,0,21,19,1,0,0,0,21,22,1,0,0,0,22,24,1,
+ 0,0,0,23,21,1,0,0,0,24,25,5,5,0,0,25,3,1,0,0,0,26,27,5,6,0,0,27,28,3,6,
+ 3,0,28,29,5,7,0,0,29,5,1,0,0,0,30,31,6,3,-1,0,31,32,5,2,0,0,32,33,3,6,
+ 3,0,33,34,5,3,0,0,34,41,1,0,0,0,35,36,5,8,0,0,36,41,3,6,3,19,37,38,5,9,
+ 0,0,38,41,3,6,3,18,39,41,3,8,4,0,40,30,1,0,0,0,40,35,1,0,0,0,40,37,1,0,
+ 0,0,40,39,1,0,0,0,41,92,1,0,0,0,42,43,10,17,0,0,43,44,5,10,0,0,44,91,3,
+ 6,3,18,45,46,10,16,0,0,46,47,5,11,0,0,47,91,3,6,3,17,48,49,10,15,0,0,49,
+ 50,5,12,0,0,50,91,3,6,3,16,51,52,10,14,0,0,52,53,5,13,0,0,53,91,3,6,3,
+ 15,54,55,10,13,0,0,55,56,5,14,0,0,56,91,3,6,3,14,57,58,10,12,0,0,58,59,
+ 5,15,0,0,59,91,3,6,3,13,60,61,10,11,0,0,61,62,5,16,0,0,62,91,3,6,3,12,
+ 63,64,10,10,0,0,64,65,5,17,0,0,65,91,3,6,3,11,66,67,10,9,0,0,67,68,5,18,
+ 0,0,68,91,3,6,3,10,69,70,10,8,0,0,70,71,5,19,0,0,71,91,3,6,3,9,72,73,10,
+ 7,0,0,73,74,5,20,0,0,74,91,3,6,3,8,75,76,10,6,0,0,76,77,5,21,0,0,77,91,
+ 3,6,3,7,78,79,10,5,0,0,79,80,5,22,0,0,80,91,3,6,3,6,81,82,10,4,0,0,82,
+ 83,5,23,0,0,83,91,3,6,3,5,84,85,10,3,0,0,85,86,5,24,0,0,86,91,3,6,3,4,
+ 87,88,10,2,0,0,88,89,5,25,0,0,89,91,3,6,3,3,90,42,1,0,0,0,90,45,1,0,0,
+ 0,90,48,1,0,0,0,90,51,1,0,0,0,90,54,1,0,0,0,90,57,1,0,0,0,90,60,1,0,0,
+ 0,90,63,1,0,0,0,90,66,1,0,0,0,90,69,1,0,0,0,90,72,1,0,0,0,90,75,1,0,0,
+ 0,90,78,1,0,0,0,90,81,1,0,0,0,90,84,1,0,0,0,90,87,1,0,0,0,91,94,1,0,0,
+ 0,92,90,1,0,0,0,92,93,1,0,0,0,93,7,1,0,0,0,94,92,1,0,0,0,95,96,5,27,0,
+ 0,96,9,1,0,0,0,4,21,40,90,92
+ };
+
+ public static readonly ATN _ATN =
+ new ATNDeserializer().Deserialize(_serializedATN);
+
+
+}
diff --git a/Compiler/gen/CGrammarVisitor.cs b/Compiler/gen/CGrammarVisitor.cs
new file mode 100644
index 0000000..1f9691a
--- /dev/null
+++ b/Compiler/gen/CGrammarVisitor.cs
@@ -0,0 +1,200 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// ANTLR Version: 4.13.2
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+// Generated from /Users/melodidey/Source/csharp/Q1/Compiler/CGrammar.g4 by ANTLR 4.13.2
+
+// Unreachable code detected
+#pragma warning disable 0162
+// The variable '...' is assigned but its value is never used
+#pragma warning disable 0219
+// Missing XML comment for publicly visible type or member '...'
+#pragma warning disable 1591
+// Ambiguous reference in cref attribute
+#pragma warning disable 419
+
+using Antlr4.Runtime.Misc;
+using Antlr4.Runtime.Tree;
+using IToken = Antlr4.Runtime.IToken;
+
+///
+/// This interface defines a complete generic visitor for a parse tree produced
+/// by .
+///
+/// The return type of the visit operation.
+[System.CodeDom.Compiler.GeneratedCode("ANTLR", "4.13.2")]
+[System.CLSCompliant(false)]
+public interface ICGrammarVisitor : IParseTreeVisitor {
+ ///
+ /// Visit a parse tree produced by .
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ Result VisitProgram([NotNull] CGrammarParser.ProgramContext context);
+ ///
+ /// Visit a parse tree produced by .
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ Result VisitFunction([NotNull] CGrammarParser.FunctionContext context);
+ ///
+ /// Visit a parse tree produced by the returnStatement
+ /// labeled alternative in .
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ Result VisitReturnStatement([NotNull] CGrammarParser.ReturnStatementContext context);
+ ///
+ /// Visit a parse tree produced by the bitwiseXorExpression
+ /// labeled alternative in .
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ Result VisitBitwiseXorExpression([NotNull] CGrammarParser.BitwiseXorExpressionContext context);
+ ///
+ /// Visit a parse tree produced by the constantExpression
+ /// labeled alternative in .
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ Result VisitConstantExpression([NotNull] CGrammarParser.ConstantExpressionContext context);
+ ///
+ /// Visit a parse tree produced by the lessThanOrEqualExpression
+ /// labeled alternative in .
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ Result VisitLessThanOrEqualExpression([NotNull] CGrammarParser.LessThanOrEqualExpressionContext context);
+ ///
+ /// Visit a parse tree produced by the modulusExpression
+ /// labeled alternative in .
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ Result VisitModulusExpression([NotNull] CGrammarParser.ModulusExpressionContext context);
+ ///
+ /// Visit a parse tree produced by the notExpression
+ /// labeled alternative in .
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ Result VisitNotExpression([NotNull] CGrammarParser.NotExpressionContext context);
+ ///
+ /// Visit a parse tree produced by the notEqualExpression
+ /// labeled alternative in .
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ Result VisitNotEqualExpression([NotNull] CGrammarParser.NotEqualExpressionContext context);
+ ///
+ /// Visit a parse tree produced by the multiplyExpression
+ /// labeled alternative in .
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ Result VisitMultiplyExpression([NotNull] CGrammarParser.MultiplyExpressionContext context);
+ ///
+ /// Visit a parse tree produced by the greaterThanExpression
+ /// labeled alternative in .
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ Result VisitGreaterThanExpression([NotNull] CGrammarParser.GreaterThanExpressionContext context);
+ ///
+ /// Visit a parse tree produced by the logicalOrExpression
+ /// labeled alternative in .
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ Result VisitLogicalOrExpression([NotNull] CGrammarParser.LogicalOrExpressionContext context);
+ ///
+ /// Visit a parse tree produced by the greaterThanOrEqualExpression
+ /// labeled alternative in .
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ Result VisitGreaterThanOrEqualExpression([NotNull] CGrammarParser.GreaterThanOrEqualExpressionContext context);
+ ///
+ /// Visit a parse tree produced by the divideExpression
+ /// labeled alternative in .
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ Result VisitDivideExpression([NotNull] CGrammarParser.DivideExpressionContext context);
+ ///
+ /// Visit a parse tree produced by the bitwiseOrExpression
+ /// labeled alternative in .
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ Result VisitBitwiseOrExpression([NotNull] CGrammarParser.BitwiseOrExpressionContext context);
+ ///
+ /// Visit a parse tree produced by the parenthesizedExpression
+ /// labeled alternative in .
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ Result VisitParenthesizedExpression([NotNull] CGrammarParser.ParenthesizedExpressionContext context);
+ ///
+ /// Visit a parse tree produced by the addExpression
+ /// labeled alternative in .
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ Result VisitAddExpression([NotNull] CGrammarParser.AddExpressionContext context);
+ ///
+ /// Visit a parse tree produced by the subtractExpression
+ /// labeled alternative in .
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ Result VisitSubtractExpression([NotNull] CGrammarParser.SubtractExpressionContext context);
+ ///
+ /// Visit a parse tree produced by the bitwiseAndExpression
+ /// labeled alternative in .
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ Result VisitBitwiseAndExpression([NotNull] CGrammarParser.BitwiseAndExpressionContext context);
+ ///
+ /// Visit a parse tree produced by the lessThanExpression
+ /// labeled alternative in .
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ Result VisitLessThanExpression([NotNull] CGrammarParser.LessThanExpressionContext context);
+ ///
+ /// Visit a parse tree produced by the logicalAndExpression
+ /// labeled alternative in .
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ Result VisitLogicalAndExpression([NotNull] CGrammarParser.LogicalAndExpressionContext context);
+ ///
+ /// Visit a parse tree produced by the invertExpression
+ /// labeled alternative in .
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ Result VisitInvertExpression([NotNull] CGrammarParser.InvertExpressionContext context);
+ ///
+ /// Visit a parse tree produced by the equalExpression
+ /// labeled alternative in .
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ Result VisitEqualExpression([NotNull] CGrammarParser.EqualExpressionContext context);
+ ///
+ /// Visit a parse tree produced by the intConstant
+ /// labeled alternative in .
+ ///
+ /// The parse tree.
+ /// The visitor result.
+ Result VisitIntConstant([NotNull] CGrammarParser.IntConstantContext context);
+}
diff --git a/Content/Content.mgcb b/Content/Content.mgcb
deleted file mode 100644
index ddc4c36..0000000
--- a/Content/Content.mgcb
+++ /dev/null
@@ -1,15 +0,0 @@
-
-#----------------------------- Global Properties ----------------------------#
-
-/outputDir:bin/$(Platform)
-/intermediateDir:obj/$(Platform)
-/platform:DesktopGL
-/config:
-/profile:Reach
-/compress:False
-
-#-------------------------------- References --------------------------------#
-
-
-#---------------------------------- Content ---------------------------------#
-
diff --git a/DisplayEngine.cs b/DisplayEngine.cs
deleted file mode 100644
index 3f67bed..0000000
--- a/DisplayEngine.cs
+++ /dev/null
@@ -1,76 +0,0 @@
-using System;
-using System.Collections.Generic;
-using Q1Emu.Chip;
-using Microsoft.Xna.Framework;
-using Microsoft.Xna.Framework.Graphics;
-using Microsoft.Xna.Framework.Input;
-
-namespace Q1Emu;
-
-public class DisplayEngine : Game
-{
- private readonly Action _onScreenTextureLoaded;
- private readonly Action _requestUpdate;
- private GraphicsDeviceManager _graphics;
- private SpriteBatch _spriteBatch;
-
- private Texture2D _texture;
- public int Scaling { get; }
- public int Width { get; }
- public int Height { get; }
-
- public DisplayEngine(int width, int height, int scaling, Action 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";
- IsMouseVisible = true;
- }
-
- protected override void Initialize()
- {
- this._texture = new Texture2D(GraphicsDevice, Width, Height);
- this._onScreenTextureLoaded?.Invoke(this._texture);
- // set window size
- _graphics.PreferredBackBufferWidth = Width * Scaling;
- _graphics.PreferredBackBufferHeight = Height * Scaling;
- _graphics.ApplyChanges();
-
- base.Initialize();
- }
-
- protected override void LoadContent()
- {
- _spriteBatch = new SpriteBatch(GraphicsDevice);
- }
-
- protected override void Update(GameTime gameTime)
- {
- var state = Keyboard.GetState();
-
- if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || state.IsKeyDown(Keys.Escape))
- Exit();
-
- base.Update(gameTime);
- }
-
- protected override void Draw(GameTime gameTime)
- {
- // 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);
-
- _spriteBatch.End();
-
- base.Draw(gameTime);
- }
-}
\ No newline at end of file
diff --git a/Emulator/.DS_Store b/Emulator/.DS_Store
new file mode 100644
index 0000000..0bebabf
Binary files /dev/null and b/Emulator/.DS_Store differ
diff --git a/Emulator/Assembler/Disassembler.cs b/Emulator/Assembler/Disassembler.cs
new file mode 100644
index 0000000..d49d2eb
--- /dev/null
+++ b/Emulator/Assembler/Disassembler.cs
@@ -0,0 +1,74 @@
+namespace Q1.Emulator.Assembler;
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using Chip;
+
+public class Disassembler
+{
+ public readonly StringWriter Writer;
+ public readonly BinaryReader Reader;
+
+ public Disassembler(StringWriter writer, BinaryReader reader)
+ {
+ this.Writer = writer;
+ this.Reader = reader;
+ }
+
+ private static Dictionary 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, 0x01) => 2, // Extended implicit
+ (_, 0x00) => 1, // Simple addressing mode
+ _ => 3 // Extended addressing mode
+ };
+
+ string opcodeName = Disassembler.GetOpcodeName(op, i);
+
+ if (i == 0 || i == 2)
+ return opcodeName;
+
+ if (i == 1)
+ return $"{opcodeName} {Disassembler.GetModeName(m1)}";
+
+ if (i == 3)
+ return $"{opcodeName} {Disassembler.GetModeName(m1)}, {Disassembler.GetModeName(m2)}";
+
+ 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 (!Q1Cpu.InstructionLookupStrings.TryGetValue(opcode, out string[]? opNames))
+ return $"[{opcode:X2}]"; // Fallback for unknown opcodes
+
+ return opNames[i];
+ }
+
+ private static string GetModeName(u8 mode)
+ {
+ if (Disassembler.ModeLookup.TryGetValue(mode, out string? modeName))
+ return modeName;
+
+ return $"[{mode:X2}]"; // Fallback for unknown modes
+ }
+}
\ No newline at end of file
diff --git a/Emulator/Chip/Bus.cs b/Emulator/Chip/Bus.cs
new file mode 100644
index 0000000..0907f61
--- /dev/null
+++ b/Emulator/Chip/Bus.cs
@@ -0,0 +1,37 @@
+namespace Q1.Emulator.Chip;
+
+using System.Collections.Generic;
+using System.Linq;
+
+public class Bus : BusDevice
+{
+ public List Devices;
+
+ public Bus(u16 addressableStart, u16 addressableEnd) : base(addressableStart, addressableEnd)
+ {
+ this.Devices = [];
+ }
+ private BusDevice? GetDevice(u16 address)
+ {
+ BusDevice? device = this.Devices.FirstOrDefault(x => address >= x.AddressableStart && address < x.AddressableEnd);
+ return device;
+ }
+
+ public override u8 Read(u16 address)
+ {
+ BusDevice? device = this.GetDevice(address);
+ if (device == null)
+ return 0;
+
+ return device.Read(address);
+ }
+
+ public override void Write(u16 address, u8 value)
+ {
+ BusDevice? device = this.GetDevice(address);
+ if (device == null)
+ return;
+
+ device.Write(address, value);
+ }
+}
\ No newline at end of file
diff --git a/Emulator/Chip/BusDevice.cs b/Emulator/Chip/BusDevice.cs
new file mode 100644
index 0000000..1e1e972
--- /dev/null
+++ b/Emulator/Chip/BusDevice.cs
@@ -0,0 +1,49 @@
+namespace Q1.Emulator.Chip;
+
+using System.Runtime.CompilerServices;
+
+public abstract class BusDevice
+{
+ public BusDevice(u16 addressableStart, u16 addressableEnd)
+ {
+ this.AddressableStart = addressableStart;
+ this.AddressableEnd = addressableEnd;
+ }
+
+ public Bus Bus { get; set; }
+ public abstract u8 Read(u16 address);
+ public abstract void Write(u16 address, u8 value);
+
+ public u16 ReadWord(u16 address)
+ {
+ u8 high = this.Read(address);
+ u8 low = this.Read((u16) (address + 1));
+ u16 value = Make.u16(high, low);
+ return value;
+ }
+
+ public void WriteWord(u16 address, u16 value)
+ {
+ ref8 data = Make.ref8(value);
+ this.Write(address, data[0]);
+ this.Write((u16) (address + 1), data[1]);
+ }
+
+ public virtual void Clock() { }
+ public virtual void Reset() { }
+
+ public void AttachToBus(Bus bus)
+ {
+ this.Bus = bus;
+ bus.Devices.Add(this);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ protected u16 GetRelativeAddress(u16 address)
+ {
+ return (u16) (address - this.AddressableStart);
+ }
+
+ public u16 AddressableStart { get; }
+ public u16 AddressableEnd { get; }
+}
\ No newline at end of file
diff --git a/Emulator/Chip/DebugDevice.cs b/Emulator/Chip/DebugDevice.cs
new file mode 100644
index 0000000..4e869bb
--- /dev/null
+++ b/Emulator/Chip/DebugDevice.cs
@@ -0,0 +1,13 @@
+namespace Q1.Emulator.Chip;
+
+using System;
+
+public class DebugDevice(u16 addressPoint)
+ : BusDevice(addressPoint, (u16) (addressPoint + 2))
+{
+ public override u8 Read(u16 address) => throw new Exception("DebugDevice.Read not permitted");
+ public override void Write(u16 address, u8 value)
+ {
+ Console.WriteLine($"DebugDevice.Write: x{value:X4} b{value:b8}");
+ }
+}
\ No newline at end of file
diff --git a/Emulator/Chip/DisplayDevice.cs b/Emulator/Chip/DisplayDevice.cs
new file mode 100644
index 0000000..a18dbd4
--- /dev/null
+++ b/Emulator/Chip/DisplayDevice.cs
@@ -0,0 +1,76 @@
+namespace Q1.Emulator.Chip;
+
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+
+public class DisplayDevice : RamDevice
+{
+ public Texture2D? OutputTexture;
+ 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))
+ {
+ 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)
+ {
+ return (u16) ((paletteSize * 3) + (displayWidth * displayHeight));
+ }
+
+ public override void Clock()
+ {
+ Color[] palette = this.ReadPalette();
+ ref8 pixelData = this.Memory.AsSpan((u16) (this._paletteSize * 3), (u16) (this._displayWidth * this._displayHeight));
+ // Console.WriteLine($"DisplayDevice.Clock: @{(this.AddressableStart + this._paletteSize * 3):X4} palette size={this._paletteSize} display size={this._displayWidth}x{this._displayHeight}");
+ for (u16 i = 0; i < this.textureData.Length; i++)
+ {
+ u8 pixelValue = pixelData[i];
+ this.textureData[i] = palette[pixelValue % this._paletteSize];
+ }
+
+ if (this.OutputTexture != null)
+ this.OutputTexture.SetData(this.textureData);
+ }
+
+ private Color[] ReadPalette()
+ {
+ ref8 paletteData = this.Memory.AsSpan(0, (u16) (this._paletteSize * 3));
+ Color[] colors = new Color[this._paletteSize + 1];
+ colors[0] = Color.Transparent;
+
+ for (u16 i = 0; i < this._paletteSize; i++)
+ {
+ u16 offset = (u16) (i * 3);
+ byte r = paletteData[offset];
+ byte g = paletteData[offset + 1];
+ byte b = paletteData[offset + 2];
+ colors[(u16) (i + 1)] = new Color(r, g, b);
+ }
+
+ return colors;
+ }
+
+ public void SetPalette(Color[] palette)
+ {
+ if (palette.Length != this._paletteSize)
+ throw new ArgumentException($"Palette must have {this._paletteSize} colors.");
+
+ ref8 paletteData = this.Memory.AsSpan(0, (u16) (this._paletteSize * 3));
+ for (u16 i = 0; i < this._paletteSize; i++)
+ {
+ u16 offset = (u16) (i * 3);
+ paletteData[offset] = palette[i].R;
+ paletteData[offset + 1] = palette[i].G;
+ paletteData[offset + 2] = palette[i].B;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Emulator/Chip/Q1Cpu.cs b/Emulator/Chip/Q1Cpu.cs
new file mode 100644
index 0000000..16e1e14
--- /dev/null
+++ b/Emulator/Chip/Q1Cpu.cs
@@ -0,0 +1,171 @@
+namespace Q1.Emulator.Chip;
+
+using System;
+using Assembler;
+
+public partial class Q1Cpu
+{
+ public const u16 StackStart = 0x2FFF;
+ public const u16 StackLength = 16 * 2; // 16 16-bit values
+
+ public Random Random;
+
+ public u16 AX = 0; // Accumulator register
+ public u16 DX = 0; // Data register
+ public u16 LX = 0; // Logical register
+
+ public u16 SP { get; set; } // Stack pointer
+ public u16 PC { get; set; } // Program counter
+
+ public u16[] V { get; set; } // Variable registers (64 total)
+ public u16 I { get; set; } // Index register
+ public u16 Cycles { get; set; } // Number of cycles
+
+ public Bus Bus { get; set; }
+ public bool AbortRequested = false;
+
+ public Q1Cpu()
+ {
+ this.LoadInstructionLookup();
+ }
+
+ public void Reset()
+ {
+ this.AbortRequested = false;
+
+ this.V = new u16[16];
+
+ this.SP = Q1Cpu.StackStart;
+ this.PushStack(0xFFFF);
+
+ this.I = 0;
+ }
+
+ public void Clock()
+ {
+ var pc = this.PC;
+ if (pc == 0xFFFF)
+ {
+ this.AbortRequested = true;
+ return;
+ }
+
+ u16 instruction = this.FetchInstruction(out u8 op, out u8 m1, out u8 m2, out _);
+ if (instruction != 0x0101)
+ Console.WriteLine($"CPU.Clock: {pc:X4} | {Disassembler.ParseInstruction(instruction)}");
+
+ bool ex = m2 > 0;
+ switch (m1, ex)
+ {
+ case (0x00, false):
+ this.InstructionLookup[op].Item1(); // Implicit
+ break;
+ case (> 0x00, false):
+ this.InstructionLookup[op].Item2(m1); // Simple addressing mode
+ break;
+ case (0x00, true):
+ this.InstructionLookup[op].Item3(); // Extended implicit
+ break;
+ case (> 0x00, true):
+ this.InstructionLookup[op].Item4(m1, m2); // Extended addressing mode
+ break;
+ }
+
+ this.Cycles++;
+ }
+ public u16 FetchInstruction(out u8 op, out u8 m1, out u8 m2, out u8 length)
+ {
+ u16 instruction = this.Bus.ReadWord(this.PC);
+ this.PC += 2;
+
+ op = (u8) ((instruction >> 8) & 0xFF); // 256 opcodes
+ m1 = (u8) ((instruction >> 4) & 0x0F); // 16 modes
+ m2 = (u8) (instruction & 0x0F); // 16 modes
+
+ length = (u8) (this.AddressingModeLength(m1) + this.AddressingModeLength(m2));
+ return instruction;
+ }
+
+ private void PushStack(u16 value)
+ {
+ if (this.SP + 2 >= Q1Cpu.StackStart + Q1Cpu.StackLength)
+ throw new InvalidOperationException("Stack overflow");
+
+ this.Bus.WriteWord(this.SP, value);
+ this.SP += 2;
+ }
+
+ private u16 PopStack()
+ {
+ if (this.SP - 2 < Q1Cpu.StackStart)
+ throw new InvalidOperationException("Stack underflow");
+
+ this.SP -= 2;
+ return this.Bus.ReadWord(this.SP);
+ }
+
+ private u16 FetchRegister(u8 regIndex)
+ {
+ return regIndex switch
+ {
+ <= 0x3F => this.V[regIndex],
+
+ 0x40 => this.AX,
+ 0x41 => (u16) (this.AX >> 8), // High byte of AX
+ 0x42 => (u16) (this.AX & 0xFF), // Low byte of AX
+
+ 0x43 => this.DX,
+ 0x44 => (u16) (this.DX >> 8), // High byte of DX
+ 0x45 => (u16) (this.DX & 0xFF), // Low byte of DX
+
+ 0x46 => this.LX,
+ 0x50 => this.PC,
+ 0x51 => this.SP,
+
+ _ => throw new InvalidOperationException($"Unknown register index: {regIndex:X2}"),
+ };
+ }
+
+ private void StoreRegister(u8 regIndex, u16 value)
+ {
+ switch (regIndex)
+ {
+ case <= 0x3F:
+ this.V[regIndex] = value;
+ break;
+
+ case 0x40:
+ this.AX = value;
+ break;
+ case 0x41:
+ this.AX = (u16) ((this.AX & 0x00FF) | (value << 8));
+ break; // Set high byte
+ case 0x42:
+ this.AX = (u16) ((this.AX & 0xFF00) | (value & 0x00FF));
+ break; // Set low byte
+
+ case 0x43:
+ this.DX = value;
+ break;
+ case 0x44:
+ this.DX = (u16) ((this.DX & 0x00FF) | (value << 8));
+ break; // Set high byte
+ case 0x45:
+ this.DX = (u16) ((this.DX & 0xFF00) | (value & 0x00FF));
+ break; // Set low byte
+
+ case 0x46:
+ this.LX = value;
+ break;
+ case 0x50:
+ this.PC = value;
+ break;
+ case 0x51:
+ this.SP = value;
+ break;
+
+ default:
+ throw new InvalidOperationException($"Unknown register index: {regIndex:X2}");
+ }
+ }
+}
\ No newline at end of file
diff --git a/Emulator/Chip/Q1CpuAddressingModes.cs b/Emulator/Chip/Q1CpuAddressingModes.cs
new file mode 100644
index 0000000..40020f1
--- /dev/null
+++ b/Emulator/Chip/Q1CpuAddressingModes.cs
@@ -0,0 +1,187 @@
+namespace Q1.Emulator.Chip;
+
+using System;
+
+public partial class Q1Cpu
+{
+ public (Func read, Action write, Action writeByte) Address(u8 mode)
+ {
+ return mode switch
+ {
+ 0x0 => this.AddressingMode_Implicit(),
+ 0x1 => this.AddressingMode_Immediate(),
+ 0x2 => this.AddressingMode_Direct(),
+ 0x3 => this.AddressingMode_Indirect(),
+ 0x4 => this.AddressingMode_Relative(),
+ 0x5 => this.AddressingMode_Register(),
+ 0x6 => this.AddressingMode_RegisterIndirect(),
+ 0x7 => this.AddressingMode_RegisterIndirectOffset(),
+ _ => throw new InvalidOperationException($"Unknown addressing mode: {mode:X2}"),
+ };
+ }
+
+ private u8 AddressingModeLength(u8 mode)
+ {
+ return mode switch
+ {
+ 0x0 => 0, // Implicit
+ 0x1 => 2, // Immediate
+ 0x2 => 2, // Direct
+ 0x3 => 2, // Indirect
+ 0x4 => 2, // Relative
+ 0x5 => 1, // Register
+ 0x6 => 1, // Register indirect
+ 0x7 => 3, // Register indirect with offset
+ _ => throw new InvalidOperationException($"Unknown addressing mode: {mode:X2}"),
+ };
+ }
+
+ public (Func read, Action write, Action writeByte) AddressingMode_Implicit()
+ {
+ u16 Read() => throw new InvalidOperationException("Cannot read from implicit mode.");
+ void Write(u16 value) => throw new InvalidOperationException("Cannot write to implicit mode.");
+ void WriteByte(u8 value) => throw new InvalidOperationException("Cannot write byte to implicit mode.");
+
+ return (Read, Write, WriteByte);
+ }
+
+
+ public (Func read, Action write, Action writeByte) AddressingMode_Immediate()
+ {
+ u16 value = this.Bus.ReadWord(this.PC);
+ this.PC += 2;
+
+ u16 Read() => value;
+ void Write(u16 v) => throw new InvalidOperationException("Cannot write to immediate mode.");
+ void WriteByte(u8 v) => throw new InvalidOperationException("Cannot write byte to immediate mode.");
+
+ return (Read, Write, WriteByte);
+ }
+
+ public (Func read, Action write, Action writeByte) AddressingMode_Direct()
+ {
+ u16 address = this.Bus.ReadWord(this.PC);
+ this.PC += 2;
+
+ u16 Read() => this.Bus.ReadWord(address);
+ void Write(u16 value) => this.Bus.WriteWord(address, value);
+ void WriteByte(u8 value) => this.Bus.Write(address, value);
+
+ return (Read, Write, WriteByte);
+ }
+
+ public (Func read, Action write, Action writeByte) AddressingMode_Indirect()
+ {
+ u16 address = this.Bus.ReadWord(this.PC);
+ this.PC += 2;
+
+ u16 Read()
+ {
+ u16 indirectAddress = this.Bus.ReadWord(address);
+ u16 value = this.Bus.ReadWord(indirectAddress);
+ return value;
+ }
+
+ void Write(u16 value)
+ {
+ u16 indirectAddress = this.Bus.ReadWord(address);
+ this.Bus.WriteWord(indirectAddress, value);
+ }
+
+ void WriteByte(u8 value)
+ {
+ u16 indirectAddress = this.Bus.ReadWord(address);
+ this.Bus.Write(indirectAddress, value);
+ }
+
+ return (Read, Write, WriteByte);
+ }
+
+ public (Func read, Action write, Action writeByte) AddressingMode_Relative()
+ {
+ u16 offset = this.Bus.ReadWord(this.PC);
+ this.PC += 2;
+
+ u16 address = (u16) (this.PC + offset);
+
+ u16 Read() => address;
+ void Write(u16 value) => throw new InvalidOperationException("Cannot write to relative mode.");
+ void WriteByte(u8 value) => throw new InvalidOperationException("Cannot write byte to relative mode.");
+
+ return (Read, Write, WriteByte);
+ }
+
+ public (Func read, Action write, Action writeByte) AddressingMode_Register()
+ {
+ u8 regIndex = this.Bus.Read(this.PC);
+ this.PC += 1;
+
+ u16 Read() => this.FetchRegister(regIndex);
+ void Write(u16 value) => this.StoreRegister(regIndex, value);
+ void WriteByte(u8 value)
+ {
+ u16 currentValue = this.FetchRegister(regIndex);
+ u16 newValue = (u16) ((currentValue & 0xFF00) | (value & 0x00FF)); // Update low byte
+ this.StoreRegister(regIndex, newValue);
+ }
+
+ return (Read, Write, WriteByte);
+ }
+
+ public (Func read, Action write, Action writeByte) AddressingMode_RegisterIndirect()
+ {
+ u8 regIndex = this.Bus.Read(this.PC);
+ this.PC += 1;
+
+ u16 Read()
+ {
+ u16 address = this.FetchRegister(regIndex);
+ u16 value = this.Bus.ReadWord(address);
+ return value;
+ }
+
+ void Write(u16 value)
+ {
+ u16 address = this.FetchRegister(regIndex);
+ this.Bus.WriteWord(address, value);
+ }
+
+ void WriteByte(u8 value)
+ {
+ u16 address = this.FetchRegister(regIndex);
+ this.Bus.Write(address, value);
+ }
+
+ return (Read, Write, WriteByte);
+ }
+
+ public (Func read, Action write, Action writeByte) AddressingMode_RegisterIndirectOffset()
+ {
+ u8 regIndex = this.Bus.Read(this.PC);
+ this.PC += 1;
+
+ u16 offset = this.Bus.ReadWord(this.PC);
+ this.PC += 2;
+
+ u16 Read()
+ {
+ u16 address = (u16) (this.FetchRegister(regIndex) + offset);
+ u16 value = this.Bus.ReadWord(address);
+ return value;
+ }
+
+ void Write(u16 value)
+ {
+ u16 address = (u16) (this.FetchRegister(regIndex) + offset);
+ this.Bus.WriteWord(address, value);
+ }
+
+ void WriteByte(u8 value)
+ {
+ u16 address = (u16) (this.FetchRegister(regIndex) + offset);
+ this.Bus.Write(address, value);
+ }
+
+ return (Read, Write, WriteByte);
+ }
+}
\ No newline at end of file
diff --git a/Emulator/Chip/Q1CpuInstructions.cs b/Emulator/Chip/Q1CpuInstructions.cs
new file mode 100644
index 0000000..2da8969
--- /dev/null
+++ b/Emulator/Chip/Q1CpuInstructions.cs
@@ -0,0 +1,282 @@
+namespace Q1.Emulator.Chip;
+
+using System;
+using System.Collections.Generic;
+
+public partial class Q1Cpu
+{
+ public static Dictionary InstructionLookupStrings = new()
+ {
+ { 0x00, ["NOP", "JMP", "HALT", "MOV"] },
+ { 0x01, ["RET", "CALL", "SUS", "MOVB"] },
+ { 0x02, ["BZ", "BZ", "BR", "NOP"] },
+ { 0x03, ["NOP", "PUSH", "NOP", "NOP"] },
+ { 0x04, ["NOP", "POP", "NOP", "NOP"] },
+
+ { 0x10, ["INV", "INV", "NOP", "AND"] },
+ { 0x11, ["SHL", "SHL", "NOP", "OR"] },
+ { 0x12, ["SHR", "SHR", "NOP", "XOR"] },
+
+ { 0x20, ["NOT", "NOT", "NOP", "CMP"] },
+ { 0x21, ["NOP", "NOP", "NOP", "LT"] },
+ { 0x22, ["NOP", "NOP", "NOP", "GT"] },
+
+ { 0x30, ["INC_AX", "INC", "NOP", "ADD"] },
+ { 0x31, ["DEC_AX", "DEC", "NOP", "SUB"] },
+ { 0x32, ["NOP", "NOP", "NOP", "DIV"] },
+ { 0x33, ["NOP", "NOP", "NOP", "MUL"] },
+ { 0x34, ["NOP", "NOP", "NOP", "MOD"] },
+ };
+
+ public Dictionary, Action, Action)> InstructionLookup;
+ private void LoadInstructionLookup()
+ {
+ this.InstructionLookup = new Dictionary, Action, Action)>
+ {
+ { 0x00, (this.Instruction_NOP, this.Instruction_JMP, this.Instruction_HALT, this.Instruction_MOV) },
+ { 0x01, (this.Instruction_RET, this.Instruction_CALL, this.Instruction_SUS, this.Instruction_MOVB) },
+ { 0x02, (this.Instruction_BZ_LX, this.Instruction_BZ, this.Instruction_BR, this.Instruction_NOP) },
+ { 0x03, (this.Instruction_NOP, this.Instruction_PUSH, this.Instruction_NOP, this.Instruction_NOP) },
+ { 0x04, (this.Instruction_NOP, this.Instruction_POP, this.Instruction_NOP, this.Instruction_NOP) },
+
+ { 0x10, (this.Instruction_INV_DX, this.Instruction_INV, this.Instruction_NOP, this.Instruction_AND) },
+ { 0x11, (this.Instruction_SHL_DX, this.Instruction_SHL, this.Instruction_NOP, this.Instruction_OR) },
+ { 0x12, (this.Instruction_SHR_DX, this.Instruction_SHR, this.Instruction_NOP, this.Instruction_XOR) },
+
+ { 0x20, (this.Instruction_NOT_LX, this.Instruction_NOT, this.Instruction_NOP, this.Instruction_CMP) },
+ { 0x21, (this.Instruction_NOP, this.Instruction_NOP, this.Instruction_NOP, this.Instruction_LT) },
+ { 0x22, (this.Instruction_NOP, this.Instruction_NOP, this.Instruction_NOP, this.Instruction_GT) },
+
+ { 0x30, (this.Instruction_INC_AX, this.Instruction_INC, this.Instruction_NOP, this.Instruction_ADD) },
+ { 0x31, (this.Instruction_DEC_AX, this.Instruction_DEC, this.Instruction_NOP, this.Instruction_SUB) },
+ { 0x32, (this.Instruction_NOP, this.Instruction_NOP, this.Instruction_NOP, this.Instruction_DIV) },
+ { 0x33, (this.Instruction_NOP, this.Instruction_NOP, this.Instruction_NOP, this.Instruction_MUL) },
+ { 0x34, (this.Instruction_NOP, this.Instruction_NOP, this.Instruction_NOP, this.Instruction_MOD) },
+ };
+ }
+ private void Instruction_ADD(u8 m1, u8 m2)
+ {
+ u16 v1 = this.Address(m1).read();
+ u16 v2 = this.Address(m2).read();
+
+ u16 result = (u16) (v1 + v2);
+ this.AX = result;
+ }
+ private void Instruction_SUB(u8 m1, u8 m2)
+ {
+ u16 v1 = this.Address(m1).read();
+ u16 v2 = this.Address(m2).read();
+
+ u16 result = (u16) (v1 - v2);
+ this.AX = result;
+ }
+ private void Instruction_MUL(u8 m1, u8 m2)
+ {
+ u16 v1 = this.Address(m1).read();
+ u16 v2 = this.Address(m2).read();
+
+ u16 result = (u16) (v1 * v2);
+ this.AX = result;
+ }
+ private void Instruction_DIV(u8 m1, u8 m2)
+ {
+ u16 v1 = this.Address(m1).read();
+ u16 v2 = this.Address(m2).read();
+
+ if (v2 == 0)
+ throw new DivideByZeroException("Cannot perform division by zero.");
+ u16 result = (u16) (v1 / v2);
+ this.AX = result;
+ }
+ private void Instruction_MOD(u8 m1, u8 m2)
+ {
+ u16 v1 = this.Address(m1).read();
+ u16 v2 = this.Address(m2).read();
+
+ if (v2 == 0)
+ throw new DivideByZeroException("Cannot perform modulo operation with divisor zero.");
+ u16 result = (u16) (v1 % v2);
+ this.AX = result;
+ }
+ private void Instruction_INC(u8 obj)
+ {
+ var address = this.Address(obj);
+ u16 value = address.read();
+ address.write((u16) (value + 1));
+ }
+ private void Instruction_DEC(u8 obj)
+ {
+ var address = this.Address(obj);
+ u16 value = address.read();
+ address.write((u16) (value - 1));
+ }
+ private void Instruction_INC_AX()
+ {
+ this.AX = (u16) (this.AX + 1);
+ }
+ private void Instruction_DEC_AX()
+ {
+ this.AX = (u16) (this.AX - 1);
+ }
+ private void Instruction_SHL(u8 obj)
+ {
+ var address = this.Address(obj);
+ u16 value = address.read();
+ u16 result = (u16) (value << 1);
+ address.write(result);
+ }
+ private void Instruction_SHR(u8 obj)
+ {
+ var address = this.Address(obj);
+ u16 value = address.read();
+ u16 result = (u16) (value >> 1);
+ address.write(result);
+ }
+ private void Instruction_SHL_DX()
+ {
+ this.DX = (u16) (this.DX << 1);
+ }
+ private void Instruction_SHR_DX()
+ {
+ this.DX = (u16) (this.DX >> 1);
+ }
+ private void Instruction_XOR(u8 m1, u8 m2)
+ {
+ u16 v1 = this.Address(m1).read();
+ u16 v2 = this.Address(m2).read();
+
+ u16 result = (u16) (v1 ^ v2);
+ this.DX = result;
+ }
+ private void Instruction_OR(u8 m1, u8 m2)
+ {
+ u16 v1 = this.Address(m1).read();
+ u16 v2 = this.Address(m2).read();
+
+ u16 result = (u16) (v1 | v2);
+ this.DX = result;
+ }
+ private void Instruction_INV(u8 obj)
+ {
+ var address = this.Address(obj);
+ u16 value = address.read();
+ u16 result = (u16) ~value;
+ this.DX = result;
+ }
+ private void Instruction_INV_DX()
+ {
+ this.DX = (u16) ~this.DX;
+ }
+ private void Instruction_AND(u8 m1, u8 m2)
+ {
+ u16 v1 = this.Address(m1).read();
+ u16 v2 = this.Address(m2).read();
+
+ u16 result = (u16) (v1 & v2);
+ this.DX = result;
+ }
+ private void Instruction_NOT(u8 obj)
+ {
+ u16 value = this.Address(obj).read();
+ u16 result = value == 0 ? (u16) 1 : (u16) 0;
+ this.LX = result;
+ }
+ private void Instruction_NOT_LX()
+ {
+ this.LX = this.LX == 0 ? (u16) 1 : (u16) 0;
+ }
+ private void Instruction_GT(u8 m1, u8 m2)
+ {
+ u16 v1 = this.Address(m1).read();
+ u16 v2 = this.Address(m2).read();
+
+ this.LX = (u16) (v1 > v2 ? 1 : 0);
+ }
+ private void Instruction_LT(u8 m1, u8 m2)
+ {
+ u16 v1 = this.Address(m1).read();
+ u16 v2 = this.Address(m2).read();
+
+ this.LX = (u16) (v1 < v2 ? 1 : 0);
+ }
+
+ private void Instruction_BR()
+ {
+ this.FetchInstruction(out _, out _, out _, out u8 length);
+ this.PC += length;
+ }
+ private void Instruction_BZ_LX()
+ {
+ if (this.LX == 0)
+ this.Instruction_BR();
+ }
+ private void Instruction_BZ(u8 obj)
+ {
+ u16 value = this.Address(obj).read();
+ if (value == 0)
+ this.Instruction_BR();
+ }
+ private void Instruction_CMP(u8 m1, u8 m2)
+ {
+ u16 v1 = this.Address(m1).read();
+ u16 v2 = this.Address(m2).read();
+
+ // Set LX based on comparison
+ this.LX = (u16) (v1 == v2 ? 1 : 0);
+ }
+ private void Instruction_MOV(u8 m1, u8 m2)
+ {
+ u16 value = this.Address(m1).read();
+ this.Address(m2).write(value);
+ }
+
+ private void Instruction_MOVB(u8 m1, u8 m2)
+ {
+ u16 value = this.Address(m1).read();
+ u8 low = Make.ref8(value)[1];
+ this.Address(m2).writeByte(low);
+ }
+
+ public void Instruction_NOP() { }
+ public void Instruction_NOP(u8 m1) { }
+ public void Instruction_NOP(u8 m1, u8 m2) { }
+
+ public void Instruction_JMP(u8 m1)
+ {
+ this.PC = this.Address(m1).read();
+ }
+
+ public void Instruction_RET()
+ {
+ this.PC = this.PopStack();
+ }
+
+ public void Instruction_CALL(u8 m1)
+ {
+ u16 address = this.Address(m1).read();
+ this.PushStack(this.PC);
+ this.PC = address;
+ }
+
+ public void Instruction_HALT()
+ {
+ this.AbortRequested = true;
+ }
+
+ public void Instruction_SUS()
+ {
+ this.PC -= 2;
+ }
+
+ public void Instruction_PUSH(u8 m1)
+ {
+ u16 value = this.Address(m1).read();
+ this.PushStack(value);
+ }
+
+ public void Instruction_POP(u8 m1)
+ {
+ u16 value = this.PopStack();
+ this.Address(m1).write(value);
+ }
+}
\ No newline at end of file
diff --git a/Emulator/Chip/RamDevice.cs b/Emulator/Chip/RamDevice.cs
new file mode 100644
index 0000000..8d5b051
--- /dev/null
+++ b/Emulator/Chip/RamDevice.cs
@@ -0,0 +1,33 @@
+namespace Q1.Emulator.Chip;
+
+public class RamDevice : BusDevice
+{
+ public u8[] Memory;
+
+ public RamDevice(u16 start, u16 size) : base(start, (u16) (start + size))
+ {
+ this.Memory = new u8[size];
+ }
+
+ public override void Reset()
+ {
+ this.Memory = new u8[this.AddressableEnd - this.AddressableStart];
+ }
+
+ public override void Clock()
+ {
+ // No clocking needed for RAM
+ }
+
+ public override u8 Read(u16 address)
+ {
+ u16 relativeAddress = this.GetRelativeAddress(address);
+ return this.Memory[relativeAddress];
+ }
+
+ public override void Write(u16 address, u8 value)
+ {
+ u16 relativeAddress = this.GetRelativeAddress(address);
+ this.Memory[relativeAddress] = value;
+ }
+}
\ No newline at end of file
diff --git a/Emulator/Content/Content.mgcb b/Emulator/Content/Content.mgcb
new file mode 100644
index 0000000..ddc4c36
--- /dev/null
+++ b/Emulator/Content/Content.mgcb
@@ -0,0 +1,15 @@
+
+#----------------------------- Global Properties ----------------------------#
+
+/outputDir:bin/$(Platform)
+/intermediateDir:obj/$(Platform)
+/platform:DesktopGL
+/config:
+/profile:Reach
+/compress:False
+
+#-------------------------------- References --------------------------------#
+
+
+#---------------------------------- Content ---------------------------------#
+
diff --git a/Emulator/DisplayEngine.cs b/Emulator/DisplayEngine.cs
new file mode 100644
index 0000000..beb2bba
--- /dev/null
+++ b/Emulator/DisplayEngine.cs
@@ -0,0 +1,76 @@
+namespace Q1.Emulator;
+
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Input;
+
+public class DisplayEngine : Game
+{
+ private readonly Action _onScreenTextureLoaded;
+ private readonly Action _requestUpdate;
+ private readonly Func _checkAbort;
+ private GraphicsDeviceManager _graphics;
+ private SpriteBatch _spriteBatch;
+
+ private Texture2D _texture;
+ public int Scaling { get; }
+ public int Width { get; }
+ public int Height { get; }
+
+ public DisplayEngine(int width, int height, int scaling, Action onScreenTextureLoaded, Action requestUpdate, Func checkAbort)
+ {
+ this.Width = width;
+ this.Height = height;
+ this.Scaling = scaling;
+ this._onScreenTextureLoaded = onScreenTextureLoaded;
+ this._requestUpdate = requestUpdate;
+ this._checkAbort = checkAbort;
+
+ this._graphics = new GraphicsDeviceManager(this);
+ this.Content.RootDirectory = "Content";
+ this.IsMouseVisible = true;
+ }
+
+ protected override void Initialize()
+ {
+ this._texture = new Texture2D(this.GraphicsDevice, this.Width, this.Height);
+ this._onScreenTextureLoaded?.Invoke(this._texture);
+ // set window size
+ this._graphics.PreferredBackBufferWidth = this.Width * this.Scaling;
+ this._graphics.PreferredBackBufferHeight = this.Height * this.Scaling;
+ this._graphics.ApplyChanges();
+
+ base.Initialize();
+ }
+
+ protected override void LoadContent()
+ {
+ this._spriteBatch = new SpriteBatch(this.GraphicsDevice);
+ }
+
+ protected override void Update(GameTime gameTime)
+ {
+ var state = Keyboard.GetState();
+
+ if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || state.IsKeyDown(Keys.Escape) || this._checkAbort())
+ this.Exit();
+
+ base.Update(gameTime);
+ }
+
+ protected override void Draw(GameTime gameTime)
+ {
+ // GraphicsDevice.Clear(Color.CornflowerBlue);
+
+ this._requestUpdate();
+
+ this._spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, SamplerState.PointClamp, DepthStencilState.None, RasterizerState.CullNone);
+ // Draw the texture to the screen
+ this._spriteBatch.Draw(this._texture, new Rectangle(0, 0, this.Width * this.Scaling, this.Height * this.Scaling), Color.White);
+
+ this._spriteBatch.End();
+
+ base.Draw(gameTime);
+ }
+}
\ No newline at end of file
diff --git a/Emulator/Emulator.csproj b/Emulator/Emulator.csproj
new file mode 100644
index 0000000..8cb327c
--- /dev/null
+++ b/Emulator/Emulator.csproj
@@ -0,0 +1,32 @@
+
+
+ WinExe
+ net8.0
+ Major
+ false
+ false
+ Q1.Emulator
+ enable
+
+
+
+
+
+
+
+ Icon.ico
+
+
+ Icon.bmp
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Emulator/Extensions.cs b/Emulator/Extensions.cs
new file mode 100644
index 0000000..3cc980d
--- /dev/null
+++ b/Emulator/Extensions.cs
@@ -0,0 +1,23 @@
+namespace Q1.Emulator;
+
+using System.Collections.Generic;
+
+public static class Extensions
+{
+ public static IEnumerable AllIndexesOf(this IEnumerable arr, T q)
+ {
+ var indexes = new List();
+ int index = 0;
+
+ foreach (var item in arr)
+ {
+ if (EqualityComparer.Default.Equals(item, q))
+ {
+ indexes.Add(index);
+ }
+ index++;
+ }
+
+ return indexes;
+ }
+}
\ No newline at end of file
diff --git a/Emulator/GlobalUsings.cs b/Emulator/GlobalUsings.cs
new file mode 100644
index 0000000..ff38a75
--- /dev/null
+++ b/Emulator/GlobalUsings.cs
@@ -0,0 +1,12 @@
+// Integer type aliases
+global using i8 = sbyte; // -128 to 127
+global using u8 = byte; // 0 to 255
+global using i16 = short; // -32,768 to 32,767
+global using u16 = ushort; // 0 to 65,535
+global using i32 = int; // -2,147,483,648 to 2,147,483,647
+global using u32 = uint; // 0 to 4,294,967,295
+global using i64 = long; // -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
+global using u64 = ulong; // 0 to 18,446,744,073,709,551,615
+
+global using ref8 = System.Span;
+global using data8 = byte[];
diff --git a/Emulator/Icon.bmp b/Emulator/Icon.bmp
new file mode 100644
index 0000000..2b48165
Binary files /dev/null and b/Emulator/Icon.bmp differ
diff --git a/Emulator/Icon.ico b/Emulator/Icon.ico
new file mode 100644
index 0000000..7d9dec1
Binary files /dev/null and b/Emulator/Icon.ico differ
diff --git a/Emulator/Make.cs b/Emulator/Make.cs
new file mode 100644
index 0000000..aad9644
--- /dev/null
+++ b/Emulator/Make.cs
@@ -0,0 +1,58 @@
+namespace Q1.Emulator;
+
+using System;
+using System.Buffers.Binary;
+
+public static class Make
+{
+ public static u16 u16(u8 high, u8 low)
+ {
+ return (u16) ((high << 8) | low);
+ }
+
+ public static u16 u16(ref8 data)
+ {
+ if (data.Length < 2)
+ throw new ArgumentException("Data must contain at least 2 bytes to form a u16.");
+
+ return Make.u16(data[0], data[1]);
+ }
+
+ public static u32 u32(u8 b1, u8 b2, u8 b3, u8 b4)
+ {
+ return (u32) ((b1 << 24) | (b2 << 16) | (b3 << 8) | b4);
+ }
+
+ public static u32 u32(ref8 data)
+ {
+ if (data.Length < 4)
+ throw new ArgumentException("Data must contain at least 4 bytes to form a u32.");
+
+ return Make.u32(data[0], data[1], data[2], data[3]);
+ }
+
+ public static ref8 ref8(u16 value)
+ {
+ u8 high = (u8) (value >> 8);
+ u8 low = (u8) (value & 0xFF);
+ return new ref8([high, low], 0, 2);
+ }
+
+ public static ref8 ref8(u32 value)
+ {
+ u8 b1 = (u8) (value >> 24);
+ u8 b2 = (u8) (value >> 16);
+ u8 b3 = (u8) (value >> 8);
+ u8 b4 = (u8) (value & 0xFF);
+ return new ref8([b1, b2, b3, b4], 0, 4);
+ }
+ public static i16 i16(ref8 value)
+ {
+ return BinaryPrimitives.ReadInt16BigEndian(value);
+ }
+
+ public static i16 i16(u8 high, u8 low)
+ {
+ return BinaryPrimitives.ReadInt16BigEndian(new ReadOnlySpan([high, low]));
+ }
+}
\ No newline at end of file
diff --git a/Emulator/Options.cs b/Emulator/Options.cs
new file mode 100644
index 0000000..a42b560
--- /dev/null
+++ b/Emulator/Options.cs
@@ -0,0 +1,7 @@
+namespace Q1.Emulator;
+
+public class Options
+{
+ [CommandLine.Option('i', "input", Required = true, HelpText = "Input file to run.")]
+ public string InputFile { get; set; }
+}
\ No newline at end of file
diff --git a/Emulator/Program.cs b/Emulator/Program.cs
new file mode 100644
index 0000000..cd6a8c0
--- /dev/null
+++ b/Emulator/Program.cs
@@ -0,0 +1,82 @@
+namespace Q1.Emulator;
+
+using System;
+using System.IO;
+using System.Threading;
+using Chip;
+using CommandLine;
+using Microsoft.Xna.Framework;
+
+internal class Program
+{
+ public static void Main(string[] args)
+ {
+ Parser.Default.ParseArguments(args).WithParsed(Program.Main);
+ }
+
+ static void Main(Options options)
+ {
+ Q1Cpu cpu = new();
+ Bus bus = new(u16.MinValue, u16.MaxValue);
+ RamDevice ram = new(0x1FFF, 1024 * 8);
+ File.ReadAllBytes(options.InputFile).CopyTo(ram.Memory, 0);
+
+ cpu.PC = ram.AddressableStart;
+
+ DisplayDevice display = new(16, 64, 32, 0x3FFF);
+ display.SetPalette([
+ Color.Red,
+ Color.Green,
+ Color.Blue,
+ Color.Yellow,
+ Color.Cyan,
+ Color.Magenta,
+ Color.White,
+ Color.Black,
+ Color.Gray,
+ Color.Orange,
+ Color.Purple,
+ Color.Brown,
+ Color.LightGray,
+ Color.DarkGray,
+ Color.LightBlue,
+ Color.LightGreen
+ ]);
+
+ DebugDevice debug = new(0xEFFF);
+
+ cpu.Bus = bus;
+ ram.AttachToBus(bus);
+ display.AttachToBus(bus);
+ debug.AttachToBus(bus);
+
+ Thread t = new(() =>
+ {
+ cpu.Reset();
+ while (!cpu.AbortRequested)
+ {
+ for (int i = 0; i < 64; i++)
+ cpu.Clock();
+
+ Thread.Sleep(1);
+ //
+ // cpu.Clock();
+ // Thread.Sleep(1000);
+ }
+ Console.WriteLine($"Exit code: 0x{cpu.V[0]:X4}");
+ });
+ t.IsBackground = true;
+ t.Start();
+
+ using DisplayEngine game = new(64, 32, 10,
+ tex =>
+ {
+ display.OutputTexture = tex;
+ Console.WriteLine("Display surface initialized.");
+ }, () => display.Clock(), () => cpu.AbortRequested);
+ game.Run();
+
+ Console.WriteLine("Display surface closed. Waiting for CPU thread to finish...");
+ t.Join();
+ }
+}
\ No newline at end of file
diff --git a/Extensions.cs b/Extensions.cs
deleted file mode 100644
index 6303c8c..0000000
--- a/Extensions.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-namespace Q1Emu;
-
-using System.Collections.Generic;
-
-public static class Extensions
-{
- public static IEnumerable AllIndexesOf(this IEnumerable arr, T q)
- {
- var indexes = new List();
- int index = 0;
-
- foreach (var item in arr)
- {
- if (EqualityComparer.Default.Equals(item, q))
- {
- indexes.Add(index);
- }
- index++;
- }
-
- return indexes;
- }
-}
\ No newline at end of file
diff --git a/GlobalUsings.cs b/GlobalUsings.cs
deleted file mode 100644
index ff38a75..0000000
--- a/GlobalUsings.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-// Integer type aliases
-global using i8 = sbyte; // -128 to 127
-global using u8 = byte; // 0 to 255
-global using i16 = short; // -32,768 to 32,767
-global using u16 = ushort; // 0 to 65,535
-global using i32 = int; // -2,147,483,648 to 2,147,483,647
-global using u32 = uint; // 0 to 4,294,967,295
-global using i64 = long; // -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
-global using u64 = ulong; // 0 to 18,446,744,073,709,551,615
-
-global using ref8 = System.Span;
-global using data8 = byte[];
diff --git a/Icon.bmp b/Icon.bmp
deleted file mode 100644
index 2b48165..0000000
Binary files a/Icon.bmp and /dev/null differ
diff --git a/Icon.ico b/Icon.ico
deleted file mode 100644
index 7d9dec1..0000000
Binary files a/Icon.ico and /dev/null differ
diff --git a/Make.cs b/Make.cs
deleted file mode 100644
index 24f3ac2..0000000
--- a/Make.cs
+++ /dev/null
@@ -1,58 +0,0 @@
-namespace Q1Emu;
-
-using System;
-using System.Buffers.Binary;
-
-public static class Make
-{
- public static u16 u16(u8 high, u8 low)
- {
- return (u16) ((high << 8) | low);
- }
-
- public static u16 u16(ref8 data)
- {
- if (data.Length < 2)
- throw new ArgumentException("Data must contain at least 2 bytes to form a u16.");
-
- return u16(data[0], data[1]);
- }
-
- public static u32 u32(u8 b1, u8 b2, u8 b3, u8 b4)
- {
- return (u32) ((b1 << 24) | (b2 << 16) | (b3 << 8) | b4);
- }
-
- public static u32 u32(ref8 data)
- {
- if (data.Length < 4)
- throw new ArgumentException("Data must contain at least 4 bytes to form a u32.");
-
- return u32(data[0], data[1], data[2], data[3]);
- }
-
- public static ref8 ref8(u16 value)
- {
- u8 high = (u8) (value >> 8);
- u8 low = (u8) (value & 0xFF);
- return new ref8([high, low], 0, 2);
- }
-
- public static ref8 ref8(u32 value)
- {
- u8 b1 = (u8) (value >> 24);
- u8 b2 = (u8) (value >> 16);
- u8 b3 = (u8) (value >> 8);
- u8 b4 = (u8) (value & 0xFF);
- return new ref8([b1, b2, b3, b4], 0, 4);
- }
- public static i16 i16(ref8 value)
- {
- return BinaryPrimitives.ReadInt16BigEndian(value);
- }
-
- public static i16 i16(u8 high, u8 low)
- {
- return BinaryPrimitives.ReadInt16BigEndian(new ReadOnlySpan([high, low]));
- }
-}
\ No newline at end of file
diff --git a/Program.cs b/Program.cs
deleted file mode 100644
index 016e557..0000000
--- a/Program.cs
+++ /dev/null
@@ -1,106 +0,0 @@
-using System;
-using System.IO;
-using System.Runtime.CompilerServices;
-using System.Threading;
-using Microsoft.Xna.Framework;
-using Q1Emu.Chip;
-using Q1Emu;
-using Q1Emu.Assembler;
-
-internal class Program
-{
- public static void Main(string[] args)
- {
- if (args.Length > 0)
- {
- string filePath = args[0];
-
- Environment.CurrentDirectory = Path.GetDirectoryName(filePath) ?? Environment.CurrentDirectory;
- filePath = Path.GetFileName(filePath);
-
- if (filePath.EndsWith(".q1"))
- {
- Run(filePath);
- }
- else
- {
- Program.AssembleAndRun(filePath);
- }
- }
- else
- {
- Console.WriteLine("Usage: Q1Emu ");
- Console.WriteLine("Example: Q1Emu game.q1");
- Console.WriteLine("Example: Q1Emu game.asm");
- }
- }
- 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)
- {
- Q1Cpu cpu = new();
- Bus bus = new(u16.MinValue, u16.MaxValue);
- RamDevice ram = new(0x1FFF, 1024 * 8);
- File.ReadAllBytes(filePath).CopyTo(ram.Memory, 0);
-
- cpu.PC = ram.AddressableStart;
-
- DisplayDevice display = new(16, 64, 32, 0x3FFF);
- display.SetPalette([
- Color.Red,
- Color.Green,
- Color.Blue,
- Color.Yellow,
- Color.Cyan,
- Color.Magenta,
- Color.White,
- Color.Black,
- Color.Gray,
- Color.Orange,
- Color.Purple,
- Color.Brown,
- Color.LightGray,
- Color.DarkGray,
- Color.LightBlue,
- Color.LightGreen
- ]);
-
- cpu.Bus = bus;
- ram.AttachToBus(bus);
- display.AttachToBus(bus);
-
- Thread t = new(() =>
- {
- while (true)
- {
- for (int i = 0; i < 64; i++)
- {
- cpu.Clock();
- }
- Thread.Sleep(1);
- //
- // cpu.Clock();
- // Thread.Sleep(1000);
- }
- });
- t.IsBackground = true;
- t.Start();
-
- using DisplayEngine game = new(64, 32, 10,
- tex =>
- {
- display.OutputTexture = tex;
- Console.WriteLine("Display texture initialized.");
- }, () => display.Clock());
- game.Run();
- }
-}
\ No newline at end of file
diff --git a/Q1.sln b/Q1.sln
new file mode 100644
index 0000000..97d648f
--- /dev/null
+++ b/Q1.sln
@@ -0,0 +1,28 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Emulator", "Emulator\Emulator.csproj", "{04CE77A9-E0DC-4CAB-9382-5F84B4275B6B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Compiler", "Compiler\Compiler.csproj", "{F3A482AD-855E-49B2-9E62-A7C68AB6250D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Assembler", "Assembler\Assembler.csproj", "{330B7F43-7267-4A2C-8EB0-257458231B7E}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {04CE77A9-E0DC-4CAB-9382-5F84B4275B6B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {04CE77A9-E0DC-4CAB-9382-5F84B4275B6B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {04CE77A9-E0DC-4CAB-9382-5F84B4275B6B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {04CE77A9-E0DC-4CAB-9382-5F84B4275B6B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F3A482AD-855E-49B2-9E62-A7C68AB6250D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F3A482AD-855E-49B2-9E62-A7C68AB6250D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F3A482AD-855E-49B2-9E62-A7C68AB6250D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F3A482AD-855E-49B2-9E62-A7C68AB6250D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {330B7F43-7267-4A2C-8EB0-257458231B7E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {330B7F43-7267-4A2C-8EB0-257458231B7E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {330B7F43-7267-4A2C-8EB0-257458231B7E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {330B7F43-7267-4A2C-8EB0-257458231B7E}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+EndGlobal
diff --git a/Q1.sln.DotSettings.user b/Q1.sln.DotSettings.user
new file mode 100644
index 0000000..a489bb0
--- /dev/null
+++ b/Q1.sln.DotSettings.user
@@ -0,0 +1,2 @@
+
+ ForceIncluded
\ No newline at end of file
diff --git a/Q1Emu.csproj b/Q1Emu.csproj
deleted file mode 100644
index 035139a..0000000
--- a/Q1Emu.csproj
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
- WinExe
- net8.0
- Major
- false
- false
- Chip8Emu2
- enable
-
-
- app.manifest
- Icon.ico
-
-
-
-
-
-
-
- Icon.ico
-
-
- Icon.bmp
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Q1Emu.sln b/Q1Emu.sln
deleted file mode 100644
index 801cf19..0000000
--- a/Q1Emu.sln
+++ /dev/null
@@ -1,16 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Q1Emu", "Q1Emu.csproj", "{04CE77A9-E0DC-4CAB-9382-5F84B4275B6B}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Release|Any CPU = Release|Any CPU
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {04CE77A9-E0DC-4CAB-9382-5F84B4275B6B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {04CE77A9-E0DC-4CAB-9382-5F84B4275B6B}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {04CE77A9-E0DC-4CAB-9382-5F84B4275B6B}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {04CE77A9-E0DC-4CAB-9382-5F84B4275B6B}.Release|Any CPU.Build.0 = Release|Any CPU
- EndGlobalSection
-EndGlobal
diff --git a/Q1Emu.sln.DotSettings.user b/Q1Emu.sln.DotSettings.user
deleted file mode 100644
index e3f7764..0000000
--- a/Q1Emu.sln.DotSettings.user
+++ /dev/null
@@ -1,4 +0,0 @@
-
- ForceIncluded
- ForceIncluded
- ForceIncluded
\ No newline at end of file
diff --git a/ROMs/.DS_Store b/ROMs/.DS_Store
index 523af33..775e323 100644
Binary files a/ROMs/.DS_Store and b/ROMs/.DS_Store differ
diff --git a/ROMs/font copy.bin b/ROMs/font copy.bin
deleted file mode 100644
index 88e4a93..0000000
Binary files a/ROMs/font copy.bin and /dev/null differ
diff --git a/ROMs/font.bin b/ROMs/font.bin
index 88e4a93..89f2af5 100644
Binary files a/ROMs/font.bin and b/ROMs/font.bin differ
diff --git a/ROMs/hello_c.asm b/ROMs/hello_c.asm
new file mode 100644
index 0000000..292b99a
--- /dev/null
+++ b/ROMs/hello_c.asm
@@ -0,0 +1,7 @@
+_main:
+ADD 1, 2
+SUB 4, 1
+MUL AX, AX
+MOV AX, V0
+RET
+
diff --git a/ROMs/hello_c.c b/ROMs/hello_c.c
new file mode 100644
index 0000000..46eab8d
--- /dev/null
+++ b/ROMs/hello_c.c
@@ -0,0 +1,4 @@
+int main()
+{
+ return (1 + 2) * (4 - 1);
+}
\ No newline at end of file
diff --git a/ROMs/hello_c.q1 b/ROMs/hello_c.q1
new file mode 100644
index 0000000..deffc80
Binary files /dev/null and b/ROMs/hello_c.q1 differ
diff --git a/ROMs/hello_world.asm b/ROMs/hello_world.asm
new file mode 100644
index 0000000..1d812fb
--- /dev/null
+++ b/ROMs/hello_world.asm
@@ -0,0 +1,42 @@
+.org $1FFF
+JMP program
+
+font:
+ .include "font.bin"
+
+program:
+ MOV 0, V0 ; Load character #12
+ MOV 0, V1 ; X position
+ MOV 0, V2 ; Y position
+ MOV 1, V3 ; Color (1 = white)
+ CALL write_char ; Call function to write character
+ SUS
+
+write_char:
+ ; V0: Character to write
+ ; V1: X position
+ ; V2: Y position
+ ; V3: Color
+ ; Write a character to the screen at (V1, V2) with color V3
+
+ MUL V0, 64 ; V0 = Character * 64 (character size)
+ MOV AX, V0 ; Store result back into character
+
+ MUL V2, 64
+ ADD AX, V1
+ MOV AX, V4 ; V4 = X position + Y position * 64 (screen index)
+
+ MOV V4, [$EFFF] ; Debug
+
+ MOV [V0 + $2003], V5 ; Read character (1FFF + 4 since jump address is 1FFF)
+ MOV V5, [$EFFF] ; Debug
+ AND V5, $01 ; Mask to get first bit (color)
+ MOV DX, V5
+ MOV V5, [$EFFF] ; Debug
+ MUL V5, V3 ; V5 = Character * Color (color index)
+ MOV AX, V5 ; Store result into V5
+
+ MOV V5, [$EFFF] ; Debug
+
+ MOVB V5, [V4 + $402F] ; Write character to screen memory
+ RET
\ No newline at end of file
diff --git a/ROMs/hello_world.dat b/ROMs/hello_world.dat
deleted file mode 100644
index 6cdacff..0000000
--- a/ROMs/hello_world.dat
+++ /dev/null
@@ -1,33 +0,0 @@
-.org $1FFF
-JMP program
-
-font:
- .include "font.bin"
-
-program:
- MOV 13, V0 ; Load character #12
- MOV 0, V1 ; X position
- MOV 0, V2 ; Y position
- MOV 1, V3 ; Color (1 = white)
- CALL write_char ; Call function to write character
- SUS
-
-write_char:
- ; V0: Character to write
- ; V1: X position
- ; V2: Y position
- ; V3: Color
- ; Write a character to the screen at (V1, V2) with color V3
-
- MUL V0, 64 ; V0 = Character * 64 (character size)
- MOV AX, V0 ; Store result back into character
-
- MUL V2, 64
- ADD AX, V1
- MOV AX, V4 ; V4 = X position + Y position * 64 (screen index)
-
- MOV [V0 + $1FFF], V5 ; Read character
- MUL V5, V3 ; V5 = Character * Color (color index)
- MOV AX, V5 ; Store result into V5
- MOV V5, [V4 + $3FFF] ; Write character to screen memory
- RET
\ No newline at end of file
diff --git a/ROMs/hello_world.q1 b/ROMs/hello_world.q1
index 4c1b1cd..fd66ffe 100644
Binary files a/ROMs/hello_world.q1 and b/ROMs/hello_world.q1 differ
diff --git a/ROMs/write_display_direct.asm b/ROMs/write_display_direct.asm
new file mode 100644
index 0000000..9fde417
--- /dev/null
+++ b/ROMs/write_display_direct.asm
@@ -0,0 +1,21 @@
+.org $1FFF
+
+program:
+MOV $0000, V0
+MUL 32, 64 ; Set AX to 32 * 64
+MOV AX, V1 ; Copy AX to V1
+MOV 1, V2 ; Color value 1
+
+reset:
+MOV 0, V0
+INC V2 ; Increment color value
+
+draw:
+GT V0, V1 ; V0 > V1?
+BZ ; If number exceeds, branch to reset
+JMP reset
+
+MOVB V2, [V0+$402F] ; Set pixel at V0 to color 6
+INC V0 ; Increment V0
+
+JMP draw ; Repeat drawing
\ No newline at end of file
diff --git a/ROMs/write_display_direct.dat b/ROMs/write_display_direct.dat
deleted file mode 100644
index 9fde417..0000000
--- a/ROMs/write_display_direct.dat
+++ /dev/null
@@ -1,21 +0,0 @@
-.org $1FFF
-
-program:
-MOV $0000, V0
-MUL 32, 64 ; Set AX to 32 * 64
-MOV AX, V1 ; Copy AX to V1
-MOV 1, V2 ; Color value 1
-
-reset:
-MOV 0, V0
-INC V2 ; Increment color value
-
-draw:
-GT V0, V1 ; V0 > V1?
-BZ ; If number exceeds, branch to reset
-JMP reset
-
-MOVB V2, [V0+$402F] ; Set pixel at V0 to color 6
-INC V0 ; Increment V0
-
-JMP draw ; Repeat drawing
\ No newline at end of file
diff --git a/app.manifest b/app.manifest
deleted file mode 100644
index d9c2d8d..0000000
--- a/app.manifest
+++ /dev/null
@@ -1,43 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- true/pm
- permonitorv2,permonitor
-
-
-
-
--
cgit v1.3.1