Implemeted Flag support and flag CONSTS.

Implmeneted ALIAS assembler instruction, JBC & JBS instructions.
This commit is contained in:
2017-12-23 17:26:35 +00:00
parent 7bd26502ff
commit 1efb9d69b5
13 changed files with 335 additions and 34 deletions

View File

@@ -8,11 +8,11 @@ Bits marked N/A read as zero and writing values will not have an effect.
### Status | CONSTS | 0x00 ### Status | CONSTS | 0x00
| | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | | | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
| --------------- | --- | --- | --- | --- | --- | --- | --- | --- | | --------------- | --- | --- | --- | --- | --- | --- | --- | --- |
| **Read/Write** | | | | | | | R/W | R | | **Read/Write** | | | | | R | R/W | R/W | R |
| **Defaults** | | | | | | | 1 | X | | **Default ** | | | | | X | 1 | 1 | X |
| **Name** | N/A | N/A | N/A | N/A | N/A | N/A | Enabled | Available | | **Name** | N/A | N/A | N/A | N/A | ReadAvailable | ReadBlock | Enabled | Available |
### Cursor X | CONPOSX | 0x01 ### Cursor X | CONPOSX | 0x01
@@ -50,9 +50,9 @@ Trap status and settings
<!-- <!--
### Name | ALIAS | 0x00 ### Name | ALIAS | 0x00
| | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | | | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
| --------------- | --- | --- | --- | --- | --- | --- | --- | --- | | --------------- | --- | --- | --- | --- | --- | --- | --- | --- |
| **Read/Write** | | | | | | | | | | **Read/Write** | | | | | | | | |
| **Defaults** | | | | | | | | | | **Default ** | | | | | | | | |
| **Name** | | | | | | | | | | **Name** | | | | | | | | |
--> -->

View File

@@ -71,8 +71,8 @@
| 0x51 | JMP | [#\|:] | | 0x51 | JMP | [#\|:] |
| 0x52 | JZ | [R] [#\|:] | | 0x52 | JZ | [R] [#\|:] |
| 0x53 | JNZ | [R] [#\|:] | | 0x53 | JNZ | [R] [#\|:] |
| 0x54 | JBS | [R] [0-7] [#\|:] | | 0x54 | JBS | [R] [1-8] [#\|:] |
| 0x55 | JBC | [R] [0-7] [#\|:] | | 0x55 | JBC | [R] [1-8] [#\|:] |
| **System** | **System**
| 0x60 | SYS | [0-255] | Syscall, parameters depend on call | 0x60 | SYS | [0-255] | Syscall, parameters depend on call
@@ -80,7 +80,8 @@
| ASM | Parameters | Notes | | ASM | Parameters | Notes |
| ------ | ---------- | ------------ | | ------ | ---------- | ------------ |
| ORIGIN | [#] | Sets the Memory Address for the next instruction | | ORIGIN | [#] | Sets the Memory Address for the next instruction
| ALIAS | X Y | Replaces word X with word Y where X and Y are alpha numberic, only applies after the instruction
## Program Format ## Program Format

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Text; using System.Text;
using System.Linq; using System.Linq;
using System.Diagnostics; using System.Diagnostics;
using System.Text.RegularExpressions;
namespace SVM namespace SVM
{ {
@@ -28,8 +29,11 @@ namespace SVM
ushort lastpos = 0; ushort lastpos = 0;
string line; string line;
string[] parts; string[] parts;
Dictionary<string, ushort> markers = new Dictionary<string, ushort>(); Dictionary<string, ushort> markers = new Dictionary<string, ushort>();
Dictionary<string, List<ushort>> markerUses = new Dictionary<string, List<ushort>>(); Dictionary<string, List<ushort>> markerUses = new Dictionary<string, List<ushort>>();
Dictionary<string, string> aliases = new Dictionary<string, string>();
//Encode ops until memory section //Encode ops until memory section
for (; i < lines.Length; i++) for (; i < lines.Length; i++)
{ {
@@ -46,6 +50,12 @@ namespace SVM
line = line.Replace(" ", " "); line = line.Replace(" ", " ");
} }
//Replace aliases
foreach(var alias in aliases)
{
line = Regex.Replace(line, string.Format(@"(^|\b){0}($|\b)", alias.Key), alias.Value);
}
//Records marker locations //Records marker locations
if (line.StartsWith(':')) if (line.StartsWith(':'))
{ {
@@ -77,6 +87,18 @@ namespace SVM
if (mempos > lastpos) lastpos = mempos; if (mempos > lastpos) lastpos = mempos;
continue; continue;
} }
if (op == "ALIAS")
{
Debug.Assert(parts.Length == 2);
var aliasParts = parts[1].Split(' ', 2);
Debug.Assert(aliasParts.Length == 2);
if (aliases.ContainsKey(aliasParts[0]))
{
aliases.Remove(aliasParts[0]);
}
aliases.Add(aliasParts[0], aliasParts[1]);
continue;
}
var instr = instructions.First(x => x.ASM == op); var instr = instructions.First(x => x.ASM == op);

33
SVM/Flag.cs Normal file
View File

@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
namespace SVM
{
abstract class Flag
{
public static Flag[] GetAllFlags()
{
var types = from t in Assembly.GetAssembly(typeof(Flag)).GetTypes()
where t.IsSubclassOf(typeof(Flag))
select t;
var flags = new List<Flag>();
foreach (var t in types)
{
flags.Add((Flag)Activator.CreateInstance(t));
}
return flags.ToArray();
}
public abstract string ASM { get; }
public abstract byte Address { get; }
public abstract byte Read(VM vm);
public abstract void Write(VM vm, byte val);
}
}

51
SVM/Flags/CONSTS.cs Normal file
View File

@@ -0,0 +1,51 @@
using SVM.Ports;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
namespace SVM.Flags
{
class CONSTS : Flag
{
public const byte AVAILABLE = 1;
public const byte ENABLED = 2;
public const byte READBLOCK = 4;
public const byte READAVAILABLE = 8;
public override string ASM => "CONSTS";
public override byte Address => 0x00;
public override byte Read(VM vm)
{
var port = vm.Ports[0] as ConsolePort;
Debug.Assert(port != null);
byte result = AVAILABLE;
if (port.Enabled)
{
result |= ENABLED;
}
if (port.ReadBlock)
{
result |= READBLOCK;
}
if (Console.KeyAvailable)
{
result |= READAVAILABLE;
}
return result;
}
public override void Write(VM vm, byte val)
{
var port = vm.Ports[0] as ConsolePort;
Debug.Assert(port != null);
port.Enabled = (val & ENABLED) == ENABLED;
port.ReadBlock = (val & READBLOCK) == READBLOCK;
}
}
}

83
SVM/Instructions/JBC.cs Normal file
View File

@@ -0,0 +1,83 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
namespace SVM.Instructions
{
class JBC : Instruction
{
public override string ASM => "JBC";
public override byte OP => 0x55;
public override byte[] Encode(string asm, Dictionary<string, ushort> markerRefs)
{
var parts = asm.Split(' ');
Debug.Assert(parts.Length == 3);
byte reg = Register.FromASM(parts[0]);
byte bit = byte.Parse(parts[1]);
Debug.Assert(bit >= 1 && bit <= 8);
ushort loc = 0;
if (parts[2].StartsWith(':') && markerRefs != null)
{
markerRefs.Add(parts[2].Substring(1), 3);
}
else if (parts[2].StartsWith("0x", StringComparison.InvariantCultureIgnoreCase))
{
loc = ushort.Parse(parts[2].Substring(2), System.Globalization.NumberStyles.HexNumber);
}
else
{
loc = ushort.Parse(parts[2]);
}
return new byte[] { OP, reg, bit, loc.HiByte(), loc.LoByte() };
}
public override byte[] Decode(VM vm)
{
var bc = vm.MEM.Subset(vm.PC, 4);
vm.PC += 4;
return bc;
}
public override void Exec(VM vm, byte[] vars)
{
Debug.Assert(vars.Length == 4);
byte reg = vars[0];
Debug.Assert(reg <= VM.REGISTERS);
byte bit = vars[1];
Debug.Assert(bit >= 1 && bit <= 8);
ushort loc = (ushort)((vars[2] << 8) + vars[3]);
if (CheckJump(vm, reg, bit))
{
vm.PC = loc;
}
}
protected virtual bool CheckJump(VM vm, byte reg, byte bit)
{
byte compare = (byte)(1 << bit - 1);
return (vm.R[reg] & compare) == 0;
}
public override string ToASM(byte[] vars)
{
Debug.Assert(vars.Length == 4);
byte reg = vars[0];
Debug.Assert(reg <= VM.REGISTERS);
byte bit = vars[1];
ushort loc = (ushort)((vars[2] << 8) + vars[3]);
return string.Format("{0} {1} {2} {3}", ASM, Register.ToASM(reg), bit, string.Format("0x{0:X}", loc));
}
}
}

19
SVM/Instructions/JBS.cs Normal file
View File

@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace SVM.Instructions
{
class JBS : JBC
{
public override string ASM => "JBS";
public override byte OP => 0x54;
protected override bool CheckJump(VM vm, byte reg, byte bit)
{
byte compare = (byte)(1 << bit - 1);
return (vm.R[reg] & compare) == compare;
}
}
}

View File

@@ -44,7 +44,7 @@ namespace SVM.Instructions
protected virtual void Run(VM vm, byte reg, byte bit) protected virtual void Run(VM vm, byte reg, byte bit)
{ {
vm.R[reg] = (ushort)(vm.R[reg] << bit); vm.R[reg] = (ushort)(vm.R[reg] << bit-1);
} }
public override string ToASM(byte[] vars) public override string ToASM(byte[] vars)

View File

@@ -15,9 +15,7 @@ namespace SVM
public const string MEMORY_ASM = "M"; public const string MEMORY_ASM = "M";
public const byte IMMEDIATE_CODE = 0x3; public const byte IMMEDIATE_CODE = 0x3;
public const string IMMEDIATE_ASM = "I"; public const string IMMEDIATE_ASM = "I";
public const byte FLAG_CODE = 0x4; public const byte ADDRESS_CODE = 0x4;
public const string FLAG_ASM = "F";
public const byte ADDRESS_CODE = 0x5;
public const string ADDRESS_ASM = "A"; public const string ADDRESS_ASM = "A";
public const int SIZE = 3; public const int SIZE = 3;
@@ -30,7 +28,6 @@ namespace SVM
case REGISTER_ASM: return REGISTER_CODE; case REGISTER_ASM: return REGISTER_CODE;
case MEMORY_ASM: return MEMORY_CODE; case MEMORY_ASM: return MEMORY_CODE;
case IMMEDIATE_ASM: return IMMEDIATE_CODE; case IMMEDIATE_ASM: return IMMEDIATE_CODE;
case FLAG_ASM: return FLAG_CODE;
case ADDRESS_ASM:return ADDRESS_CODE; case ADDRESS_ASM:return ADDRESS_CODE;
default: throw new Exception("Invalid location type"); default: throw new Exception("Invalid location type");
} }
@@ -43,7 +40,6 @@ namespace SVM
case REGISTER_CODE: return REGISTER_ASM; case REGISTER_CODE: return REGISTER_ASM;
case MEMORY_CODE: return MEMORY_ASM; case MEMORY_CODE: return MEMORY_ASM;
case IMMEDIATE_CODE: return IMMEDIATE_ASM; case IMMEDIATE_CODE: return IMMEDIATE_ASM;
case FLAG_CODE: return FLAG_ASM;
case ADDRESS_CODE: return ADDRESS_ASM; case ADDRESS_CODE: return ADDRESS_ASM;
default: throw new Exception("Invalid location type"); default: throw new Exception("Invalid location type");
} }
@@ -59,7 +55,6 @@ namespace SVM
switch(type) switch(type)
{ {
case PORT_CODE: case PORT_CODE:
case FLAG_CODE:
loc = byte.Parse(locVal); loc = byte.Parse(locVal);
break; break;
case ADDRESS_CODE: case ADDRESS_CODE:
@@ -127,14 +122,12 @@ namespace SVM
Debug.Assert(loc <= VM.REGISTERS); Debug.Assert(loc <= VM.REGISTERS);
return vm.R[loc]; return vm.R[loc];
case MEMORY_CODE: case MEMORY_CODE:
return vm.MEM[loc]; return vm.Read(loc);
case IMMEDIATE_CODE: case IMMEDIATE_CODE:
return loc; return loc;
case FLAG_CODE:
throw new NotImplementedException();
case ADDRESS_CODE: case ADDRESS_CODE:
Debug.Assert(loc <= VM.REGISTERS); Debug.Assert(loc <= VM.REGISTERS);
return vm.MEM[vm.R[loc]]; return vm.Read(vm.R[loc]);
default: throw new Exception("Invalid location type"); default: throw new Exception("Invalid location type");
} }
} }
@@ -151,15 +144,13 @@ namespace SVM
vm.R[loc] = val; vm.R[loc] = val;
break; break;
case MEMORY_CODE: case MEMORY_CODE:
vm.MEM[loc] = (byte)(val & 0xFF); vm.Write(loc, (byte)(val & 0xFF));
break; break;
case IMMEDIATE_CODE: case IMMEDIATE_CODE:
throw new Exception("Invalid operation"); throw new Exception("Invalid operation");
case FLAG_CODE:
throw new NotImplementedException();
case ADDRESS_CODE: case ADDRESS_CODE:
Debug.Assert(loc <= VM.REGISTERS); Debug.Assert(loc <= VM.REGISTERS);
vm.MEM[vm.R[loc]] = (byte)(val & 0xFF); vm.Write(vm.R[loc], (byte)(val & 0xFF));
break; break;
default: default:
throw new Exception("Invalid location type"); throw new Exception("Invalid location type");
@@ -176,7 +167,6 @@ namespace SVM
switch(type) switch(type)
{ {
case PORT_CODE: case PORT_CODE:
case FLAG_CODE:
return string.Format("{0}{1}", DecodeType(type), loc); return string.Format("{0}{1}", DecodeType(type), loc);
case REGISTER_CODE: case REGISTER_CODE:
return string.Format("R{0}", Register.ToASM((byte)loc)); return string.Format("R{0}", Register.ToASM((byte)loc));

52
SVM/PGM/FlagTest.txt Normal file
View File

@@ -0,0 +1,52 @@
ALIAS F_CONSTS 0xFF00
ALIAS STR_ENABLED 0x100
ALIAS STR_AVAILABLE 0x110
ALIAS STR_READBLOCK 0x120
ALIAS STR_READAVAILABLE 0x130
ALIAS STR_YES 0x140
ALIAS STR_NO 0x150
ORIGIN 0
LOAD D M F_CONSTS # Read the flag into reg D
LOAD A I STR_ENABLED
CALL :WSTR
JBS D 2 :ENYES # Check for enabled
LOAD A I STR_NO # Set str to NO if enabled bit not set
JMP :ENWR
:ENYES LOAD A I STR_YES
:ENWR CALL :WSTR
CALL :WNL
LOAD A I STR_READAVAILABLE
CALL :WSTR
JBS D 4 :RAYES
LOAD A I STR_NO
JMP :RAWR
:RAYES LOAD A I STR_YES
:RAWR CALL :WSTR
CALL :WNL
HALT
:WSTR LOAD C RA
:WSTR_L LOAD A AC
JZ A :WSTR_R
SAVE A P0
INC C
JMP :WSTR_L
:WSTR_R RET
:WNL LOAD A I13
SAVE A P0
LOAD A I10
SAVE A P0
RET
MEMORY
0x100 "Enabled "
0x110 "Available "
0x120 "ReadBlock "
0x130 "ReadAvailable "
0x140 "Yes"
0x150 "No"

View File

@@ -6,19 +6,32 @@ namespace SVM.Ports
{ {
class ConsolePort : Port class ConsolePort : Port
{ {
public bool Enabled { get; set; }
public bool ReadBlock { get; set; }
public ConsolePort(VM vm) public ConsolePort(VM vm)
: base(vm) : base(vm)
{ } {
Enabled = true;
ReadBlock = true;
}
public override ushort Read() public override ushort Read()
{
if (ReadBlock || Console.KeyAvailable)
{ {
var result = Console.ReadKey(true); var result = Console.ReadKey(true);
return (byte)result.KeyChar; return (byte)result.KeyChar;
} }
return 0;
}
public override void Write(byte val) public override void Write(byte val)
{
if (Enabled)
{ {
Console.Write((char)val); Console.Write((char)val);
} }
} }
}
} }

View File

@@ -9,6 +9,7 @@
<ItemGroup> <ItemGroup>
<None Remove="PGM\CALL.txt" /> <None Remove="PGM\CALL.txt" />
<None Remove="PGM\FlagTest.txt" />
<None Remove="PGM\HELLO.txt" /> <None Remove="PGM\HELLO.txt" />
<None Remove="PGM\LOGIC.txt" /> <None Remove="PGM\LOGIC.txt" />
</ItemGroup> </ItemGroup>
@@ -17,6 +18,9 @@
<Content Include="PGM\CALL.txt"> <Content Include="PGM\CALL.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>
<Content Include="PGM\FlagTest.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="PGM\HELLO.txt"> <Content Include="PGM\HELLO.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>

View File

@@ -8,7 +8,7 @@ namespace SVM
class VM class VM
{ {
public const int REGISTERS = 4; public const int REGISTERS = 4;
public const int PORTS = 8; public const int PORTS = 255;
public const int STACKDEPTH = 16; public const int STACKDEPTH = 16;
public const int MEMSIZE = 0xFFFF; public const int MEMSIZE = 0xFFFF;
@@ -20,18 +20,23 @@ namespace SVM
public ushort[] STACK = new ushort[STACKDEPTH]; public ushort[] STACK = new ushort[STACKDEPTH];
public byte[] MEM = new byte[MEMSIZE]; public byte[] MEM = new byte[MEMSIZE];
public Port[] Ports = new Port[PORTS]; public Port[] Ports = new Port[PORTS];
public ushort FlagStart = 0xFF00;
public int CycleDelay = 0; public int CycleDelay = 0;
private Dictionary<byte, Instruction> instructions = new Dictionary<byte, Instruction>(); private Dictionary<byte, Instruction> instructions = new Dictionary<byte, Instruction>();
private Dictionary<byte, Flag> flags = new Dictionary<byte, Flag>();
public VM() public VM()
{ {
var instrs = Instruction.GetAllInstructions(); foreach(var instr in Instruction.GetAllInstructions())
foreach(var instr in instrs)
{ {
instructions.Add(instr.OP, instr); instructions.Add(instr.OP, instr);
} }
foreach(var flag in Flag.GetAllFlags())
{
flags.Add(flag.Address, flag);
}
Ports[0] = new Ports.ConsolePort(this); Ports[0] = new Ports.ConsolePort(this);
Reset(); Reset();
@@ -72,11 +77,39 @@ namespace SVM
var pc = PC; var pc = PC;
var instr = instructions[MEM[PC++]]; var instr = instructions[MEM[PC++]];
byte[] decoded = instr.Decode(this); byte[] decoded = instr.Decode(this);
Console.Write("{4:X4} | A{0:X3} B{1:X3} C{2:X3} D{3:X3} | ", R[0], R[1], R[2], R[3], pc); //Console.Write("{4:X4} | A{0:X3} B{1:X3} C{2:X3} D{3:X3} | ", R[0], R[1], R[2], R[3], pc);
Console.WriteLine("0x{0:X4} {1}", pc, instr.ToASM(decoded)); //Console.WriteLine("{0}", instr.ToASM(decoded));
instr.Exec(this, decoded); instr.Exec(this, decoded);
//Console.ReadKey(true); //Console.ReadKey(true);
} }
} }
public byte Read(ushort location)
{
if (location >= FlagStart && location < FlagStart + 0xFF)
{
byte flagAddress = (byte)(location - FlagStart);
if (flags.ContainsKey(flagAddress))
{
return flags[flagAddress].Read(this);
}
return 0;
}
return MEM[location];
}
public void Write(ushort location, byte val)
{
if (location >= FlagStart && location < FlagStart + 0xFF)
{
byte flagAddress = (byte)(location - FlagStart);
if (flags.ContainsKey(flagAddress))
{
flags[flagAddress].Write(this, val);
}
} else
{
MEM[location] = val;
}
}
} }
} }