SCAR Code:
program Emulator;
const
datafile = 'C:\program.bxe';
var
RAM: Array [0..255] of Byte; //0-63 = Program, 64-79 = Stack, 80-255 = general memory
Register: Array [0..16] of Byte;
Counter: Integer;
C_END, PC: Integer; //Program counter. TODO: Replace with register PC
OpCode: Byte;
CPUIsntRunning: Boolean;
const
//Register array locations (all here for reference)
AX = 0;
BX = 1;
CX = 2;
DX = 3;
EX = 4;
FX = 5;
GX = 6;
HX = 7;
IX = 8;
JX = 9;
KX = 10;
LX = 11;
MX = 12;
NX = 13;
OX = 14;
PX = 15;
SP = 16;
//Program is @ RAM 0-63
//Stack is @ RAM 64-79 (15 levels deep)
INIT = $00;
DIS1 = $01;
JMP = $02;
TERM = $03;
PUSH = $04;
POP = $05;
JIE = $06;
INCX = $07;
MOV = $08;
JNE = $0A;
LOAD = $0B;
STOR = $0C;
VAL = $0D;
SHLX = $0E;
SHRX = $0F;
DECX = $10;
ADD = $11;
SUB = $12;
PROD = $13;
DIVX = $14;
MODX = $15;
function nem: Byte;
begin
try
result := RAM[PC];
except
writeln('Debugtime!');
wait(40000);
end
inc(PC);
end;
procedure ReadFileIntoRAM(theFile: String);
var
hFile, i: integer;
data: byte;
begin
try
hFile := OpenFile(theFile, false);
for i := 0 to 2 do
begin
ReadFileByte(hFile, data);
case i of
0: if(data <> $53) then
RaiseException(erUnexpectedEof, 'File is not an SXE executable');
1: PC := data;
2: C_END := data;
end;
end;
i := 0;
repeat
ReadFileByte(hFile, data);
RAM[i] := data;
inc(i);
until((EndOfFile(hFile)) or (i > 63));
writeln('Program loaded (' + inttostr(i) + '/64 bytes used)');
except
writeln('Error loading executable: ' + ExceptionParam);
TerminateScript;
finally
CloseFile(hFile);
end;
end;
begin
{ ASM Instructions //TODO: Group similar instructions, ie inc/dec
INIT 0x00, InitialCounter //NOT YET IMPLEMENTED
DIS1 0x01, Register
JMP 0x02, JumpLocation
TERM 0x03 //TODO: REMOVE
PUSH 0x04, Register
POP 0x05, Register
JIE 0x06, Register, Register, JumpLocation
INC 0x07, Register
MOV 0x08, Register, Register
INP 0x09, Register //TODO: discard? [INPut]
JNE 0x0A, Register, Register, JumpLocation
LOAD 0x0B, Register, RAM
STOR 0x0C, RAM, Register
VAL 0x0D, Register, Value
SHL 0x0E, Register
SHR 0x0F, Register
DEC 0x10, Register
ADD 0x11, Register, Register, Register | A = B + C
SUB 0x12, Register, Register, Register | A = B - C
PROD 0x13, Register, Register, Register | A = B * C
DIV 0x14, Register, Register, Register | A = B / C
MOD 0x15, Register, Register, Register | A = B % C
AND 0xXX, Register, Register //TODO
NAND 0xXX, Register, Register
OR 0xXX, Register, Register
NOR 0xXX, Register, Register
XOR 0xXX, Register, Register
}
ClearReport;
readFileIntoRAM(datafile);
Register[SP] := 79;
repeat
OpCode := nem;
case OpCode of
INIT:
CPUIsntRunning := false;
DIS1:
AddToReport(inttostr(Register[nem]));
JMP:
PC := nem;
TERM:
CPUIsntRunning := true;
POP:
begin
Register[nem] := RAM[Register[SP]];
inc(Register[SP]);
end;
PUSH:
begin
dec(Register[SP]);
RAM[Register[SP]] := Register[nem];
end;
JIE:
if(Register[nem] = Register[nem])then
PC := nem
else
nem;
JNE:
if(Register[nem] <> Register[nem])then
PC := nem
else
nem;
INCX:
inc(Register[nem]);
MOV:
Register[nem] := Register[nem];
LOAD:
Register[nem] := RAM[nem + 80];
STOR:
RAM[nem + 80] := Register[nem];
VAL:
Register[nem] := nem;
SHLX:
Register[nem] := Register[RAM[PC - 1]] shl 1;
SHRX:
Register[nem] := Register[RAM[PC - 1]] shr 1;
DECX:
dec(Register[nem]);
ADD:
Register[nem] := Register[nem] + Register[nem];
SUB:
Register[nem] := Register[nem] - Register[nem];
PROD:
Register[nem] := Register[nem] * Register[nem];
DIVX:
Register[nem] := Register[nem] / Register[nem];
MODX:
Register[nem] := Register[nem] mod Register[nem];
else
writeln('INVALID OPCODE: ' + inttostr(OPCODE));
end;
inc(Counter);
// writeln('Line ' + inttostr(counter));
until((CPUIsntRunning) or (PC = C_END))
end.
SCAR Code:
program Assembler; //TODO: Rewrite this.
{
[Planned] Executable layout
[Code header]
0x52
Code Start Address
Code End Address
[Data segment]
todo..
[Code segment]
Instructions
}
const
SourceFile = 'C:\program'; //Input file is .asm, output file is .bxe
var
timer: integer;
prog: string;
progWords: TStringArray;
initdata, code: Array of Byte;
labelList: Array of record
address: integer; name: string;
end;
labelUsages: Array of record
address: integer; labelname: string;
end;
function ParseWords(data: string): TStringArray;
var
i, j, k: integer;
begin
data := Replace(data, chr(13) + chr(10), ' ');
SetLength(result, length(data) / 8);
k := 1;
for i := 1 to length(data) do
begin
if(k > 0) then
begin
if((data[i] = ' ') or (i = length(data))) then
begin
if(j > high(result))then
SetLength(result, j + 15);
if(i = length(data)) then
inc(i);
result[j] := copy(data, k, i - k);
inc(j);
k := -1;
end;
end
else if(data[i] <> ' ') then
k := i;
end;
SetLength(result, j);
end;
procedure AddToLabelList(codeAddress: integer; labelName: String);
begin
SetLength(labelList, Length(LabelList) + 1);
labelList[high(LabelList)].address := codeAddress;
labelList[high(LabelList)].name := Copy(labelName, 1, length(labelName) - 1);
end;
procedure AddToLabelCalls(codeAddress: integer; labelName: String);
begin
SetLength(labelUsages, Length(labelUsages) + 1);
labelUsages[high(labelUsages)].address := codeAddress;
labelUsages[high(labelUsages)].labelName := labelName;
end;
function ParseInstructions(data: TStringArray): Array of Byte;
var
InstructionList: Array of String;
Registers: Array of String;
Code: Array of Byte;
done: boolean;
i, j, r: integer;
begin
Registers := ['AX', 'BX', 'CX', 'DX', 'EX', 'FX', 'GX', 'HX', 'IX',
'JX', 'KX', 'LX', 'MX', 'NX', 'OX', 'PX', 'SP'];
InstructionList := ['INIT', 'DIS1', 'JMP', 'TERM', 'PUSH', 'POP',
'JIE', 'INC', 'MOV', 'INP', 'JNE', 'LOAD',
'STOR', 'VAL', 'SHL', 'SHR', 'DEC', 'ADD', 'SUB',
'PROD', 'DIV', 'MOD'];
SetLength(Code, Length(data));
for i := 0 to high(data) do
begin
done := false;
if(TrimNumbers(data[i]) = '') then
begin
Code[r] := StrToInt(data[i]);
inc(r);
done := true;
end;
if(done) then
Continue;
for j := 0 to high(InstructionList) do //Process instructions
if(data[i] = InstructionList[j]) then
begin
Code[r] := j;
inc(r);
done := true;
break;
end;
if(done) then
Continue;
for j := 0 to high(Registers) do
if(data[i] = Registers[j]) then
begin
Code[r] := j;
inc(r);
done := true;
break;
end;
if(done) then
Continue;
if(data[i][length(data[i])] = ':') then //Define labels
AddToLabelList(r, data[i])
else
begin
AddToLabelCalls(r, data[i]); //Process label calls
Code[r] := -1;
inc(r);
end;
end;
SetLength(Code, r);
result := Code;
end;
procedure ProcessLabels(var data: Array of Byte);
var
i, j: integer;
begin
for i := 0 to high(labelUsages) do
for j := 0 to high(labelList) do
if(LabelUsages[i].LabelName = labelList[j].name) then
begin
if(data[labelUsages[i].address] = 255) then
data[labelUsages[i].address] := labelList[j].address //+ length(initdata)
else
writeln('debug: your assembler is broken ;)');
break;
end;
end;
function ReadSource: string;
var
h: integer;
begin
h := OpenFile(SourceFile + '.asm', false);
ReadFileString(h, result, FileSize(h));
CloseFile(h);
end;
procedure WriteFile(data: Array of Byte);
var
h, i: integer;
begin
h := RewriteFile(SourceFile + '.bxe', true);
for i := 0 to high(initdata) do
WriteFileByte(h, initdata[i]);
for i := 0 to high(data) do
WriteFileByte(h, data[i]);
CloseFile(h);
end;
begin
SetLength(InitData, 3);
InitData[0] := $53;
timer := GetSystemTime;
prog := readSource;
progWords := ParseWords(prog);
code := ParseInstructions(progWords);
processLabels(code);
InitData[1] := 0;
InitData[2] := length(code);
writeFile(code);
writeln('Assembled in ' + inttostr(GetSystemTime - timer) + ' ms');
end.