unit Simx86p;
interface
uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
Forms, Dialogs, Patterns, Menus, StdCtrls, TabNotBk, ExtCtrls, VBXCtrl,
Switch, Spin, GetInput, Printers;
type
TMem = array [0..$ffef] of byte;
TMemPtr = ^TMem;
TSIMx86Form = class(TForm)
Simx86Pages: TTabbedNotebook;
SourceCode: TMemo;
MainMenu: TMainMenu;
File1: TMenuItem;
Edit: TMenuItem;
New: TMenuItem;
Open: TMenuItem;
Save: TMenuItem;
SaveAs: TMenuItem;
Cut: TMenuItem;
Copy: TMenuItem;
Paste: TMenuItem;
Delete: TMenuItem;
EditBreak: TMenuItem;
BeforeQuit: TMenuItem;
PrintMenuItem: TMenuItem;
SelectAll: TMenuItem;
OpenDialog: TOpenDialog;
SaveDialog: TSaveDialog;
StartAdrs: TEdit;
StartAdrsLbl: TLabel;
ASMbtn: TButton;
Mem01: TEdit;
Mem02: TEdit;
Mem03: TEdit;
Mem04: TEdit;
Mem05: TEdit;
Mem00: TEdit;
Mem06: TEdit;
Mem07: TEdit;
AdrsEntry: TEdit;
Label0: TLabel;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
Label5: TLabel;
Label6: TLabel;
Label7: TLabel;
Lbl8: TLabel;
Lbl10: TLabel;
Lbl18: TLabel;
Lbl20: TLabel;
Lbl28: TLabel;
Lbl30: TLabel;
Lbl38: TLabel;
Mem10: TEdit;
Mem11: TEdit;
Mem12: TEdit;
Mem13: TEdit;
Mem14: TEdit;
Mem15: TEdit;
Mem16: TEdit;
Mem17: TEdit;
Mem27: TEdit;
Mem26: TEdit;
Mem25: TEdit;
Mem24: TEdit;
Mem23: TEdit;
Mem22: TEdit;
Mem21: TEdit;
Mem20: TEdit;
Mem30: TEdit;
Mem31: TEdit;
Mem32: TEdit;
Mem33: TEdit;
Mem34: TEdit;
Mem35: TEdit;
Mem36: TEdit;
Mem37: TEdit;
Mem47: TEdit;
Mem46: TEdit;
Mem45: TEdit;
Mem44: TEdit;
Mem43: TEdit;
Mem42: TEdit;
Mem41: TEdit;
Mem40: TEdit;
Mem50: TEdit;
Mem51: TEdit;
Mem52: TEdit;
Mem53: TEdit;
Mem54: TEdit;
Mem55: TEdit;
Mem56: TEdit;
Mem57: TEdit;
Mem67: TEdit;
Mem66: TEdit;
Mem65: TEdit;
Mem64: TEdit;
Mem63: TEdit;
Mem62: TEdit;
Mem61: TEdit;
Mem60: TEdit;
Mem70: TEdit;
Mem71: TEdit;
Mem72: TEdit;
Mem73: TEdit;
Mem74: TEdit;
Mem75: TEdit;
Mem76: TEdit;
Mem77: TEdit;
IntVect: TEdit;
IntVectLbl: TLabel;
ResetVectLbl: TLabel;
ResetVect: TEdit;
Label8: TLabel;
DisAsm: TListBox;
Output: TListBox;
InPort0: TBiSwitch;
InPort2: TBiSwitch;
InPort4: TBiSwitch;
InPort6: TBiSwitch;
OutPort8: TShape;
OutPortA: TShape;
OutPortC: TShape;
OutPortE: TShape;
FFF8Lbl: TLabel;
FFFALbl: TLabel;
FFFCLbl: TLabel;
FFFELbl: TLabel;
RunBtn: TButton;
StepBtn: TButton;
HaltBtn: TButton;
InterruptBtn: TButton;
OutputLbl: TLabel;
RunningLite: TPanel;
AXValue: TEdit;
AXLbl: TLabel;
BXValue: TEdit;
DXValue: TEdit;
CXValue: TEdit;
IPValue: TEdit;
BXLbl: TLabel;
CXLbl: TLabel;
DXLbl: TLabel;
IPLbl: TLabel;
Instruction: TLabel;
DisAsmAdrs: TEdit;
EqualFlag: TCheckBox;
LessThanFlag: TCheckBox;
ResetBtn: TButton;
Input: TListBox;
InputLbl: TLabel;
SpinButton: TSpinButton;
ClrMemBtn: TButton;
PrintDialog: TPrintDialog;
N1: TMenuItem;
Quit: TMenuItem;
procedure QuitClick(Sender: TObject);
procedure CutClick(Sender: TObject);
procedure CopyClick(Sender: TObject);
procedure PasteClick(Sender: TObject);
procedure DeleteClick(Sender: TObject);
procedure SelectAllClick(Sender: TObject);
procedure NewClick(Sender: TObject);
procedure OpenClick(Sender: TObject);
procedure SaveAsClick(Sender: TObject);
procedure HexChange(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure AdrsEntryChange(Sender: TObject);
procedure StartAdrsChange(Sender: TObject);
procedure ASMbtnClick(Sender: TObject);
procedure Simx86PagesChange(Sender: TObject; NewTab: Integer;
var AllowChange: Boolean);
procedure ClrMemBtnClick(Sender: TObject);
procedure DisAsmAdrsChange(Sender: TObject);
procedure SpinButtonDownClick(Sender: TObject);
procedure SpinButtonUpClick(Sender: TObject);
procedure ResetBtnClick(Sender: TObject);
procedure RunBtnClick(Sender: TObject);
procedure HaltBtnClick(Sender: TObject);
procedure InterruptBtnClick(Sender: TObject);
procedure IntVectChange(Sender: TObject);
procedure IPValueChange(Sender: TObject);
procedure StepBtnClick(Sender: TObject);
procedure PrintMenuItemClick(Sender: TObject);
procedure SaveClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
SIMx86Form: TSIMx86Form;
MemEntry: array[0..7,0..7] of TEdit;
implementation
type
TSymPtr = ^TSym;
TSym = record
value:word;
defined:boolean;
end;
const
MaxCodeAdrs = 4095;
var
HasOpcode:Boolean;
Opcode:word;
HasReg:Boolean;
RegCode:word;
HasOperand:Boolean;
OperandCode:word;
HasValue:Boolean;
OperandValue:word;
StoreMem:boolean;
Halted:boolean;
Running:boolean;
PendingInt:boolean;
InInt:boolean;
IntAdrs:word;
Val:byte;
AX: word;
BX: word;
CX: word;
DX: word;
IP: word;
LineNum:integer;
Adrs:word;
MemAdrs:word;
MemWS:integer;
AbortAsm:Boolean;
NoError:Boolean;
Memory: TMemPtr;
SymTbl: array ['A'..'Z'] of TSym;
SaveAX:word;
SaveBX:word;
SaveCX:word;
SaveDX:word;
SaveIP:word;
SaveEqual:boolean;
SaveLess:boolean;
Reg:byte;
RegMem:byte;
Operation:byte;
InstrSize:word;
Op1:^word;
Op2v:word;
offset:word;
Filename:string;
{$F+}
function ProcessLbl(Pat:TPatPtr):boolean; forward;
function GetLbl(Pat:TPatPtr):boolean; forward;
function ConvertHex(Pat:TPatPtr):boolean; forward;
procedure SetJmp(Pat:TPatPtr); forward;
procedure SetJa(Pat:TPatPtr); forward;
procedure SetJae(Pat:TPatPtr); forward;
procedure SetJb(Pat:TPatPtr); forward;
procedure SetJbe(Pat:TPatPtr); forward;
procedure SetJe(Pat:TPatPtr); forward;
procedure SetJne(Pat:TPatPtr); forward;
procedure SetNot(Pat:TPatPtr); forward;
procedure SetAnd(Pat:TPatPtr); forward;
procedure SetOr(Pat:TPatPtr); forward;
procedure SetCmp(Pat:TPatPtr); forward;
procedure SetSub(Pat:TPatPtr); forward;
procedure SetAdd(Pat:TPatPtr); forward;
procedure SetMovReg(Pat:TPatPtr); forward;
procedure SetMovMem(Pat:TPatPtr); forward;
procedure SetIret(Pat:TPatPtr); forward;
procedure SetHalt(Pat:TPatPtr); forward;
procedure SetBrk(Pat:TPatPtr); forward;
procedure SetPut(Pat:TPatPtr); forward;
procedure SetGet(Pat:TPatPtr); forward;
procedure SetAX(Pat:TPatPtr); forward;
procedure SetBX(Pat:TPatPtr); forward;
procedure SetCX(Pat:TPatPtr); forward;
procedure SetDX(Pat:TPatPtr); forward;
procedure SetAX2(Pat:TPatPtr); forward;
procedure SetBX2(Pat:TPatPtr); forward;
procedure SetCX2(Pat:TPatPtr); forward;
procedure SetDX2(Pat:TPatPtr); forward;
procedure SetBXInd(Pat:TPatPtr); forward;
procedure SetBXIndx(Pat:TPatPtr); forward;
procedure SetABS(Pat:TPatPtr); forward;
procedure SetImm(Pat:TPatPtr); forward;
{$F-}
const
{ WS1- Matches a string containing one or more white- }
{ space characters. }
WS1:TPattern = (mf:OneOrMoreCset; m:(cset:[' ',#9]);
Next:NIL; Alt:NIL; Success:NIL);
{ WS0- Matches a string containing zero or more white- }
{ space characters. }
WS0:TPattern=(mf:SpanCset; m:(cset:[' ',#9]);
Next:NIL; Alt:NIL; Success:NIL);
{ A Pattern that matches whitespace at the end of a line }
SkipToEOS:TPattern=(mf:EOS; m:(ch:' ');
Next:NIL; Alt:NIL; Success:NIL);
WSeoln:TPattern=(mf:SpanCset; m:(cset:[' ',#9]);
Next:@SkipToEOS; Alt:NIL; Success:NIL);
{ Match an x86 register mode here. }
TryDX:Tpattern=(mf:Matchistr; m:(str:'DX');
Next:NIL; Alt:NIL; Success:SetDX);
TryCX:Tpattern=(mf:Matchistr; m:(str:'CX');
Next:NIL; Alt:@TryDX; Success:SetCX);
TryBX:Tpattern=(mf:Matchistr; m:(str:'BX');
Next:NIL; Alt:@TryCX; Success:SetBX);
TryReg:Tpattern=(mf:Matchistr; m:(str:'AX');
Next:NIL; Alt:@TryBX; Success:SetAX);
{ Match an x86 addressing mode here }
TryImm:TPattern=( mf:ConvertHex; m:(ch:' ');
Next:@WSEoln; Alt:NIL; Success:SetImm);
TryDX2:Tpattern=(mf:Matchistr; m:(str:'DX');
Next:@WSeoln; Alt:@TryImm; Success:SetDX2);
TryCX2:Tpattern=(mf:Matchistr; m:(str:'CX');
Next:@WSeoln; Alt:@TryDX2; Success:SetCX2);
TryBX2:Tpattern=(mf:Matchistr; m:(str:'BX');
Next:@WSeoln; Alt:@TryCX2; Success:SetBX2);
TryReg2:Tpattern=(mf:Matchistr; m:(str:'AX');
Next:@WSeoln; Alt:@TryBX2; Success:SetAX2);
BXBrack:TPattern=( mf:MatchChar; m:(ch:']');
Next:NIL; Alt:NIL; Success:NIL);
BXBrackWS:TPattern=( mf:SpanCset; m:(cset:[' ',#9]);
Next:@BXBrack; Alt:NIL; Success:NIL);
BXEnd:TPattern=( mf:MatchiStr; m:(str:'BX');
Next:@BXBrackWS; Alt:NIL; Success:NIL);
TryABS:TPattern=( mf:Succeed; m:(ch:' ');
Next:@BXBrackWS; Alt:NIL; Success:SetABS);
BXPlus:TPattern=( mf:MatchChar; m:(ch:'+');
Next:@BXEnd; Alt:@TryABS; Success:SetBXIndx);
BXPlusWS:TPattern=( mf:SpanCset; m:(cset:[' ',#9]);
Next:@BXPlus; Alt:NIL; Success:NIL);
BXIndex:TPattern=( mf:ConvertHex; m:(ch:' ');
Next:@BXPlusWS; Alt:@BXEnd; Success:NIL);
BXBracket:TPattern=( mf:MatchiStr; m:(str:'BX');
Next:@BXBrackWS; Alt:@BXIndex; Success:SetBXInd);
BXIndWS:TPattern=(mf:SpanCset; m:(cset:[' ',#9]);
Next:@BXBracket; Alt:NIL; Success:NIL);
DoMem:TPattern=( mf:MatchChar; m:(ch:'[');
Next:@BXIndWS; Alt:@TryReg2; Success:NIL);
{ Generic Two-operand instructions }
TryOr:TPattern=(mf:MatchiStr; m:(str:'OR');
Next:NIL; Alt:NIL; Success:SetOr);
TryAnd:TPattern=(mf:MatchiStr; m:(str:'AND');
Next:NIL; Alt:@TryOr; Success:SetAnd);
TryCmp:TPattern=(mf:MatchiStr; m:(str:'CMP');
Next:NIL; Alt:@TryAnd; Success:SetCmp);
TrySub:TPattern=(mf:MatchiStr; m:(str:'SUB');
Next:NIL; Alt:@TryCmp; Success:SetSub);
TryAdd:TPattern=( mf:MatchiStr; m:(str:'ADD');
Next:NIL; Alt:@TrySub; Success:SetAdd);
{ Handle label definitions at the beginning of the line }
Lbl:TPattern=(mf:ProcessLbl; m:(ch:' ');
Next:NIL; Alt:NIL; Success:NIL);
{ A statement may be one of the following: }
{ }
{ 1: A Blank Line. }
{ 2: An optional label in column 1 followed by an }
{ instruction. }
{ 3: Whitespace followed by an instruction. }
{ 4: An instruction starting in column 1. }
{ }
{ The following patterns match one of the above. }
{ Zero-Operand Instructions here: }
TryBrk:TPattern=( mf:MatchiStr; m:(str:'BRK');
Next:@WSeoln; Alt:NIL; Success:SetBrk);
TryIRet:TPattern=( mf:MatchiStr; m:(str:'IRET');
Next:@WSeoln; Alt:@TryBrk; Success:SetIret);
TryHalt:TPattern=( mf:MatchiStr; m:(str:'HALT');
Next:@WSeoln; Alt:@TryIRet; Success:SetHalt);
TryPut:TPattern=( mf:MatchiStr; m:(str:'PUT');
Next:@WSeoln; Alt:@TryHalt; Success:SetPut);
TryGet:TPattern=( mf:MatchiStr; m:(str:'GET');
Next:@WSeoln; Alt:@TryPut; Success:SetGet);
{ Jump Instructions here: }
JmpLbl2:TPattern=(mf:GetLbl; m:(ch:' ');
Next:NIL; Alt:NIL; Success:NIL);
JmpLbl:TPattern=(mf:OneOrMoreCset; m:(cset:[' ',#9]);
Next:@JmpLbl2; Alt:NIL; Success:NIL);
TryJne:TPattern=(mf:MatchiStr; m:(str:'JNE');
Next:@JmpLbl; Alt:@TryGet; Success:SetJne);
TryJe:TPattern=(mf:MatchiStr; m:(str:'JE');
Next:@JmpLbl; Alt:@TryJne; Success:SetJe);
TryJb:TPattern=(mf:MatchiStr; m:(str:'JB');
Next:@JmpLbl; Alt:@TryJe; Success:SetJb);
TryJbe:TPattern=(mf:MatchiStr; m:(str:'JBE');
Next:@JmpLbl; Alt:@TryJb; Success:SetJbe);
TryJa:TPattern=(mf:MatchiStr; m:(str:'JA');
Next:@JmpLbl; Alt:@TryJbe; Success:SetJa);
TryJae:TPattern=(mf:MatchiStr; m:(str:'JAE');
Next:@JmpLbl; Alt:@TryJa; Success:SetJae);
TryJmp:TPattern=(mf:MatchiStr; m:(str:'JMP');
Next:@JmpLbl; Alt:@TryJae; Success:SetJmp);
{ not reg/mem here: }
GenMemMode:TPattern=( mf:MatchSub; m:(Pat:@DoMem);
Next:@WSeoln; Alt:NIL; Success:NIL);
NotWS:TPattern=(mf:SpanCset; m:(cset:[' ',#9]);
Next:@GenMemMode; Alt:NIL; Success:NIL);
TryNotInstr:TPattern=( mf:MatchiStr; m:(str:'NOT');
Next:@NotWS; Alt:@TryJmp; Success:SetNot);
{ instr reg, mem here: }
WSComma2:TPattern=( mf:SpanCset; m:(cset:[' ',',',#9]);
Next:@GenMemMode; Alt:NIL; Success:NIL);
GenRegMem:TPattern=(mf:MatchSub; m:(Pat:@TryReg);
Next:@WSComma2; Alt:NIL; Success:NIL);
InstrWS:TPattern=(mf:SpanCset; m:(cset:[' ',#9]);
Next:@GenRegMem; Alt:NIL; Success:NIL);
TryGeneric:TPattern=( mf:MatchSub; m:(Pat:@TryAdd);
Next:@InstrWS; Alt:@TryNotInstr; Success:NIL);
{ mov mem, reg here: }
MovReg:TPattern=(mf:MatchSub; m:(Pat:@TryReg);
Next:@WSeoln; Alt:NIL; Success:SetMovMem);
WSComma3:TPattern=( mf:SpanCset; m:(cset:[' ',',',#9]);
Next:@MovReg; Alt:NIL; Success:NIL);
MemReg:TPattern=( mf:MatchSub; m:(Pat:@DoMem);
Next:@WSComma3; Alt:NIL; Success:NIL);
{ mov reg, mem here: }
MemMode:TPattern=( mf:MatchSub; m:(Pat:@DoMem);
Next:@WSeoln; Alt:NIL; Success:SetMovReg);
WSComma:TPattern=( mf:SpanCset; m:(cset:[' ',',',#9]);
Next:@MemMode; Alt:NIL; Success:NIL);
RgMem:TPattern=(mf:MatchSub; m:(Pat:@TryReg);
Next:@WSComma; Alt:@MemReg; Success:NIL);
{ Generic mov here: }
MovWS:TPattern=(mf:SpanCset; m:(cset:[' ',#9]);
Next:@RgMem; Alt:NIL; Success:NIL);
TryMnemonic:TPattern=(mf:MatchiStr; m:(str:'MOV');
Next:@MovWS; Alt:@TryGeneric; Success:NIL);
TryEOS:TPattern=(mf:EOS; m:(ch:' ');
Next:NIL; Alt:@TryMnemonic; Success:NIL);
TryWS:TPattern =(mf:SpanCset; m:(cset:[' ',#9]);
Next:@TryEOS; Alt:NIL; Success:NIL);
stmt:TPattern = (mf:MatchSub; m:(Pat:@Lbl);
Next:@TryMnemonic; Alt:@TryWS; Success:NIL);
{ System initialization }
procedure TSIMx86Form.FormCreate(Sender: TObject);
var i: word;
ch: char;
begin
{ Allocate Storage for the x86 memory space }
system.new(Memory);
{ Zero out the allocated memory }
for i := 0 to $ffef do
Memory^[i] := 0;
MemAdrs := 0;
MemWS := 0;
IntAdrs := $FFFF;
Adrs := 0;
AX := 0;
BX := 0;
CX := 0;
DX := 0;
IP := 0;
MemEntry[0,0] := Mem00;
MemEntry[0,1] := Mem01;
MemEntry[0,2] := Mem02;
MemEntry[0,3] := Mem03;
MemEntry[0,4] := Mem04;
MemEntry[0,5] := Mem05;
MemEntry[0,6] := Mem06;
MemEntry[0,7] := Mem07;
MemEntry[1,0] := Mem10;
MemEntry[1,1] := Mem11;
MemEntry[1,2] := Mem12;
MemEntry[1,3] := Mem13;
MemEntry[1,4] := Mem14;
MemEntry[1,5] := Mem15;
MemEntry[1,6] := Mem16;
MemEntry[1,7] := Mem17;
MemEntry[2,0] := Mem20;
MemEntry[2,1] := Mem21;
MemEntry[2,2] := Mem22;
MemEntry[2,3] := Mem23;
MemEntry[2,4] := Mem24;
MemEntry[2,5] := Mem25;
MemEntry[2,6] := Mem26;
MemEntry[2,7] := Mem27;
MemEntry[3,0] := Mem30;
MemEntry[3,1] := Mem31;
MemEntry[3,2] := Mem32;
MemEntry[3,3] := Mem33;
MemEntry[3,4] := Mem34;
MemEntry[3,5] := Mem35;
MemEntry[3,6] := Mem36;
MemEntry[3,7] := Mem37;
MemEntry[4,0] := Mem40;
MemEntry[4,1] := Mem41;
MemEntry[4,2] := Mem42;
MemEntry[4,3] := Mem43;
MemEntry[4,4] := Mem44;
MemEntry[4,5] := Mem45;
MemEntry[4,6] := Mem46;
MemEntry[4,7] := Mem47;
MemEntry[5,0] := Mem50;
MemEntry[5,1] := Mem51;
MemEntry[5,2] := Mem52;
MemEntry[5,3] := Mem53;
MemEntry[5,4] := Mem54;
MemEntry[5,5] := Mem55;
MemEntry[5,6] := Mem56;
MemEntry[5,7] := Mem57;
MemEntry[6,0] := Mem60;
MemEntry[6,1] := Mem61;
MemEntry[6,2] := Mem62;
MemEntry[6,3] := Mem63;
MemEntry[6,4] := Mem64;
MemEntry[6,5] := Mem65;
MemEntry[6,6] := Mem66;
MemEntry[6,7] := Mem67;
MemEntry[7,0] := Mem70;
MemEntry[7,1] := Mem71;
MemEntry[7,2] := Mem72;
MemEntry[7,3] := Mem73;
MemEntry[7,4] := Mem74;
MemEntry[7,5] := Mem75;
MemEntry[7,6] := Mem76;
MemEntry[7,7] := Mem77;
{ See if there were any command-line parameters }
if (ParamCount = 1) then
begin
SourceCode.Lines.LoadFromFile(ParamStr(1));
Filename := ParamStr(1);
end
else Filename := '';
end;
(****************************************************************************)
{$R *.DFM}
{ Read a byte from memory. Also handles memory-mapped I/O (locations }
{ $FFF0.$FFFF are memory-mapped I/O locations). }
{ }
{ $FFF0 (bit 0)- Switch zero. }
{ $FFF2 (bit 0)- Switch one. }
{ $FFF4 (bit 0)- Switch two. }
{ $FFF6 (bit 0)- Switch three. }
{ All other bit positions return zero in the above words. }
{ }
{ Locations $FFF8..$FFFF are write-only locations and return }
{ random garbage. }
function ReadMem(adrs:word):byte;
begin
if (adrs < $fff0) then Result := Memory^[adrs]
else begin
with SIMx86Form do begin
if (Adrs = $fff0) then Result := ord(Inport0.pOn)
else if (Adrs = $fff2) then Result := ord(Inport2.pOn)
else if (Adrs = $fff4) then Result := ord(Inport4.pOn)
else if (Adrs = $fff6) then Result := ord(Inport6.pOn)
else if (Adrs = $fff1) or (Adrs=$FFF3) or
(Adrs = $fff5) or (Adrs=$fff7) then Result := 0;
end;
end;
end;
{ WriteMem- Write a byte to memory. Note that locations }
{ $FFF0..$FFFF are memory mapped I/O locations }
{ and must be handled specially. Only the low- }
{ order bit of locations $FFF8, $FFFA, $FFFC, and }
{ $FFFE are active outputs; these bits cor- }
{ respond to the four LEDs. The other memory- }
{ mapped I/O locations ignore data written to them}
procedure WriteMem(Adrs:word; Value:word);
begin
if (Adrs < $fff0) then
Memory^[Adrs] := Value
else begin
with SIMx86Form do begin
if (Adrs = $fff8) then
if (odd(Value)) then Outport8.Brush.Color := clRed
else Outport8.Brush.Color := clWhite
else if (Adrs = $fffa) then
if (odd(Value)) then OutportA.Brush.Color := clRed
else OutportA.Brush.Color := clWhite
else if (Adrs = $fffC) then
if (odd(Value)) then OutportC.Brush.Color := clRed
else OutportC.Brush.Color := clWhite
else if (Adrs = $fffe) then
if (odd(Value)) then OutportE.Brush.Color := clRed
else OutportE.Brush.Color := clWhite;
end;
end;
end;
{ Print an error message dialog box for the assembler. }
procedure ErrorMsg(const msg, Stmt:string);
begin
AbortAsm := MessageDlg(msg+': '+Stmt,
mtWarning,[mbOK, mbCancel],0) = mrCancel;
NoError := false;
end;
{ The following function converts a string of characters representing a }
{ hexadecimal number into the binary equivalent. }
function HexToWord(const s:string):word;
var i:integer;
begin
Result := 0;
for i := 1 to length(s) do
if (s[i] in ['0'..'9']) then
Result := (Result shl 4) + ord(s[i]) - ord('0')
else
Result := (Result shl 4) + ord(upcase(s[i])) -
ord('A') + 10;
end;
{ CheckHex- This procedure checks a TEdit object to see if its text }
{ field contains a valid hexadecimal value. It turns the }
{ background red if invalid. }
procedure CheckHex(var s:TEdit);
var i:integer;
begin
s.Color := clWindow;
for i := 1 to length(s.Text) do
if not (s.Text[i] in ['0'..'9','A'..'F','a'..'f']) then
begin
s.Color := clRed;
MessageBeep($FFFF);
end;
end;
{$F+}
{ Whenever the assembler encounters a label at the beginning of a line, }
{ the following function checks to see if it is a legal label and adds }
{ it to the symbol table along with its address. It also backpatches }
{ any previous references to that symbol if there are any. }
function ProcessLbl(Pat:TPatPtr):boolean;
var id: char;
i,
tmp:word;
begin
id :=upcase(Pat^.EndPattern^);
{ See if this is a legal label }
if (id in ['A'..'Z']) and ((Pat^.EndPattern+1)^ = ':') then
begin
{See if this symbol is already in the symbol table. }
if SymTbl[id].Defined then
begin
ErrorMsg('Duplicate Identifier',
SIMx86Form.SourceCode.lines[LineNum]);
end
else begin
{ See if this symbol was used already. }
{ If so, we need to backpatch some }
{ addresses in memory. }
if (SymTbl[id].Value <> 0) then
begin
i := SymTbl[id].Value;
repeat
tmp := Memory^[i] + (Memory^[i+1] shl 8);
Memory^[i] := Adrs and $ff;
Memory^[i+1] := Adrs shr 8;
i := tmp;
until i = 0;
end;
{ Put all the necessary information into the symbol table. }
SymTbl[id].Defined := true;
SymTbl[id].Value := adrs;
Result := true;
{ Skip over any white space following this label. }
Pat^.EndPattern := Pat^.EndPattern + 2;
While (Pat^.EndPattern^ in [' ',#9]) do
inc(Pat^.EndPattern);
end;
end
else Result := false;
end;
{ ConvertHex- Converts the text field of a PChar object into a binary }
{ value and return true if the result is successful. }
{ This routine shoves the binary result into the global }
{ variable OperandValue. The assembler uses this func }
{ to process hexadecimal instruction operands. }
function ConvertHex(Pat:TPatPtr):Boolean;
var i:integer;
begin
OperandValue := 0;
Result := Pat^.EndPattern^ in ['0'..'9', 'a'..'f', 'A'..'F'];
HasValue := true;
while (Pat^.EndPattern^ in ['0'..'9', 'a'..'f', 'A'..'F']) do
begin
if (Pat^.EndPattern^ in ['0'..'9']) then
OperandValue := (OperandValue shl 4) +
ord(Pat^.EndPattern^) - ord('0')
else
OperandValue := ( OperandValue shl 4) +
ord(upcase(Pat^.EndPattern^ )) -
ord('A') + 10;
inc(Pat^.EndPattern);
end;
end;
{ GetLbl- The assembler uses this function to process labels it }
{ finds in the operand field of a jump instruction. }
function GetLbl(Pat:TPatPtr):boolean;
var id:char;
begin
id :=upcase(Pat^.EndPattern^);
Result := false;
{ If the operand begins with a decimal digit, it's a hexadecimal }
{ number, not a label. }
if (id in ['0'..'9']) then
begin
HasValue := ConvertHex(Pat);
while (Pat^.EndPattern^ in [' ',#9]) do inc(Pat^.EndPattern);
Result := Pat^.EndPattern^ = #0;
end
{ If the operand begins with an alphabetic character, then we've }
{ got a label. }
else if (id in ['A'..'Z']) then
begin
HasValue := true;
if (not SymTbl[id].Defined) then
begin
{ If the symbol is not defined yet, create a linked }
{ list of undefined items for this symbol. }
OperandValue := SymTbl[id].Value;
SymTbl[id].Value := adrs+1;
end
else OperandValue := SymTbl[id].Value;
repeat
inc(Pat^.EndPattern);
until not (Pat^.EndPattern^ in [' ',#9]);
Result := Pat^.EndPattern^ = #0;
end
else begin
ErrorMsg('Expected label operand',
SIMx86Form.SourceCode.lines[LineNum]);
end;
end;
{ The assembler calls the following procedure whenever it encounters }
{ the corresponding procedure or operand. These procedures set up the }
{ global opcode and operand values so the assembler can emit the ap- }
{ propriate object code later. }
Procedure SetJmp(Pat:TPatPtr);
begin
HasOpcode := True;
Opcode := $0;
HasReg := true;
RegCode := $8;
HasOperand := true;
OperandCode := $6;
end;
Procedure SetJa(Pat:TPatPtr);
begin
HasOpcode := True;
Opcode := $0;
HasReg := true;
RegCode := $8;
HasOperand := true;
OperandCode := $4;
end;
Procedure SetJae(Pat:TPatPtr);
begin
HasOpcode := True;
Opcode := $0;
HasReg := true;
RegCode := $8;
HasOperand := true;
OperandCode := $5;
end;
Procedure SetJb(Pat:TPatPtr);
begin
HasOpcode := True;
Opcode := $0;
HasReg := true;
RegCode := $8;
HasOperand := true;
OperandCode := $2;
end;
Procedure SetJbe(Pat:TPatPtr);
begin
HasOpcode := True;
Opcode := $0;
HasReg := true;
RegCode := $8;
HasOperand := true;
OperandCode := $3;
end;
Procedure SetJe(Pat:TPatPtr);
begin
HasOpcode := True;
Opcode := $0;
HasReg := true;
RegCode := $8;
HasOperand := true;
OperandCode := $0;
end;
Procedure SetJne(Pat:TPatPtr);
begin
HasOpcode := True;
Opcode := $0;
HasReg := true;
RegCode := $8;
HasOperand := true;
OperandCode := $1;
end;
Procedure SetNot(Pat:TPatPtr);
begin
HasOpcode := True;
Opcode := $0;
HasReg := true;
RegCode := $10;
end;
Procedure SetOr(Pat:TPatPtr);
begin
HasOpcode := True;
Opcode := $20;
end;
Procedure SetAnd(Pat:TPatPtr);
begin
HasOpcode := True;
Opcode := $40;
end;
Procedure SetCmp(Pat:TPatPtr);
begin
HasOpcode := True;
Opcode := $60;
end;
Procedure SetSub(Pat:TPatPtr);
begin
HasOpcode := True;
Opcode := $80;
end;
Procedure SetAdd(Pat:TPatPtr);
begin
HasOpcode := True;
Opcode := $A0;
end;
Procedure SetMovReg(Pat:TPatPtr);
begin
HasOpcode := True;
Opcode := $C0;
end;
Procedure SetMovMem(Pat:TPatPtr);
begin
HasOpcode := True;
Opcode := $E0;
end;
Procedure SetBRK(Pat:TPatPtr);
begin
HasOpcode := True;
Opcode := $0;
HasReg := true;
RegCode := $0;
HasOperand := true;
OperandCode := $3;
end;
Procedure SetIret(Pat:TPatPtr);
begin
HasOpcode := True;
Opcode := $0;
HasReg := true;
RegCode := $0;
HasOperand := true;
OperandCode := $4;
end;
Procedure SetHalt(Pat:TPatPtr);
begin
HasOpcode := True;
Opcode := $0;
HasReg := true;
RegCode := $0;
HasOperand := true;
OperandCode := $5;
end;
Procedure SetPut(Pat:TPatPtr);
begin
HasOpcode := True;
Opcode := $0;
HasReg := true;
RegCode := $0;
HasOperand := true;
OperandCode := $7;
end;
Procedure SetGet(Pat:TPatPtr);
begin
HasOpcode := True;
Opcode := $0;
HasReg := true;
RegCode := $0;
HasOperand := true;
OperandCode := $6;
end;
Procedure SetAX(Pat:TPatPtr);
begin
HasReg := True;
Regcode := $00;
end;
Procedure SetBX(Pat:TPatPtr);
begin
HasReg := True;
Regcode := $08;
end;
Procedure SetCX(Pat:TPatPtr);
begin
HasReg := True;
Regcode := $10;
end;
Procedure SetDX(Pat:TPatPtr);
begin
HasReg := True;
Regcode := $18;
end;
Procedure SetAX2(Pat:TPatPtr);
begin
HasOperand := True;
Operandcode := $00;
end;
Procedure SetBX2(Pat:TPatPtr);
begin
HasOperand := True;
Operandcode := $1;
end;
Procedure SetCX2(Pat:TPatPtr);
begin
HasOperand := True;
Operandcode := $2;
end;
Procedure SetDX2(Pat:TPatPtr);
begin
HasOperand := True;
Operandcode := $3;
end;
Procedure SetBXInd(Pat:TPatPtr);
begin
HasOperand := True;
Operandcode := $4;
end;
Procedure SetBXIndx(Pat:TPatPtr);
begin
HasOperand := True;
Operandcode := $5;
end;
Procedure SetABS(Pat:TPatPtr);
begin
HasOperand := True;
Operandcode := $6;
end;
Procedure SetImm(Pat:TPatPtr);
begin
HasOperand := True;
Operandcode := $7;
end;
{$F-}
{ Whenever the user presses the CLEAR button on the memory page, the }
{ following method zeros out memory. }
procedure TSIMx86Form.ClrMemBtnClick(Sender: TObject);
var i:word;
begin
AdrsEntry.Text := '0000';
AdrsEntryChange(AdrsEntry);
{ Zero out memory }
for i := 0 to $ffef do
Memory^[i] := 0;
MemAdrs := 0;
Adrs := 0;
end;
{ Handle the NEW, OPEN, SAVE, SAVEAS, Print, and QUIT entries in the File Menu }
procedure TSIMx86Form.QuitClick(Sender: TObject);
begin
Application.Terminate;
end;
procedure TSIMx86Form.PrintMenuItemClick(Sender: TObject);
var
i: integer;
f: TextFile;
begin
if PrintDialog.Execute then begin
if (SIMx86Pages.PageIndex = 0) then begin
AssignPrn(f);
Rewrite(f);
for i := 0 to SourceCode.Lines.Count-1 do
writeln(f,SourceCode.Lines[i]);
CloseFile(f);
end
else Print;
end;
end;
procedure TSIMx86Form.NewClick(Sender: TObject);
begin
SourceCode.Clear;
Filename := '';
end;
procedure TSIMx86Form.OpenClick(Sender: TObject);
var
name:string;
begin
if OpenDialog.Execute then
begin
SourceCode.Lines.LoadFromFile(OpenDialog.Filename);
Filename := OpenDialog.Filename;
end;
end;
procedure TSIMx86Form.SaveAsClick(Sender: TObject);
begin
if SaveDialog.Execute then
begin
FileName := SaveDialog.Filename;
SourceCode.Lines.SaveToFile(SaveDialog.Filename);
end;
end;
procedure TSIMx86Form.SaveClick(Sender: TObject);
begin
if (Filename = '') then
begin
if SaveDialog.Execute then
Filename := SaveDialog.Filename;
end;
if (Filename <> '') then
begin
SourceCode.Lines.SaveToFile(Filename);
end;
end;
{ Handle Cut, Copy, Paste, Delete, and SelectAll in the Edit Menu }
procedure TSIMx86Form.CutClick(Sender: TObject);
begin
SourceCode.CutToClipBoard;
end;
procedure TSIMx86Form.CopyClick(Sender: TObject);
begin
SourceCode.CopyToClipBoard;
end;
procedure TSIMx86Form.PasteClick(Sender: TObject);
begin
SourceCode.PasteFromClipBoard;
end;
procedure TSIMx86Form.DeleteClick(Sender: TObject);
begin
SourceCode.ClearSelection;
end;
procedure TSIMx86Form.SelectAllClick(Sender: TObject);
begin
SourceCode.SelectAll;
SourceCode.Repaint;
end;
{ Whenver a value changes in one of the memory data entry boxes, this }
{ method converts the data data to hexadecimal and stores the resulting }
{ value away into memory. }
procedure TSIMx86Form.HexChange(Sender: TObject);
var Cell:TEdit;
HexVal:byte;
i,
j,
index:word;
begin
Cell := TEdit(Sender);
CheckHex(Cell);
{ Only store the data if there is no error. If there is an error, }
{ the memory cell's background color will be red. }
if (Cell.Color <> clRed) then
begin
for i := 0 to 7 do
for j := 0 to 7 do
if (Sender = MemEntry[i,j]) then
WriteMem(MemAdrs+ i*8+j, HexToWord(Cell.Text));
end;
end;
{ AdrsEntryChange- This method executes whenever the user changes }
{ a value in the address box on the Memory page. }
{ This method converts the string representation }
{ of the address to binary, updates all the labels}
{ on the screen, and then updates all the memory }
{ entry boxes on the page. }
procedure TSIMx86Form.AdrsEntryChange(Sender: TObject);
var
HexVal: word;
index: word;
i,j: word;
begin
CheckHex(TEdit(Sender));
{ If the entry is invalid, don't do anything. }
if (AdrsEntry.Color <> clRed) then begin
HexVal := HexToWord(AdrsEntry.Text);
{ Update the labels on the page. Make sure the values we use }
{ are all even multiples of eight. }
MemAdrs := HexVal and $FFF8;
Lbl8.Caption := IntToHex(MemAdrs+8,4);
Lbl10.Caption := IntToHex(MemAdrs+16,4);
Lbl18.Caption := IntToHex(MemAdrs+24,4);
Lbl20.Caption := IntToHex(MemAdrs+32,4);
Lbl28.Caption := IntToHex(MemAdrs+40,4);
Lbl30.Caption := IntToHex(MemAdrs+48,4);
Lbl38.Caption := IntToHex(MemAdrs+56,4);
{ Update the data in the entry cells on the page. If }
{ the location we access is before the starting address }
{ (because we may have rounded it down to the previous }
{ eight-byte boundary), then turn the background color }
{ gray. }
for i := 0 to 7 do
for j := 0 to 7 do
begin
index := MemAdrs + i*8 + j;
MemEntry[i,j].Text := IntToHex(ReadMem(index),2);
if ((index < HexVal) or (Index >=$fff0)) then
begin
MemEntry[i,j].Color := clSilver;
MemEntry[i,j].Enabled := false;
end
else begin
MemEntry[i,j].Color := clWindow;
MemEntry[i,j].Enabled := true;
end;
end;
end;
end;
procedure TSIMx86Form.StartAdrsChange(Sender: TObject);
begin
CheckHex(StartAdrs);
end;
{ Do the assembly here }
procedure TSIMx86Form.ASMbtnClick(Sender: TObject);
var
i:word;
ch:char;
line:array[0..255] of char;
s:PChar;
begin
{ Initialize the symbol table }
for ch := 'A' to 'Z' do
begin
SymTbl[ch].Value := 0;
SymTbl[ch].Defined := false;
end;
{ Compute the address of the first instruction }
if (StartAdrs.Color <> clRed) then
Adrs := HexToWord(StartAdrs.Text)
else Adrs := 0;
{ Assemble each line of source code }
for LineNum := 0 to SourceCode.Lines.Count-1 do begin
s := strPCopy(line, SourceCode.Lines[LineNum]);
NoError := true;
HasValue := false;
HasOpcode := false;
HasReg := false;
HasOperand := false;
if (not Match(stmt, s)) then
begin
if (NoError) then
ErrorMsg('Syntax Error',
SourceCode.lines[LineNum]);
if (AbortAsm) then break;
end
else begin
{ Okay, the instruction is syntactically cor- }
{ rect. Now emit the opcode and any necessary }
{ operands to memory. }
Val := 0;
if (HasOpcode) then {It's not a blank line }
begin
Val := Val or Opcode;
if (HasReg) then Val := Val or Regcode;
if (HasOperand) then Val := Val or OperandCode;
WriteMem(Adrs, Val);
inc(adrs);
if (HasValue) then begin {It has an operand }
WriteMem(Adrs, OperandValue and $ff);
inc(adrs);
WriteMem(Adrs, OperandValue shr 8);
inc (adrs);
end;
end;
end;
end;
{ Check to see if there were any undefined symbols }
for ch := 'A' to 'Z' do
if (not SymTbl[ch].Defined)then
if (SymTbl[ch].Value <> 0) then
ErrorMsg('Undefined Symbol', ch);
end;
{ Given an opcode, the following function returns the size of }
{ an instruction (in bytes). This is either one or three. }
function InstrSz(opcode:word):integer;
begin
if (opcode > $1f) or ((opcode and $18) = $10) then
if (opcode and $7) >= 5 then Result := 3
else Result := 1
else if (opcode and $18) = $8 then Result := 3
else Result := 1;
end;
{ Given an opcode, the following function returns a string that }
{ corresponds to the instruction's mnemonic. }
function Instr(opcode:word):string;
begin
Result := '????';
case (opcode shr 5) of
1: Result := 'or ';
2: Result := 'and ';
3: Result := 'cmp ';
4: Result := 'sub ';
5: Result := 'add ';
6: Result := 'mov ';
7: Result := 'mov ';
0: begin
if (opcode and $18) = $10 then
Result := 'not '
else if (opcode and $18) = $8 then
begin
case opcode and $7 of
0: Result := 'je ';
1: Result := 'jne ';
2: Result := 'jb ';
3: Result := 'jbe ';
4: Result := 'ja ';
5: Result := 'jae ';
6: Result := 'jmp ';
7: Result := '****';
end;
end
else if (opcode and $18) = $18 then Result := '****'
else begin
case (opcode and $7) of
0: Result := '****';
1: Result := '****';
2: Result := '****';
3: Result := 'brk ';
4: Result := 'iret';
5: Result := 'halt';
6: Result := 'get ';
7: Result := 'put ';
end;
end;
end;
end;
end;
{ Given an opcode and an option operand, the following function returns }
{ a string that represents the reg/memory addressing mode. }
function AdrsMode(opcode, operand:word):string;
function MemMode(opcode,operand:word):string;
begin
case opcode and $7 of
0: Result := 'ax';
1: Result := 'bx';
2: Result := 'cx';
3: Result := 'dx';
4: Result := '[bx]';
5: Result := '['+IntToHex(operand,4)+'+bx]';
6: Result := '['+IntToHex(operand,4)+']';
7: Result := IntToHex(operand,4);
end;
end;
begin
if (opcode > $1f) or (opcode and $18 = $10) then
Result := MemMode(opcode,operand)
else if (opcode and $18 = $8) then
Result := MemMode($27, operand)
else Result := '';
end;
{ The following function disassembles a single instruction at the given }
{ address and returns the string representation of that instruction. }
function Disassemble2(var CodeAdrs:word):string;
var Size,
Operand:word;
begin
Result := IntToHex(CodeAdrs,4) + ': ' +
IntToHex(ReadMem(CodeAdrs),2) + ' ';
Size := InstrSz(ReadMem(CodeAdrs));
Opcode := ReadMem(CodeAdrs);
if Size = 1 then
begin
Result := Result + ' ';
inc(CodeAdrs);
end
else begin
Result := Result +
IntToHex(ReadMem(CodeAdrs+1),2) + ' ' +
IntToHex(ReadMem(CodeAdrs+2),2) + ' ';
Operand := ReadMem(CodeAdrs+1) + (ReadMem(CodeAdrs+2) shl 8);
CodeAdrs := CodeAdrs + 3;
end;
Result := Result + Instr(opcode) + ' ';
case (opcode shr 5) of
1,2,3,4,5,6:begin
case ((opcode shr 3) and $3) of
0: Result := Result + 'ax, ';
1: Result := Result + 'bx, ';
2: Result := Result + 'cx, ';
3: Result := Result + 'dx, ';
end;
Result := Result + AdrsMode(Opcode, Operand);
end;
7:begin
Result := Result + AdrsMode(Opcode, Operand) + ', ';
case ((opcode shr 3) and $3) of
0: Result := Result + 'ax';
1: Result := Result + 'bx';
2: Result := Result + 'cx';
3: Result := Result + 'dx';
end;
end;
0: begin
case (opcode shr 3) and $3 of
1: Result := Result + IntToHex(Operand,4);
2: Result := Result + AdrsMode(Opcode,Operand);
end;
end;
end;
end;
function Disassemble(CodeAdrs:word):string;
begin
Result := Disassemble2(CodeAdrs);
end;
{ The following event method handles switching between pages on the form. }
procedure TSIMx86Form.Simx86PagesChange(Sender: TObject;
NewTab: Integer;
var AllowChange: Boolean);
var DisAdrs:word;
i:integer;
begin
{ Don't allow a change if a program is running. }
if (Running and (NewTab = 0)) then
begin
AllowChange := false;
end
{ If the user switches to the memory page, redraw all the cells. }
else if (NewTab = 1) then
AdrsEntryChange(AdrsEntry)
{ If the user switches to the execute page, disassemble some }
{ code for the disassembly list box. }
else if (NewTab = 2) then
begin
DisAdrs := HexToWord(DisAsmAdrs.Text);
DisAsm.Clear;
for i := 1 to 15 do
DisAsm.Items.Add(Disassemble2(DisAdrs));
Instruction.Caption := Disassemble(IP);
end;
end;
{ If the user changes the address in the TEdit box at the bottom of the }
{ disassembly list box, the following procedure converts this to a word }
{ and disassembles 15 instructions starting at this new address. }
procedure TSIMx86Form.DisAsmAdrsChange(Sender: TObject);
var i:integer;
DisAdrs:word;
begin
DisAdrs := HexToWord(DisAsmAdrs.Text);
DisAsm.Clear;
for i := 1 to 15 do
DisAsm.Items.Add(Disassemble2(DisAdrs));
end;
{ If the user presses on the down portion of the spinner at the bottom }
{ of the disassembly list box, this method increments the disassembly }
{ address and updates the disassembly list box. }
procedure TSIMx86Form.SpinButtonDownClick(Sender: TObject);
var value:word;
begin
Value := HexToWord(DisAsmAdrs.Text);
inc(Value);
DisAsmAdrs.Text := IntToHex(Value,4);
end;
{ If they press on the up arrow portion of the spinner, this code will }
{ decrement the starting disassembly address and update the list box. }
procedure TSIMx86Form.SpinButtonUpClick(Sender: TObject);
var value:word;
begin
Value := HexToWord(DisAsmAdrs.Text);
dec(Value);
DisAsmAdrs.Text := IntToHex(Value,4);
end;
procedure OneInstr;
procedure Store(mode:byte; index:word; value: word);
begin
case mode of
0: AX := value;
1: BX := value;
2: CX := value;
3: DX := value;
4: begin
WriteMem(bx, value and $FF);
WriteMem(bx+1, value shr 8);
end;
5: begin
WriteMem(bx+index, value and $FF);
WriteMem(bx+index+1, value shr 8);
end;
6: begin
WriteMem(index, value and $FF);
WriteMem(index+1, value shr 8);
end;
end;
end;
begin
with SIMx86Form do begin
if (PendingInt) and (not InInt) then
if (IntAdrs <> $FFFF) then
begin
InInt := true;
SaveAX := AX;
SaveBX := BX;
SaveCX := CX;
SaveDX := DX;
SaveIP := IP;
SaveLess := LessThanFlag.Checked;
SaveEqual:= EqualFlag.Checked;
PendingInt := false;
IP := IntAdrs;
end;
{ Okay, do the instruction here. }
Opcode := ReadMem(IP);
Operation := Opcode shr 5;
Reg := (Opcode shr 3) and $3;
RegMem := Opcode and $7;
InstrSize := 1;
case Reg of
0: Op1 := @AX;
1: Op1 := @BX;
2: Op1 := @CX;
3: Op1 := @DX;
end;
case RegMem of
0: Op2v := AX;
1: Op2v := BX;
2: Op2v := CX;
3: Op2v := DX;
4: Op2v := ReadMem(BX) + (ReadMem(BX+1) shl 8);
5: begin {[1000+bx]}
offset := BX + ReadMem(IP+1) + ReadMem(IP+2) shl 8;
Op2v := ReadMem(offset) + ReadMem(offset+1) shl 8;
InstrSize := 3;
end;
6: begin {[1000]}
offset := ReadMem(IP+1) + ReadMem(IP+2) shl 8;
Op2v := ReadMem(offset) + ReadMem(offset+1) shl 8;
InstrSize := 3;
end;
7: begin {1000}
Op2v := ReadMem(IP+1) + ReadMem(IP+2) shl 8;
InstrSize := 3;
end;
end;
case Operation of
1: Op1^ := Op1^ or Op2v;
2: Op1^ := Op1^ and Op2v;
3: begin
LessThanFlag.Checked := Op1^ < Op2v;
EqualFlag.Checked := Op1^ = Op2v;
end;
4: Op1^ := Op1^ - Op2v;
5: Op1^ := Op1^ + Op2v;
6: Op1^ := Op2v;
7: Store(regmem, ReadMem(IP+1) + ReadMem(IP+2) shl 8, Op1^);
0: case Reg of
2: Store(regmem,
ReadMem(IP+1) + ReadMem(IP+2) shl 8,
not Op2v);
1: begin {jumps}
InstrSize := 0;
case RegMem of
0: if EqualFlag.Checked then
IP := ReadMem(IP+1) +
ReadMem(IP+2) shl 8
else InstrSize := 3;
1: if not EqualFlag.Checked then
IP := ReadMem(IP+1) +
ReadMem(IP+2) shl 8
else InstrSize := 3;
2: if LessThanFlag.Checked then
IP := ReadMem(IP+1) +
ReadMem(IP+2) shl 8
else InstrSize := 3;
3: if LessThanFlag.Checked or
EqualFlag.Checked then
IP := ReadMem(IP+1) +
ReadMem(IP+2) shl 8
else InstrSize := 3;
4: if not (LessThanFlag.Checked or
EqualFlag.Checked) then
IP := ReadMem(IP+1) +
ReadMem(IP+2) shl 8
else InstrSize := 3;
5: if not LessThanFlag.Checked then
IP := ReadMem(IP+1) +
ReadMem(IP+2) shl 8
else InstrSize := 3;
6: IP := ReadMem(IP+1) + ReadMem(IP+2) shl 8;
7: begin
ErrorMsg('Illegal instruction',
IntToHex(IP,4));
Halted := true;
end;
end;
end;
3: begin
ErrorMsg('Illegal instruction',IntToHex(IP,4));
Halted := true;
end;
0: case (RegMem) of
0,1,2:begin
ErrorMsg('Illegal instruction',IntToHex(IP,4));
Halted := true;
InstrSize := 0;
end;
3: begin
ErrorMsg('BRK encountered',IntToHex(IP,4));
Halted := true;
InstrSize := 1;
end;
4: if (not InInt) then
begin
ErrorMsg('IRET encountered outside interrupt',
IntToHex(IP,4));
Halted := true;
InstrSize := 0;
end
else begin
AX := SaveAX;
BX := SaveBX;
CX := SaveCX;
DX := SaveDX;
IP := SaveIP;
LessThanFlag.Checked := SaveLess;
EqualFlag.Checked := SaveEqual;
InstrSize := 0;
InInt := false;
end;
5: begin
ErrorMsg('Halt encountered',IntToHex(IP,4));
Halted := true;
InstrSize := 0;
end;
6: begin
InputForm.ShowModal;
AX := InputValue;
InstrSize := 1;
end;
7: begin
Output.Items.Add(IntToHex(AX,4));
InstrSize := 1;
end;
end;
end;
end;
IP := IP + InstrSize;
end;
end;
procedure StopPgm;
begin
with SIMx86Form do begin
IPValue.Enabled := true;
DisAsmAdrs.Enabled := true;
SpinButton.Enabled := true;
RunBtn.Enabled := true;
StepBtn.Enabled := true;
AXValue.Enabled := true;
BXValue.Enabled := true;
CXValue.Enabled := true;
DXValue.Enabled := true;
LessThanFlag.Enabled := true;
EqualFlag.Enabled := true;
HaltBtn.Enabled := false;
RunningLite.Color := clGray;
MainMenu.Items[0].Enabled := true;
MainMenu.Items[1].Enabled := true;
PendingInt := false;
Instruction.Caption := Disassemble(IP);
end;
end;
{ If the users presses the "RUN" button, the following code kicks in }
{ the emulator. }
procedure TSIMx86Form.RunBtnClick(Sender: TObject);
begin
IPValue.Enabled := false;
DisAsmAdrs.Enabled := false;
SpinButton.Enabled := false;
RunBtn.Enabled := false;
StepBtn.Enabled := false;
AXValue.Enabled := false;
BXValue.Enabled := false;
CXValue.Enabled := false;
DXValue.Enabled := false;
LessThanFlag.Enabled := false;
EqualFlag.Enabled := false;
HaltBtn.Enabled := true;
RunningLite.Color := clRed;
PendingInt := false;
MainMenu.Items[0].Enabled := false;
MainMenu.Items[1].Enabled := false;
Halted := false;
Running := true;
InInt := false;
while not Halted do begin
Application.ProcessMessages;
OneInstr;
end;
Running := false;
RunningLite.Color := clGray;
StopPgm;
IPValue.Text := IntToHex(IP,4);
AXValue.Text := IntToHex(AX,4);
BXValue.Text := IntToHex(BX,4);
CXValue.Text := IntToHex(CX,4);
DXValue.Text := IntToHex(DX,4);
end;
procedure TSIMx86Form.HaltBtnClick(Sender: TObject);
begin
StopPgm;
Halted := true;
end;
{ If the user presses the reset button, the following method resets }
{ the machine. }
procedure TSIMx86Form.ResetBtnClick(Sender: TObject);
begin
AX := 0;
BX := 0;
CX := 0;
DX := 0;
AXValue.Text := '0000';
BXValue.Text := '0000';
CXValue.Text := '0000';
DXValue.Text := '0000';
if (ResetVect.Color <> clRed) then
begin
IP := HexToWord(ResetVect.Text);
IPValue.Text := ResetVect.Text;
end
else begin
IP := 0;
IPValue.Text := '0000';
end;
LessThanFlag.Checked := false;
EqualFlag.Checked := false;
PendingInt := false;
StopPgm;
Halted := true;
Output.Items.Clear;
Input.Items.Clear;
Instruction.Caption := Disassemble(IP);
end;
procedure TSIMx86Form.InterruptBtnClick(Sender: TObject);
begin
PendingInt := true;
end;
procedure TSIMx86Form.IntVectChange(Sender: TObject);
begin
CheckHex(IntVect);
if (IntVect.Color <> clRed) then
begin
IntAdrs := HexToWord(IntVect.Text);
end;
end;
procedure TSIMx86Form.IPValueChange(Sender: TObject);
begin
CheckHex(IPValue);
if IPValue.Color <> clRed then
begin
IP := HexToWord(IPValue.Text);
end;
Instruction.Caption := Disassemble(IP);
end;
procedure TSIMx86Form.StepBtnClick(Sender: TObject);
begin
OneInstr;
IPValue.Text := IntToHex(IP,4);
AXValue.Text := IntToHex(AX,4);
BXValue.Text := IntToHex(BX,4);
CXValue.Text := IntToHex(CX,4);
DXValue.Text := IntToHex(DX,4);
Instruction.Caption := Disassemble(IP);
end;
end.