summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Assembler/Assembler.cs2
-rw-r--r--Compiler/CCompilerVisitor.cs208
-rw-r--r--Emulator/Chip/Q1Cpu.cs8
-rw-r--r--Emulator/Program.cs16
-rw-r--r--ROMs/hello_c.asm11
-rw-r--r--ROMs/hello_c.c2
-rw-r--r--ROMs/hello_c.q1bin22 -> 22 bytes
7 files changed, 163 insertions, 84 deletions
diff --git a/Assembler/Assembler.cs b/Assembler/Assembler.cs
index 7c172e7..d2f79ed 100644
--- a/Assembler/Assembler.cs
+++ b/Assembler/Assembler.cs
@@ -29,7 +29,7 @@ public class Assembler
private void ResolveLabels()
{
- int offset = 0;
+ int offset = Q1Cpu.ProgramStart;
int pos = 0;
foreach (string line in this.InputLines)
{
diff --git a/Compiler/CCompilerVisitor.cs b/Compiler/CCompilerVisitor.cs
index cee69f4..7bbbeda 100644
--- a/Compiler/CCompilerVisitor.cs
+++ b/Compiler/CCompilerVisitor.cs
@@ -2,19 +2,37 @@ namespace Q1.Compiler;
public class CCompilerVisitor : CGrammarBaseVisitor<string?>
{
- private List<string> Instructions = new();
+ private int _branchCount = 1;
+ private List<string> _instructions = new();
+ private string GetBranchLabel(string type)
+ {
+ return $"_{type}_{_branchCount++}";
+ }
+ private void Instruction(string instruction)
+ {
+ this._instructions.Add($" {instruction}");
+ }
+ private void Blank()
+ {
+ this._instructions.Add("");
+ }
+ private void Label(string name)
+ {
+ this._instructions.Add($"{name}:");
+ }
+
public IEnumerable<string> Compile(CGrammarParser.ProgramContext program)
{
this.Visit(program);
- return this.Instructions;
+ return this._instructions;
}
public override string? VisitFunction(CGrammarParser.FunctionContext context)
{
string functionName = context.ID().GetText();
- Instructions.Add($"_{functionName}:");
+ this.Label($"_{functionName}");
this.VisitChildren(context);
- this.Instructions.Add("");
+ this.Blank();
return null;
}
@@ -29,14 +47,14 @@ public class CCompilerVisitor : CGrammarBaseVisitor<string?>
string? expression = this.Visit(context.expression());
if (expression != null)
{
- this.Instructions.Add($"MOV {expression}, V0");
- Instructions.Add($"RET");
+ this.Instruction($"mov {expression}, V0");
+ this.Instruction($"ret");
}
else
throw new CompilerException("Return value was not an expression.");
}
else
- Instructions.Add("RET");
+ this.Instruction("ret");
return null;
}
@@ -55,7 +73,7 @@ public class CCompilerVisitor : CGrammarBaseVisitor<string?>
if (value == null)
throw new CompilerException("Value for negating was not an expression.");
- this.Instructions.Add($"NOT {value}");
+ this.Instruction($"not {value}");
return "LX";
}
@@ -65,108 +83,170 @@ public class CCompilerVisitor : CGrammarBaseVisitor<string?>
if (value == null)
throw new CompilerException("Value for inversion was not an expression.");
- this.Instructions.Add($"INV {value}");
+ this.Instruction($"inv {value}");
return "DX";
}
- public override string? VisitAddExpression(CGrammarParser.AddExpressionContext context)
+ private void BaseBinaryOperation(CGrammarParser.ExpressionContext leftExpr, CGrammarParser.ExpressionContext rightExpr, string operation, string operationFriendlyName)
{
- string? left = this.Visit(context.left);
- string? right = this.Visit(context.right);
+ string? left = this.Visit(leftExpr);
+ if (left == null)
+ throw new CompilerException($"Left operand for {operationFriendlyName} was not an expression.");
+
+ this.Instruction($"push {left}");
- if (left == null || right == null)
- throw new CompilerException("Left or right operand for addition was not an expression.");
+ string? right = this.Visit(rightExpr);
+ if (right == null)
+ throw new CompilerException($"Right operand for {operationFriendlyName} was not an expression.");
- this.Instructions.Add($"ADD {left}, {right}");
+ this.Instruction($"mov {right}, V1");
+ this.Instruction($"pop V0");
+ this.Instruction($"{operation} V0, V1");
+ }
+ public override string? VisitAddExpression(CGrammarParser.AddExpressionContext context)
+ {
+ BaseBinaryOperation(context.left, context.right, "add", "addition");
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}");
+ BaseBinaryOperation(context.left, context.right, "sub", "subtraction");
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}");
+ BaseBinaryOperation(context.left, context.right, "mul", "multiplication");
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}");
+ BaseBinaryOperation(context.left, context.right, "div", "division");
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}");
+ BaseBinaryOperation(context.left, context.right, "mod", "modulus");
return "AX";
}
- public override string? VisitBitwiseXorExpression(CGrammarParser.BitwiseXorExpressionContext context)
- {
- throw new NotImplementedException();
- }
- public override string? VisitLessThanOrEqualExpression(CGrammarParser.LessThanOrEqualExpressionContext context)
+ public override string? VisitEqualExpression(CGrammarParser.EqualExpressionContext context)
{
- throw new NotImplementedException();
+ BaseBinaryOperation(context.left, context.right, "cmp", "equality check");
+ return "LX";
}
+
public override string? VisitNotEqualExpression(CGrammarParser.NotEqualExpressionContext context)
{
- throw new NotImplementedException();
+ BaseBinaryOperation(context.left, context.right, "cmp", "inequality check");
+ this.Instruction($"not"); // lx is implicit
+ return "LX";
}
+
public override string? VisitGreaterThanExpression(CGrammarParser.GreaterThanExpressionContext context)
{
- throw new NotImplementedException();
+ BaseBinaryOperation(context.left, context.right, "gt", "greater than check");
+ return "LX";
+ }
+
+ public override string? VisitLessThanExpression(CGrammarParser.LessThanExpressionContext context)
+ {
+ BaseBinaryOperation(context.left, context.right, "lt", "less than check");
+ return "LX";
}
+
public override string? VisitLogicalOrExpression(CGrammarParser.LogicalOrExpressionContext context)
{
- throw new NotImplementedException();
+ string? left = this.Visit(context.left);
+ if (left == null)
+ throw new CompilerException("Left operand for logical OR was not an expression.");
+
+ string clauseBranch = this.GetBranchLabel("clause");
+ string endBranch = this.GetBranchLabel("end");
+
+ this.Instruction($"cmp {left}, 0");
+ this.Instruction("bz"); // implicit LX
+ this.Instruction($"jmp {clauseBranch}"); // only if bz is not 0
+ this.Instruction("mov 1, V0");
+ this.Instruction($"jmp {endBranch}");
+ this.Label(clauseBranch);
+
+ string? right = this.Visit(context.right);
+ if (right == null)
+ throw new CompilerException("Right operand for logical OR was not an expression.");
+
+ this.Instruction($"cmp {right}, 0");
+ this.Instruction("not");
+ this.Instruction("mov LX, V0");
+ this.Label(endBranch);
+
+ return "V0";
}
- public override string? VisitGreaterThanOrEqualExpression(CGrammarParser.GreaterThanOrEqualExpressionContext context)
+ public override string? VisitLogicalAndExpression(CGrammarParser.LogicalAndExpressionContext context)
{
- throw new NotImplementedException();
+ string? left = this.Visit(context.left);
+ if (left == null)
+ throw new CompilerException("Left operand for logical OR was not an expression.");
+
+ string clauseBranch = this.GetBranchLabel("clause");
+ string endBranch = this.GetBranchLabel("end");
+
+ this.Instruction($"cmp {left}, 0");
+ this.Instruction("not");
+ this.Instruction("bz"); // implicit LX
+ this.Instruction($"jmp {clauseBranch}"); // only if bz is not 0
+ this.Instruction("mov 0, V0");
+ this.Instruction($"jmp {endBranch}");
+ this.Label(clauseBranch);
+
+ string? right = this.Visit(context.right);
+ if (right == null)
+ throw new CompilerException("Right operand for logical OR was not an expression.");
+
+ this.Instruction($"cmp {right}, 0");
+ this.Instruction("not");
+ this.Instruction("mov LX, V0");
+ this.Label(endBranch);
+
+ return "V0";
}
- public override string? VisitBitwiseOrExpression(CGrammarParser.BitwiseOrExpressionContext context)
+
+ public override string? VisitGreaterThanOrEqualExpression(CGrammarParser.GreaterThanOrEqualExpressionContext context)
{
- throw new NotImplementedException();
+ BaseBinaryOperation(context.left, context.right, "cmp", "equality check");
+ string endBranch = this.GetBranchLabel("end");
+
+ this.Instruction("bz");
+ this.Instruction($"jmp {endBranch}");
+ this.Instruction($"gt V0, V1");
+ this.Label(endBranch);
+
+ return "LX";
}
- public override string? VisitBitwiseAndExpression(CGrammarParser.BitwiseAndExpressionContext context)
+ public override string? VisitLessThanOrEqualExpression(CGrammarParser.LessThanOrEqualExpressionContext context)
{
- throw new NotImplementedException();
+ BaseBinaryOperation(context.left, context.right, "cmp", "equality check");
+ string endBranch = this.GetBranchLabel("end");
+
+ this.Instruction("bz");
+ this.Instruction($"jmp {endBranch}");
+ this.Instruction($"lt V0, V1");
+ this.Label(endBranch);
+
+ return "LX";
}
- public override string? VisitLessThanExpression(CGrammarParser.LessThanExpressionContext context)
+ public override string? VisitBitwiseXorExpression(CGrammarParser.BitwiseXorExpressionContext context)
{
- throw new NotImplementedException();
+ this.BaseBinaryOperation(context.left, context.right, "xor", "exclusive or");
+ return "DX";
}
- public override string? VisitLogicalAndExpression(CGrammarParser.LogicalAndExpressionContext context)
+ public override string? VisitBitwiseOrExpression(CGrammarParser.BitwiseOrExpressionContext context)
{
- throw new NotImplementedException();
+ this.BaseBinaryOperation(context.left, context.right, "or", "or");
+ return "DX";
}
- public override string? VisitEqualExpression(CGrammarParser.EqualExpressionContext context)
+ public override string? VisitBitwiseAndExpression(CGrammarParser.BitwiseAndExpressionContext context)
{
- throw new NotImplementedException();
+ this.BaseBinaryOperation(context.left, context.right, "and", "and");
+ return "DX";
}
} \ No newline at end of file
diff --git a/Emulator/Chip/Q1Cpu.cs b/Emulator/Chip/Q1Cpu.cs
index 16e1e14..d1fcf7a 100644
--- a/Emulator/Chip/Q1Cpu.cs
+++ b/Emulator/Chip/Q1Cpu.cs
@@ -5,8 +5,9 @@ using Assembler;
public partial class Q1Cpu
{
- public const u16 StackStart = 0x2FFF;
- public const u16 StackLength = 16 * 2; // 16 16-bit values
+ public const u16 StackStart = 0x2FFF;
+ public const u16 StackLength = 16 * 2; // 16 16-bit values
+ public const u16 ProgramStart = 0x1FFF;
public Random Random;
@@ -18,7 +19,6 @@ public partial class Q1Cpu
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; }
@@ -38,7 +38,7 @@ public partial class Q1Cpu
this.SP = Q1Cpu.StackStart;
this.PushStack(0xFFFF);
- this.I = 0;
+ this.PC = Q1Cpu.ProgramStart;
}
public void Clock()
diff --git a/Emulator/Program.cs b/Emulator/Program.cs
index cd6a8c0..3104fa9 100644
--- a/Emulator/Program.cs
+++ b/Emulator/Program.cs
@@ -20,9 +20,7 @@ internal class Program
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,
@@ -55,13 +53,13 @@ internal class Program
cpu.Reset();
while (!cpu.AbortRequested)
{
- for (int i = 0; i < 64; i++)
- cpu.Clock();
-
- Thread.Sleep(1);
+ // for (int i = 0; i < 64; i++)
+ // cpu.Clock();
+ //
+ // Thread.Sleep(1);
//
- // cpu.Clock();
- // Thread.Sleep(1000);
+ cpu.Clock();
+ Thread.Sleep(1000);
}
Console.WriteLine($"Exit code: 0x{cpu.V[0]:X4}");
});
diff --git a/ROMs/hello_c.asm b/ROMs/hello_c.asm
index 292b99a..8cdf58b 100644
--- a/ROMs/hello_c.asm
+++ b/ROMs/hello_c.asm
@@ -1,7 +1,8 @@
_main:
-ADD 1, 2
-SUB 4, 1
-MUL AX, AX
-MOV AX, V0
-RET
+ push 0
+ mov 1, V1
+ pop V0
+ or V0, V1
+ mov DX, V0
+ ret
diff --git a/ROMs/hello_c.c b/ROMs/hello_c.c
index 46eab8d..1f79a53 100644
--- a/ROMs/hello_c.c
+++ b/ROMs/hello_c.c
@@ -1,4 +1,4 @@
int main()
{
- return (1 + 2) * (4 - 1);
+ return 0 | 1;
} \ No newline at end of file
diff --git a/ROMs/hello_c.q1 b/ROMs/hello_c.q1
index deffc80..5e4d71e 100644
--- a/ROMs/hello_c.q1
+++ b/ROMs/hello_c.q1
Binary files differ