Skip to content

Commit

Permalink
working opcode system using JSON
Browse files Browse the repository at this point in the history
  • Loading branch information
rbaker26 committed Jun 17, 2020
1 parent c9aeea2 commit 8f4e6ae
Show file tree
Hide file tree
Showing 6 changed files with 170 additions and 30 deletions.
24 changes: 12 additions & 12 deletions SAP1EMU.Assembler/Assemble.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ namespace SAP1EMU.Assembler
{
public static class Assemble
{

public static List<string> Parse(List<string> unchecked_assembly)
private const string DefaultInstructionSetName = "SAP1Emu";
public static List<string> Parse(List<string> unchecked_assembly, string InstructionSetName = DefaultInstructionSetName)
{

// Get Instruction Set
InstructionSet iset = OpCodeLoader.GetSet("SAP1Emu");
InstructionSet iset = OpCodeLoader.GetSet(InstructionSetName);

// *********************************************************************
// Sanitize *
Expand Down Expand Up @@ -142,14 +142,14 @@ private static bool IsValid(List<string> unchecked_assembly, InstructionSet iset

if(nibbles.Length == 0)
{
throw new ParseException($"SAP1ASM: Line cannot be blank (line: {line_number})", new ParseException("Use \"NOP 0x0\" for a no-operation command"));
throw new ParseException($"SAP1ASM: Line cannot be blank (line: {line_number}).", new ParseException("Use \"NOP 0x0\" for a no-operation command"));

}

string instruction = nibbles[0];
if (nibbles.Length < 2)
{
throw new ParseException($"SAP1ASM: No lower nibble detected (line: {line_number})", new ParseException($"{instruction} must be paired with a valid address in the range of 0x0 - 0xF"));
throw new ParseException($"SAP1ASM: No lower nibble detected (line: {line_number}).", new ParseException($"{instruction} must be paired with a valid address in the range of 0x0 - 0xF"));
}
string addr = nibbles[1];

Expand All @@ -158,15 +158,15 @@ private static bool IsValid(List<string> unchecked_assembly, InstructionSet iset
// Check Intruction
if (instruction.Length != 3)
{
throw new ParseException($"SAP1ASM: invalid intruction on line {line_number}", new ParseException($"{instruction} is not a recognized instruction"));
throw new ParseException($"SAP1ASM: invalid intruction on line {line_number}.", new ParseException($"{instruction} is not a recognized instruction"));
}


if (!InstructionValidator.IsValidInstruction(instruction.ToUpper(),iset)) // Check if is valid instruction
{
if (!Regex.IsMatch(instruction, "^0[xX][0-9a-fA-F]$")) // Make sure it isnt data
{
throw new ParseException($"SAP1ASM: invalid intruction on line {line_number}", new ParseException($"{instruction} is not a recognized instruction or valid data"));
throw new ParseException($"SAP1ASM: invalid intruction on line {line_number}.", new ParseException($"{instruction} is not a recognized instruction or valid data"));
}
}

Expand All @@ -175,21 +175,21 @@ private static bool IsValid(List<string> unchecked_assembly, InstructionSet iset
// Check Address
if (addr.Length != 3) // should be no more than 3
{
throw new ParseException($"SAP1ASM: invalid address on line {line_number}", new ParseException($"{addr} is not of the form \"0xX\""));
throw new ParseException($"SAP1ASM: invalid address on line {line_number}.", new ParseException($"{addr} is not of the form \"0xX\""));
}
if (!Regex.IsMatch(addr, "^0[xX][0-9a-fA-F]$")) // should be of the form 0xX
{
throw new ParseException($"SAP1ASM: invalid address on line {line_number}", new ParseException($"{addr} is not of the form \"0xX\""));
throw new ParseException($"SAP1ASM: invalid address on line {line_number}.", new ParseException($"{addr} is not of the form \"0xX\""));
}
int hex_addr = (int)(Convert.ToUInt32(addr.Substring(2, 1), 16));
if (hex_addr < 0 || hex_addr >= 16) // must tbe between 0-15
{
throw new ParseException($"SAP1ASM: address out of range on line {line_number}", new ParseException($"{addr} must be betweeen 0x0 and 0xF"));
throw new ParseException($"SAP1ASM: address out of range on line {line_number}.", new ParseException($"{addr} must be betweeen 0x0 and 0xF"));
}

if(line.Contains("..."))
{
throw new ParseException($"SAP1ASM: invalid use of \"...\" on line {line_number}", new ParseException($"{line} must only contain \"...\" with no extra charecters or spaces"));
throw new ParseException($"SAP1ASM: invalid use of \"...\" on line {line_number}.", new ParseException($"{line} must only contain \"...\" with no extra charecters or spaces"));

}
}
Expand All @@ -201,7 +201,7 @@ private static bool IsValid(List<string> unchecked_assembly, InstructionSet iset
}
else
{
throw new ParseException($"SAP1ASM: invalid use of \"...\" {line_number}", new ParseException($"{line} must only contain once instance of \"...\" in the program"));
throw new ParseException($"SAP1ASM: invalid use of \"...\" {line_number}.", new ParseException($"{line} must only contain once instance of \"...\" in the program"));

}
}
Expand Down
80 changes: 66 additions & 14 deletions SAP1EMU.Engine-CLI/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
using System.IO;
using System.Text;
using System.Threading;

using CommandLine;

using SAP1EMU.Assembler;
using SAP1EMU.Engine;
using SAP1EMU.Lib;
Expand Down Expand Up @@ -53,6 +55,12 @@ public class Options
public bool Debug { get; set; }
// ********************************************

// Instruction Set ****************************
[Option('i', "instructionSet", Required = false, HelpText = "Sets the Instruction Set to use\nParameters:\n SAP1Emu\tUses expanded SAP1EMU Instruction Set (default)\n Malvino\tUses Malvino's Instruction Set\n BenEater\tUses Ben Eater's Instruction Set", Default = "SAP1Emu")]
public string InstructionSetName { get; set; }
// ********************************************




}
Expand Down Expand Up @@ -124,24 +132,58 @@ static void Main(string[] args)


}
if(!string.IsNullOrEmpty(o.FOframe))
if (!string.IsNullOrEmpty(o.FOframe))
{
if (o.FOframe.ToLower() != "no-format" && o.FOframe.ToLower() != "std")
{
Console.Error.WriteLine($"SAP1EMU: warning: {o.SourceFile}: invalid format argument {o.FOframe}: Defaulting to \"std\".");
o.FOframe = "std";
}
}



if (o.InstructionSetName.ToLower() != "sap1emu" && o.InstructionSetName.ToLower() != "malvino" && o.InstructionSetName.ToLower() != "beneater")
{
Console.Error.WriteLine($"SAP1EMU: warning: {o.InstructionSetName}: invalid argument: Defaulting to \"SAP1Emu\".");
o.InstructionSetName = "SAP1Emu";
}



List<string> compiled_binary;



List<string> compiled_binary = null;

if (fileType == FileType.S)
{
compiled_binary = Assemble.Parse(source_file_contents);
try
{
compiled_binary = Assemble.Parse(source_file_contents, o.InstructionSetName);
}
catch (ParseException pe)
{
//Console.SetOut(new StreamWriter(Console.OpenStandardOutput()));
//Console.SetError(new StreamWriter(Console.OpenStandardError()));

var tempColor = Console.ForegroundColor;
if (Console.BackgroundColor == ConsoleColor.Red)
{
Console.ForegroundColor = ConsoleColor.Cyan;
}
else
{
Console.ForegroundColor = ConsoleColor.Red;
}
Console.Error.WriteLine($"SAP1ASM: fatal error: " + pe.Message + " " + pe.InnerException.Message);
Console.ForegroundColor = tempColor;
Console.Error.WriteLine("assembly terminated");



Console.Error.Flush();

System.Environment.Exit(1);
}
}
else
{
Expand All @@ -164,18 +206,28 @@ static void Main(string[] args)
//Console.SetError(writer_error);


engine.Init(rmp);
engine.Init(rmp, o.InstructionSetName);
try
{
engine.Run();

}
catch (EngineRuntimeException ere)
{
Console.SetOut(new StreamWriter(Console.OpenStandardOutput()));
Console.SetError(new StreamWriter(Console.OpenStandardError()));
var tempColor = Console.ForegroundColor;
if (Console.BackgroundColor == ConsoleColor.Red)
{
Console.ForegroundColor = ConsoleColor.Cyan;
}
else
{
Console.ForegroundColor = ConsoleColor.Red;
}
//Console.SetOut(new StreamWriter(Console.OpenStandardOutput()));
//Console.SetError(new StreamWriter(Console.OpenStandardError()));

Console.Error.WriteLine($"SAP1EMU: fatal error: " + ere.Message);
Console.Error.WriteLine($"SAP1EMU: fatal error: " + ere.Message + " " + ere.InnerException.Message);
Console.ForegroundColor = tempColor;
Console.Error.WriteLine("emulation terminated");

Console.Error.Flush();
Expand Down Expand Up @@ -208,9 +260,9 @@ static void Main(string[] args)

engine_output += "\n" + sb.ToString();
}
else if(o.FOframe != null)
else if (o.FOframe != null)
{
engine_output =null; // Clear the output
engine_output = null; // Clear the output

StringBuilder sb = new StringBuilder();
StringWriter fw = new StringWriter(sb);
Expand All @@ -223,16 +275,16 @@ static void Main(string[] args)
{
fw.WriteLine(frame.OutputRegister());
}
else if(o.FOframe.ToLower() == "no-format")
else if (o.FOframe.ToLower() == "no-format")
{
string temp = frame.OReg;
if(string.IsNullOrEmpty(temp))
if (string.IsNullOrEmpty(temp))
{
temp = "00000000";
}
fw.WriteLine(temp);
}

}
}
fw.Flush();
Expand Down
5 changes: 3 additions & 2 deletions SAP1EMU.Engine/EngineProc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@ public class EngineProc
private readonly List<Frame> _FrameStack = new List<Frame>();
private RAMProgram Program { get; set; }
private InstructionSet InstructionSet { get; set; }
private const string DefaultInstructionSetName = "SAP1Emu";

// *************************************************************************
// Init Engine
// *************************************************************************
public void Init(RAMProgram program)
public void Init(RAMProgram program, string InstructionSetName = DefaultInstructionSetName)
{
// Get Instruction Set
InstructionSet = OpCodeLoader.GetSet("SAP1Emu");
InstructionSet = OpCodeLoader.GetSet(InstructionSetName);

// Init RAM
if (program == null)
Expand Down
51 changes: 51 additions & 0 deletions SAP1EMU.Lib.Test/AssemblerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -417,5 +417,56 @@ public void TestParseList_Invalid_Code_3()


#endregion


// Malvino Op Code Loop Detection Test **************************************
[TestMethod]
public void Test_MalvinoCodes_1()
{
List<string> asm = new List<string>
{
"LDA 0xF",
"OUT 0x0",
"HLT 0x0",
"... ",
"0xA 0xA"
};
try
{
Assemble.Parse(asm, "Malvino");
}
catch(Exception e)
{
Assert.Fail(e.ToString());
}
}


[TestMethod]
public void Test_MalvinoCodes_2()
{
List<string> asm = new List<string>
{
"LDA 0xF",
"STA 0xE",
"OUT 0x0",
"HLT 0x0",
"... ",
"0x0 0x0",
"0xA 0xA"
};
try
{
Assemble.Parse(asm, "Malvino");
Assert.Fail();
}
catch (Exception e)
{

}
}
// **************************************************************************


}
}
2 changes: 1 addition & 1 deletion SAP1EMU.Lib.Test/EngineTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1138,7 +1138,7 @@ public void Infinite_Loop_Test()
}
// **************************************************************************



}
}
38 changes: 37 additions & 1 deletion SAP1EMU.Lib/InstructionSets.json
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,42 @@
"00101110000111",
"00111100011111"
]
},
{
"OpCode": "SUB",
"BinCode": "0010",
"MicroCode": [
"01011110001111",
"10111110001111",
"00100110001111",
"00011010001111",
"00101110000111",
"00111100111111"
]
},
{
"OpCode": "OUT",
"BinCode": "1110",
"MicroCode": [
"01011110001111",
"10111110001111",
"00100110001111",
"00111111001011",
"00111110001111",
"00111110001111"
]
},
{
"OpCode": "HLT",
"BinCode": "1111",
"MicroCode": [
"01011110001111",
"10111110001111",
"00100110001111",
"00111110001111",
"00111110001111",
"00111110001111"
]
}
]
},
Expand All @@ -156,7 +192,7 @@
]
},
{
"OpCode": "LDA",
"OpCode": "OUT",
"BinCode": "0000",
"MicroCode": [
"01010",
Expand Down

0 comments on commit 8f4e6ae

Please sign in to comment.