組譯器(4)參考老師的教學
http://ccckmit.wikidot.com/code:assembler
// 共有兩個檔案
// 程式檔 : SicAssembler.cs
// 測試檔 : SUM.sic
// ------------------------------ SicAssembler.cs ------------------------------------
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;
using Microsoft.VisualBasic;
namespace SICAssembler
{
public class SIC
{
static void Main(string[] args)
{
SicAssembler asm = new SicAssembler();
asm.parse(args[0]);
asm.pass2();
SicMemory memory = new SicMemory();
SicLoader.load(asm.codes, memory);
SicVirtualMachine vm = new SicVirtualMachine(memory, 0);
vm.run();
}
}
public class SicVirtualMachine
{
public static OpTable opTable = new OpTable();
SicMemory mem;
int A = 0, X = 0, L = 0, SW = 0, PC = 0;
public SicVirtualMachine(SicMemory pMemory, int pCounter) {
mem = pMemory;
PC = pCounter;
}
public void dump()
{
Debug.log("A=" + A + " X=" + X + " L=" + L + " SW=" + SW + " PC=" + PC);
}
public void run() {
while (runCode())
{
}
dump();
}
public int compare(int a, int b)
{
if (a
>
b) return 1;
else if (a
<
b) return -1;
else return 0;
}
public bool runCode()
{
byte op = mem.memory[PC];
byte a1 = mem.memory[PC + 1];
byte a2 = mem.memory[PC + 2];
int m = ((a1
&
0x7F)
<
<
8) + a2;
int word = mem.getWord(m);
String opStr = String.Format("{0:X2}", op);
Debug.log(opTable.codeToOp[opStr]+"\tmem("+String.Format("{0:X2}", m)+")\t= "+word);
switch (op) {
case 0x18: // ADD m
A += word;
break;
case 0x40: // AND m
A
&
= word;
break;
case 0x28: // COMP m
SW = compare(A, word);
break;
case 0x24: // DIV m
A /= word;
break;
case 0x3C: // J m
PC = m;
break;
case 0x30: // JEQ m
if (SW == 0) PC = m;
break;
case 0x34: // JGT m
if (SW
>
0) PC = m;
break;
case 0x38: // JLT m
if (SW
<
0) PC = m;
break;
case 0x48: // JSUB m
L = PC;
PC = m;
break;
case 0x00: // LDA m
A = word;
break;
case 0x50: // LDCH m
A = (A
&
0xFF0) | mem.memory[m];
break;
case 0x04: // LDX m
X = word;
break;
case 0x20: // MUL m
A *= word;
break;
case 0x44: // OR m
A |= word;
break;
// case 0xD8: // RD m
case 0x4C: // RSUB
if (L == 0) return false;
PC = L;
break;
case 0x0C: // STA m
mem.setWord(A, m);
break;
case 0x54: // STCH m
mem.memory[m] = (byte)A;
break;
case 0x10: // STX m
mem.setWord(X, m);
break;
case 0x1C: // SUB m
A -= word;
break;
// case 0xB0: // SVC x
// case 0xE0: // TD m
// break;
case 0x2C: // TIX m
X++;
SW = compare(X, word);
break;
// case 0xDC: // WD m
// break;
default:
Debug.log(String.Format("Error : op={0:X2} not found !", op));
break;
}
PC += 3;
return true;
}
}
public class SicLoader
{
public static void load(CodeList codes, SicMemory m)
{
foreach (Code code in codes) {
for (int i = 0; i
<
code.objCode.Length; i+=2)
{
String hex = code.objCode;
int offset = code.offset + i/2;
byte b = Byte.Parse(hex.Substring(i, 2), System.Globalization.NumberStyles.AllowHexSpecifier);
m.memory[offset] = b;
Debug.log(String.Format("{0:X2}:{1:X2}", offset, b));
}
}
}
}
public class SicMemory
{
public byte[] memory = new byte[32768];
public SicMemory() {
for (int i = 0; i
<
memory.Length; i++)
memory[i] = 0;
}
public void setWord(int word, int offset)
{
memory[offset] = (byte)(word
>
>
16);
memory[offset + 1] = (byte)(word
>
>
8);
memory[offset + 2] = (byte)(word);
}
public int getWord(int offset)
{
return memory[offset]
<
<
16 | memory[offset + 1]
<
<
8 | memory[offset + 2];
}
}
public class SicAssembler
{
public static OpTable opTable = new OpTable();
public CodeList codes = new CodeList();
public SymbolTable symbolTable = new SymbolTable();
public void parse(String pFileName)
{
Debug.log("======================= PARSE ================================");
String text = IO.fileToText(pFileName);
text = text.Replace('\r', ' ');
String[] lines = text.Split('\n');
int offset = 0;
for (int i = 0; i
<
lines.Length; i++)
{
String line = lines[i];
if (line.Trim().Length == 0) continue;
if (line.StartsWith(".")) continue;
Code code = new Code(line, opTable);
code.lineNumber = i;
if (code.offset
>
= 0)
offset = code.offset;
else
code.offset = offset;
Debug.log(code.ToString());
if (code.label.Length
>
0)
symbolTable.Add(code.label, code);
codes.Add(code);
offset = offset + code.codeSize;
}
}
public void pass2()
{
Debug.log("======================= PASS2 ================================");
for (int i = 0; i
<
codes.Count; i++)
{
Code code = codes[i];
if (!code.isPseudo)
{
if (code.arg.Length == 0)
code.objCode += "0000";
else
{
if (symbolTable.ContainsKey(code.arg))
{
int argCode = symbolTable[code.arg].offset;
if (code.x == 'X')
argCode += 0x8000;
code.objCode += String.Format("{0:X4}", argCode);
}
else Debug.error("ARG " + code.arg + " not found !");
}
}
Debug.log(code.ToString());
}
}
}
public class OpTable {
public Dictionary
<
String, String
>
opToCode = new Dictionary
<
String, String
>
();
public Dictionary
<
String, String
>
codeToOp = new Dictionary
<
String, String
>
();
public static String opCodes = "ADD=18,ADDF=58,ADDR=90,AND=40,CLEAR=B4,COMP=28,COMPF=88,DIV=24,DIVF=64,DIVR=9C,FIX=C4," +
"FLOAT=C0,HIO=F4,J=3C,JEQ=30,JGT=34,JLT=38,JSUB=48,LDA=00,LDB=68,LDCH=50,LDF=70,LDL=08," +
"LDS=6C,LDT=74,LDX=04,LPS=D0,MUL=20,MULF=60,MULR=98,NORM=C8,OR=44,RD=D8,RMO=AC,RSUB=4C," +
"SHIFTL=A4,SHIFTR=A8,SIO=F0,SSK=EC,STA=0C,STB=78,STCH=54,STF=80,STI=D4,STL=14,STS=7C,STSW=E8," +
"STT=84,STX=10,SUB=1C,SUBF=5C,SUBR=94,SVC=B0,TD=E0,TIO=F8,TIX=2C,TIXR=B8,WD=DC," +
"RESB=,RESW=,BYTE=,WORD=,START=,END=";
public OpTable() {
Debug.log("======================= OP TABLE ================================");
String[] records = opCodes.Split(',');
for (int i = 0; i
<
records.Length; i++)
{
String[] tokens = records[i].Split('=');
opToCode.Add(tokens[0], tokens[1]);
if (tokens.Length
>
1
&
&
tokens[1].Length
>
0)
codeToOp.Add(tokens[1], tokens[0]);
Debug.log(tokens[0] + "\t" + tokens[1]);
}
}
}
public class SymbolTable : Dictionary
<
String, Code
>
{ }
public class CodeList : List
<
Code
>
{ }
public class Code
{
public static String PSEUDO_OP = ",RESB,RESW,BYTE,WORD,START,END,";
public String label = "", op = "", arg = "";
public char x = ' ';
public String objCode = null;
public int offset = -1;
public int codeSize = 0;
public int lineNumber = 0;
public bool isPseudo;
public Code(String line, OpTable opTable)
{
String[] tokens = line.Split('\t');
int argIdx;
if (opTable.opToCode.ContainsKey(tokens[0]))
{
op = tokens[0].Trim();
argIdx = 1;
}
else
{
label = tokens[0].Trim();
op = tokens[1].Trim();
argIdx = 2;
}
if (argIdx
<
tokens.Length)
{
String argStr = tokens[argIdx];
String[] args = argStr.Split(',');
arg = args[0].Trim();
if (args.Length
>
1)
if (args[1].Trim().Equals("X"))
x = 'X';
}
objCode = opTable.opToCode[op];
if (objCode == null) Debug.error("op:" + op + " not found!");
if (op.Equals("BYTE"))
{
if (arg.StartsWith("C'")) // EOF BYTE C'EOF'
{
String str = arg.Substring(2, arg.Length - 3);
codeSize = str.Length;
objCode = "";
for (int si = 0; si
<
str.Length; si++)
{
char ch = str[si];
int chInt = ch;
objCode += String.Format("{0:x2}", (uint) System.Convert.ToUInt32(chInt.ToString()));
}
objCode = objCode.ToUpper();
}
else if (arg.StartsWith("X'")) // OUTPUT BYTE X'05'
{
String str = arg.Substring(2, arg.Length - 3);
objCode = str;
codeSize = str.Length / 2;
}
else // THREE BYTE 3
codeSize = 1;
}
else if (op.Equals("WORD")) // FIVE WORD 5
{
codeSize = 3;
objCode = String.Format("{0:X6}", Int32.Parse(arg));
}
else if (op.Equals("RESB")) // BUFFER RESB 1024
codeSize = Int32.Parse(arg) * 1;
else if (op.Equals("RESW")) // LENGTH RESW 1
codeSize = Int32.Parse(arg) * 3;
else if (op.Equals("START")) // COPY START 1000
offset = Int32.Parse(arg, System.Globalization.NumberStyles.AllowHexSpecifier);
else if (op.Equals("END"))
codeSize = 0;
else
codeSize = 3; // SIC 中一個指令佔 3 byte
isPseudo = (PSEUDO_OP.IndexOf(","+op+",")
>
= 0);
}
public override String ToString()
{
return lineNumber + "\t" + String.Format("{0:X}", offset) + "\t" + label + "\t" + op + "\t" + arg + "\t" + x+"\t"+objCode;
}
}
public class IO
{
// 讀取文字檔,以字串形式傳回。
public static String fileToText(String filePath)
{
StreamReader file = new StreamReader(filePath);
String text = file.ReadToEnd();
file.Close();
return text;
}
}
class Debug
{
public static void error(String msg)
{
Debug.log(msg);
throw new Exception(msg);
}
public static void log(String msg)
{
Console.WriteLine(msg);
}
}
}