summaryrefslogtreecommitdiff
path: root/Assembler/Assembler.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Assembler/Assembler.cs')
-rw-r--r--Assembler/Assembler.cs106
1 files changed, 106 insertions, 0 deletions
diff --git a/Assembler/Assembler.cs b/Assembler/Assembler.cs
new file mode 100644
index 0000000..14a33fd
--- /dev/null
+++ b/Assembler/Assembler.cs
@@ -0,0 +1,106 @@
+namespace Q1Emu.Assembler;
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+
+public class Assembler
+{
+ public readonly BinaryWriter Writer;
+ public readonly StringReader Reader;
+
+ public Assembler(StringReader reader, BinaryWriter writer)
+ {
+ this.Reader = reader;
+ this.Writer = writer;
+ }
+
+ public void Assemble()
+ {
+ while (this.Reader.ReadLine() is { } line)
+ {
+ string trimmedLine = line.Trim();
+ if (string.IsNullOrEmpty(trimmedLine) || trimmedLine.StartsWith(';'))
+ continue;
+
+ this.ParseInstruction(trimmedLine);
+ }
+ }
+
+ private void ParseInstruction(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 ArgumentException($"Invalid instruction format: {instruction}");
+
+ u8 m1 = 0, m2 = 0;
+ if (parts.Length > 0)
+ {
+ m1 = this.ParseOperand(parts[0]);
+ if (parts.Length > 1)
+ m2 = this.ParseOperand(parts[1]);
+ }
+
+ switch (opcode)
+ {
+ case "NOP":
+ this.Writer.Write((u8) 0x00);
+ break;
+
+ default:
+ throw new NotSupportedException($"Unsupported opcode: {opcode}");
+ }
+ }
+
+ private u8 ParseOperand(string operand)
+ {
+ operand = operand.Trim();
+
+ bool IsRegister(string text)
+ {
+ if (text.Length > 1 && text[0] == 'V')
+ return true;
+
+ string[] hardcodedRegisters =
+ [
+ "AX",
+ "AH",
+ "AL",
+ "DX",
+ "DH",
+ "DL",
+ "LX",
+ "PC",
+ "SP",
+ ];
+
+ return hardcodedRegisters.Contains(text);
+ }
+
+ if (operand.StartsWith("@"))
+ {
+ return 0x03; // Indirect
+ }
+
+ if (operand.StartsWith("[") && operand.EndsWith("]"))
+ {
+ string inner = operand[1..^1].Trim();
+ if (inner.Contains("+"))
+ return 0x07; // Register indirect with offset
+
+ if (IsRegister(inner))
+ return 0x06; // Register indirect
+
+ return 0x02; // Direct
+ }
+
+ if (IsRegister(operand))
+ return 0x05; // Register
+
+ return 0x01; // Immediate
+ }
+} \ No newline at end of file