home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DP Tool Club 8
/
CDASC08.ISO
/
NEWS
/
555
/
M85
/
M85.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1993-10-07
|
38KB
|
1,351 lines
Program M85;
{======================================================================
Assembleur - Désassembleur - Interpréteur
de code M85
Vocation pédagogique de modèle de processeur RISC
Assemblage et exécutions en modes pas à pas
Accès direct aux registres du processeur
Version 1.0
Début de projet : 9.1.93
Dernière modification : 16.1.93
Eric Nicolas, d'après le cours de Jean Suchard.
======================================================================}
{$DEFINE Int}
{$DEFINE Ass}
{$DEFINE Hor}
{$X+}
Uses Crt,Dos,Objects,Drivers,Menus,Views,App,Dialogs,StdDlg,TvExt;
Type
TIdent = String[40];
TEtiq = Record
Id : TIdent;
Ad : Word;
End;
TMnem = Record
Id : TIdent;
Co : Byte;
Ad : String[3];
End;
Const
EtiqMax = 50;
MemMax = 500;
PilMax = 100;
StrError : Array[1..15] Of String[50] =
('Identificateur attendu',
'Table des symboles pleine',
'Mnémonique attendue',
'Registre Rx attendu',
'Mauvais numero de registre',
'Valeur numérique entière attendue',
'"[" attendu',
'"]" attendu',
'Symbole défini pour la deuxième fois',
'Identificateur inconnu',
'Code d''instruction inconnu',
'Saut à une adresse contenant une donnée',
'Tentative d''empilement sur une pile pleine',
'Tentative de dépilement sur une pile vide',
'Changement d''une case mémoire non autorisée');
NbMnem = 24;
Mnem : Array[1..NbMnem] Of TMnem =
((Id:'NOP';Co:00;Ad:' '),
(Id:'MOV';Co:10;Ad:'rr '),
(Id:'STO';Co:11;Ad:'br '),
(Id:'LDR';Co:12;Ad:'rb '),
(Id:'LDI';Co:13;Ad:'ri '),
(Id:'JMP';Co:20;Ad:'a '),
(Id:'JZE';Co:21;Ad:'ra '),
(Id:'JNZ';Co:22;Ad:'ra '),
(Id:'JPO';Co:23;Ad:'ra '),
(Id:'JPN';Co:24;Ad:'ra '),
(Id:'ADD';Co:30;Ad:'rrr'),
(Id:'SUB';Co:31;Ad:'rrr'),
(Id:'MUL';Co:32;Ad:'rrr'),
(Id:'DIV';Co:33;Ad:'rrr'),
(Id:'NEG';Co:34;Ad:'r '),
(Id:'INC';Co:35;Ad:'r '),
(Id:'DEC';Co:36;Ad:'r '),
(Id:'INP';Co:40;Ad:' '),
(Id:'OUT';Co:41;Ad:' '),
(Id:'PSH';Co:50;Ad:'r '),
(Id:'POP';Co:51;Ad:'r '),
(Id:'JSR';Co:52;Ad:'a '),
(Id:'RTS';Co:53;Ad:' '),
(Id:'END';Co:60;Ad:' '));
{======================================================================
Routines générales
======================================================================}
Procedure SignaleError(S : String);
Var E : TEvent;
Sortie : Boolean;
Begin
Sortie:=FALSE;
TextAttr:=$4F;
GotoXY(1,25);ClrEol;Write(Copy(S,1,72),' Pressez ESC.');
Repeat
GetKeyEvent(E);
If E.What=evKeyDown Then
If E.CharCode=#27 Then Sortie:=TRUE;
Until Sortie;
StatusLine^.DrawView;
End;
{$IFDEF Ass}
{======================================================================
Assembleur 2 passes avec mode pas à pas
======================================================================}
Const
cmAssWReset = 200;
cmAssWUnPas = 201;
cmAssWPasse1 = 202;
cmAssWPasse2 = 203;
cmIsAssW = 204;
Type
PAssembleur = ^TAssembleur;
PAssInterior= ^TAssInterior;
TAssInterior= Object(TScroller)
Ass : PAssembleur;
Tpe : Byte;
constructor Init(var Bounds: TRect;
AHScrollBar,AVScrollBar: PScrollBar;
eAss : PAssembleur ; eTpe : Byte);
Procedure Draw; Virtual;
Procedure MiseAJour;
End;
TAssembleur = Object(TDialog)
I1,I2,I3: PAssInterior;
Ligne : Word;
NbEtiq : Word;
Etiq : Array[1..EtiqMax] Of TEtiq;
Code : Array[0..MemMax-1] Of Word;
Marque : Array[0..MemMax-1] Of Boolean;
Adr : Word;
CarLu : Char;
Etat : Byte;
EtatStr : String;
Source : PByteArray;
Taille : Word;
Pos : Word;
PosAff : Byte;
NbLigne : Word;
Err : String;
Constructor Init(eNom : String);
Destructor Done; Virtual;
Procedure Reset;
Procedure UnPas;
Procedure Passe1;
Procedure Passe2;
Procedure LitCar;
Procedure Error(n : Byte);
Procedure Sauve(eNom : String);
Function MakeInterior(Bounds : TRect;Tpe : Byte) : PAssInterior;
Procedure HandleEvent(Var Event : TEvent); Virtual;
Function Valid(Command : Word) : Boolean; Virtual;
Procedure SizeLimits(Var Min,Max : TPoint); Virtual;
End;
constructor TAssInterior.Init(var Bounds: TRect; AHScrollBar,
AVScrollBar: PScrollBar; eAss : PAssembleur ; eTpe : Byte);
begin
TScroller.Init(Bounds, AHScrollBar, AVScrollBar);
Ass:=eAss;
Tpe:=eTpe;
Options := Options or ofFramed;
Case Tpe Of
1 : SetLimit(128,Ass^.NbLigne);
2 : SetLimit(128,0);
3 : SetLimit(128,0);
End;
end;
Procedure TAssInterior.MiseAJour;
Begin
Case Tpe Of
1 : Begin
If Ass^.Ligne>=Size.Y Then ScrollTo(0,Ass^.Ligne-Size.Y+1);
If Ass^.Ligne<=Delta.Y Then ScrollTo(0,Ass^.Ligne);
End;
2 : Begin
SetLimit(128,Ass^.NbEtiq);
ScrollTo(0,Ass^.NbEtiq-Size.Y);
End;
3 : Begin
SetLimit(128,Ass^.Adr);
ScrollTo(0,Ass^.Adr-Size.Y);
End;
End;
End;
Procedure TAssInterior.Draw;
Var I,J : Byte;
B : TDrawBuffer;
S,T : String;
Color : Byte;
E : TEtiq;
P : Word;
Begin
P:=0;
If Tpe=1 Then
For I:=1 to Delta.Y do
Begin
While (Ass^.Source^[P]<>10) do Inc(P);
Inc(P);
End;
Color:=GetColor(1);
For I:=0 to Size.Y-1 do
Begin
S:='';
Case Tpe Of
1 : Begin
While (Ass^.Source^[P]<>10) AND (P<Ass^.Taille) do
Begin
Case Ass^.Source^[P] Of
9 : S:=S+' ';
32..255 : S:=S+Chr(Ass^.Source^[P]);
End;
Inc(P);
End;
Inc(P);
If I+Delta.Y+1=Ass^.Ligne Then Color:=$2F Else Color:=$70;
End;
2 : If I+Delta.Y<Ass^.NbEtiq Then
Begin
E:=Ass^.Etiq[I+Delta.Y+1];
S:=Copy(E.Id,1,16);
While Length(S)<16 do S:=S+' ';
If E.Ad<>0 Then Str(E.Ad-1:4,T)
Else T:='NR';
S:=S+T;
End;
3 : If I+Delta.Y<Ass^.Adr Then
Begin
Str(Ass^.Code[I+Delta.Y],S);
If Ass^.Marque[I+Delta.Y] Then S:='$'+S;
End;
End;
MoveChar(B,' ',Color,Size.X);
MoveStr(B,Copy(S,Delta.X,Size.X),Color);
WriteLine(0,I,Size.X,1,B);
End;
End;
Procedure TAssembleur.SizeLimits(Var Min,Max : TPoint);
Begin
Min.X:=60;
Min.Y:=13;
Max:=Owner^.Size;
End;
Function TAssembleur.Valid(Command : Word) : Boolean;
Var R : Boolean;
Begin
If Command=cmValid Then If Err='Not Enough Memory' Then R:=FALSE;
R:=R AND TDialog.Valid(Command);
Valid:=R;
End;
Function TAssembleur.MakeInterior(Bounds: TRect ; Tpe : Byte): PAssInterior;
var
HScrollBar, VScrollBar: PScrollBar;
R: TRect;
begin
R.Assign(Bounds.B.X - 1, Bounds.A.Y + 1, Bounds.B.X, Bounds.B.Y - 1);
VScrollBar := New(PScrollBar, Init(R));
VScrollBar^.Options := VScrollBar^.Options or ofPostProcess;
Insert(VScrollBar);
if Tpe=1 Then
Begin
R.Assign(Bounds.A.X + 2, Bounds.B.Y - 1, Bounds.B.X - 2, Bounds.B.Y);
HScrollBar := New(PScrollBar, Init(R));
HScrollBar^.Options := HScrollBar^.Options or ofPostProcess;
Insert(HScrollBar);
End
Else HScrollBar:=NIL;
Bounds.Grow(-1, -1);
MakeInterior := New(PAssInterior, Init(Bounds, HScrollBar, VScrollBar,@Self,Tpe));
end;
Constructor TAssembleur.Init(eNom : String);
Var Rep : DirStr;
NomFich : NameStr;
Ext : ExtStr;
R,R1 : TRect;
S : PDosStream;
I : Word;
P : PView;
Begin
FSplit(eNom,Rep,NomFich,Ext);
If Ext='' Then Ext:='.ASM';
DeskTop^.GetExtent(R);
R.Grow(-1,-4);
TDialog.Init(R,NomFich+Ext);
S:=New(PDosStream,Init(Rep+NomFich+Ext,stOpenRead));
Taille:=S^.GetSize;
If MaxAvail<Taille Then Err:='Not Enough Memory';
GetMem(Source,Taille);
S^.Read(Source^,Taille);
Dispose(S,Done);
NbLigne:=1;
For I:=1 to Taille do
If Source^[I]=10 Then Inc(NbLigne);
GetExtent(R); R.Grow(0,-1);
R.A.X:=2;
R.B.X:=R.B.X-46;
I1:=MakeInterior(R,1);
I1^.GrowMode:=I1^.GrowMode OR gfGrowHiX OR gfGrowHiY;
Insert(I1);
R1.Assign(R.A.X+1,R.A.Y,R.A.X+7,R.A.Y+1);
Insert(New(PStaticText,Init(R1,'Source')));
R.A.X:=R.B.X+1;
R.B.X:=R.A.X+22;
I2:=MakeInterior(R,2);
I2^.GrowMode:=I2^.GrowMode OR gfGrowHiX OR gfGrowLoX OR gfGrowHiY;
Insert(I2);
R1.Assign(R.A.X+1,R.A.Y,R.A.X+9,R.A.Y+1);
P:=New(PStaticText,Init(R1,'Symboles'));
P^.GrowMode:=P^.GrowMode OR gfGrowHiX OR gfGrowLoX; Insert(P);
R.A.X:=R.B.X+1;
R.B.X:=R.A.X+7;
I3:=MakeInterior(R,3);
I3^.GrowMode:=I3^.GrowMode OR gfGrowHiX OR gfGrowLoX OR gfGrowHiY;
Insert(I3);
R1.Assign(R.A.X+1,R.A.Y,R.A.X+5,R.A.Y+1);
P:=New(PStaticText,Init(R1,'Code'));
P^.GrowMode:=P^.GrowMode OR gfGrowHiX OR gfGrowLoX; Insert(P);
R.A.X:=R.B.X+1;
R.B.X:=R.A.X+11;
R.A.Y:=R.B.Y-11;
R.B.Y:=R.A.Y+1;
P:=New(PStaticText,Init(R,'Etat : '));
P^.GrowMode:=P^.GrowMode OR gfGrowAll; Insert(P);
R.A.Y:=R.B.Y;
R.B.Y:=R.A.Y+1;
P:=New(PStatus,Init(R,@EtatStr));
P^.GrowMode:=P^.GrowMode OR gfGrowAll; Insert(P);
R.A.Y:=R.B.Y+1;
R.B.Y:=R.A.Y+2;
P:=New(PButton,Init(R,'Reset',cmAssWReset,bfNormal));
P^.GrowMode:=P^.GrowMode OR gfGrowAll; Insert(P);
R.A.Y:=R.B.Y;
R.B.Y:=R.A.Y+2;
P:=New(PButton,Init(R,'Un Pas',cmAssWUnPas,bfNormal));
P^.GrowMode:=P^.GrowMode OR gfGrowAll; Insert(P);
R.A.Y:=R.B.Y;
R.B.Y:=R.A.Y+2;
P:=New(PButton,Init(R,'Passe 1',cmAssWPasse1,bfNormal));
P^.GrowMode:=P^.GrowMode OR gfGrowAll; Insert(P);
R.A.Y:=R.B.Y;
R.B.Y:=R.A.Y+2;
P:=New(PButton,Init(R,'Passe 2',cmAssWPasse2,bfNormal));
P^.GrowMode:=P^.GrowMode OR gfGrowAll; Insert(P);
Reset;
Flags:=Flags OR wfGrow OR wfZoom;
End;
Procedure TAssembleur.HandleEvent(Var Event : TEvent);
Begin
TDialog.HandleEvent(Event);
If Event.What=evBroadCast Then
If Event.Command=cmIsAssW Then ClearEvent(Event);
If Event.What=evCommand Then
Begin
Case Event.Command Of
cmAssWReset : Reset;
cmAssWUnPas : UnPas;
cmAssWPasse1 : Passe1;
cmAssWPasse2 : Passe2;
Else
Exit;
End;
ClearEvent(Event);
I1^.MiseAJour;
I2^.MiseAJour;
I3^.MiseAJour;
ReDraw;
End;
End;
Procedure TAssembleur.Sauve(eNom : String);
Var S : PDosStream;
Begin
If Etat<>2 Then Exit;
S:=New(PDosStream,Init(eNom,stCreate));
S^.Write(Code,Adr*2);
Dispose(S,Done);
End;
Destructor TAssembleur.Done;
Begin
FreeMem(Source,Taille);
TWindow.Done;
End;
Procedure TAssembleur.Reset;
Begin
Etat:=0;
EtatStr:='Initial';
Err:='';
FillChar(Code,SizeOf(Code),0);
FillChar(Marque,SizeOf(Marque),FALSE);
Adr:=0;
NbEtiq:=0;
Ligne:=1;PosAff:=1;
Pos:=0;
LitCar;
End;
Procedure TAssembleur.Error(n : Byte);
Var S : String;
Begin
Str(Ligne,S);
Err:=StrError[n]+' : Ligne '+S+'.';
EtatStr:='Erreur survenue';
Etat:=5;
I1^.MiseAJour;
I2^.MiseAJour;
I3^.MiseAJour;
ReDraw;
SignaleError(Err);
Ligne:=0;
End;
Procedure TAssembleur.LitCar;
Begin
If Etat<>0 Then Exit;
If Pos=Taille Then
Begin
Etat:=1;
EtatStr:='Passe 1 OK';
Ligne:=0;PosAff:=0;
End;
CarLu:=UpCase(Chr(Source^[Pos]));
Inc(Pos);
Inc(PosAff);
If CarLu=#10 Then
Begin
PosAff:=1;
Inc(Ligne);
End;
End;
Procedure TAssembleur.UnPas;
Var Id : TIdent;
NoReg : Byte;
Regs : Array[0..2] Of Byte;
I,J : Byte;
AdrPas : Byte;
Procedure LitCarUtile;
Begin
While (Etat=0) AND (Ord(CarLu)<=32) Do LitCar;
End;
Procedure PasseLigne;
Begin
While (Etat=0) AND (CarLu<>#10) Do LitCar;
LitCar;
End;
Procedure LitIdent(Var Id : TIdent ; Test : Boolean);
Begin
Id:='';
If Test Then
If (CarLu<'A') Or (CarLu>'Z') Then Error(1);
Repeat
Id:=Id+CarLu;
LitCar;
Until (Etat<>0) Or (Not(CarLu IN ['0'..'9','A'..'Z','_']));
End;
Procedure NewEtiq(Id : TIdent ; Ad : Word);
Begin
If NbEtiq=EtiqMax Then Error(2)
Else
Begin
Inc(NbEtiq);
Etiq[NbEtiq].Id:=Id;
Etiq[NbEtiq].Ad:=Ad;
End;
End;
Procedure LitRegistre;
Begin
LitCarUtile;
LitIdent(Id,False);
If Length(Id)<>2 Then Begin Error(4); Exit; End;
If Id[1]<>'R' Then Begin Error(4); Exit; End;
Regs[NoReg]:=Ord(Id[2])-48;
If (Regs[NoReg]>3) Then Error(5);
Inc(NoReg);
End;
Procedure LitAdresse;
Var ValRes : Real;
ValErr : Integer;
I,J : Byte;
Begin
LitCarUtile;
LitIdent(Id,FALSE);
Val(Id,ValRes,ValErr);
If ValErr=0 Then Code[Adr+1]:=Round(ValRes)
Else
Begin
J:=0;
For I:=1 to NbEtiq do
If Etiq[I].Id=Id Then J:=I;
If J=0
Then
Begin
NewEtiq(Id,0);
Code[Adr+1]:=NbEtiq;
Marque[Adr+1]:=TRUE;
End
Else
If Etiq[J].Ad=0
Then
Begin
Code[Adr+1]:=J;
Marque[Adr+1]:=TRUE;
End
Else
Code[Adr+1]:=Etiq[J].Ad-1;
End;
AdrPas:=2;
End;
Procedure LitIndirect;
Begin
LitCarUtile;
If CarLu<>'[' Then Error(7);
LitCar;
LitAdresse;
If CarLu<>']' Then Error(8);
LitCar;
End;
Procedure LitImmediat;
Var ValRes : Real;
ValErr : Integer;
Begin
LitCarUtile;
LitIdent(Id,FALSE);
Val(Id,ValRes,ValErr);
If ValErr<>0 Then Error(6)
Else
Begin
Code[Adr+1]:=Round(ValRes);
AdrPas:=2;
End;
End;
Begin
If Etat<>0 Then Exit;
LitCarUtile;
Case CarLu Of
';' : PasseLigne;
'$' : Begin
LitCar;
LitIdent(Id,TRUE);
J:=0;
For I:=1 to NbEtiq Do
If Etiq[I].Id=Id Then
Begin
If Etiq[I].Ad=0 Then Etiq[I].Ad:=Adr+1
Else Error(9);
J:=I;
End;
If J=0 Then NewEtiq(Id,Adr+1);
End;
Else
Begin
LitIdent(Id,TRUE);
If Id='DAT'
Then
Begin
LitImmediat;
Code[Adr]:=Code[Adr+1];
Inc(Adr);
End
Else
Begin
J:=0;
For I:=1 to NbMnem do
If Id=Mnem[I].Id Then J:=I;
If J=0 Then Error(3)
Else
Begin
NoReg:=0;Regs[0]:=0;Regs[1]:=0;Regs[2]:=0;
AdrPas:=1;
For I:=1 to 3 do
Begin
If Err<>'' Then Exit;
Case Mnem[J].Ad[I] Of
'r' : LitRegistre;
'a' : LitAdresse;
'i' : LitImmediat;
'b' : LitIndirect;
End;
End;
If Err<>'' Then Exit;
Code[Adr]:=Mnem[J].Co*1000+Regs[0]*100+Regs[1]*10+Regs[2];
Inc(Adr,AdrPas);
End;
End;
End;
End;
End;
Procedure TAssembleur.Passe1;
Var I : Byte;
Begin
If Etat<>0 Then Exit;
Repeat UnPas;
Until Etat<>0;
End;
Procedure TAssembleur.Passe2;
Var I : Word;
Begin
If Etat<>1 Then Exit;
For I:=0 to Adr-1 do
If Marque[I] Then
If Etiq[Code[I]].Ad=0
Then
Begin
Err:=StrError[9]+' '+Etiq[Code[I]].Id;
Exit;
End
Else
Begin
Code[I]:=Etiq[Code[I]].Ad-1;
Marque[I]:=FALSE;
End;
Etat:=2;
EtatStr:='Passe 2 OK';
End;
{$ENDIF}
{$IFDEF Int}
{======================================================================
Interpréteur et désassembleur avec mode pas à pas
======================================================================}
Const
cmIntWDesassemble = 150;
cmIntWUnPas = 151;
cmIntWRun = 152;
cmIntWReset = 153;
Type
TData = Record
Regs : Array[0..3] Of Integer;
CO : Word;
InM : String[60];
OutM : String[60];
End;
PInterpret = ^TInterpret;
PIntInterior= ^TIntInterior;
TIntInterior= Object(TScroller)
Int : PInterpret;
Tpe : Byte;
constructor Init(var Bounds: TRect;
AHScrollBar,AVScrollBar: PScrollBar;
eInt : PInterpret ; eTpe : Byte);
Procedure Draw; Virtual;
Procedure MoveTo(Ad : Word);
Procedure PileHaut;
End;
TInterpret = Object(TDialog)
LongMem : Word;
Mem : Array[0..MemMax-1] Of Word;
Struct : Array[0..MemMax-1] Of Word;
Source : Array[0..MemMax-1] Of PString;
Pile : Array[0..PilMax-1] Of Word;
HautPile: Word;
Etiq : Word;
Int : PIntInterior;
Data : TData;
Fin : Boolean;
Desass : Boolean;
Constructor Init(Nom : String);
Procedure Error(n : Byte);
Function VerifieCO : Boolean;
Procedure UnPas;
Procedure Run;
Procedure Reset;
Procedure ProduitListing;
Function MakeInterior(R : TRect; Tpe : Byte) : PIntInterior;
Procedure HandleEvent(Var Event : TEvent); Virtual;
Procedure SizeLimits(Var Min,Max : TPoint); Virtual;
Destructor Done; Virtual;
End;
Procedure TIntInterior.PileHaut;
Begin
If Tpe=2 Then
Begin
SetLimit(5,Int^.HautPile);
End;
End;
Procedure TIntInterior.MoveTo(Ad : Word);
Begin
If Ad>Delta.Y+Size.Y-1 Then ScrollTo(0,Size.Y-Ad-1);
End;
constructor TIntInterior.Init(var Bounds: TRect; AHScrollBar,
AVScrollBar: PScrollBar; eInt : PInterpret ; eTpe : Byte);
Begin
TScroller.Init(Bounds, AHScrollBar, AVScrollBar);
Tpe:=eTpe;
Int:=eInt;
Options := Options or ofFramed;
If Tpe=1 Then SetLimit(55,Int^.LongMem)
Else SetLimit(5,0);
End;
Procedure TIntInterior.Draw;
Var I : Byte;
B : TDrawBuffer;
Color : Byte;
S : String;
Begin
For I:=0 to Size.Y-1 do
Begin
S:='';Color:=$70;
Case Tpe Of
1 : Begin
If I+Delta.Y<Int^.LongMem Then S:=Int^.Source[I+Delta.Y]^;
If (I+Delta.Y=Int^.Data.Co) AND (Not Int^.Fin) Then Color:=$2F;
End;
2 : If I+Delta.Y<Int^.HautPile Then Str(Int^.Pile[I+Delta.Y]:5,S);
End;
MoveChar(B,' ',Color,Size.X);
MoveStr(B,Copy(S,Delta.X,Size.X),Color);
WriteLine(0,I,Size.X,1,B);
End;
End;
Procedure TInterpret.SizeLimits(Var Min,Max : TPoint);
Begin
Min.X:=39;
Min.Y:=17;
Max:=Owner^.Size;
End;
Procedure TInterpret.Error(n : Byte);
Begin
SignaleError(StrError[n]);
Fin:=TRUE;
End;
Function TInterpret.VerifieCO : Boolean;
Var B : Boolean;
Begin
B:=(Struct[Data.CO] AND 3)<>2;
If B Then Error(12);
VerifieCO:=B;
End;
Procedure TInterpret.ProduitListing;
Var Adr,AdrPas : Word;
I,K,L,CodOp : Byte;
Temp : String[50];
NbRegs : Byte;
R : Array[0..2] Of Byte;
Function Zeros(A : Word) : String;
Var S : String;
Begin
S[1]:='L';
S[2]:=Chr(((A DIV 1000 ) MOD 10)+48);
S[3]:=Chr(((A DIV 100 ) MOD 10)+48);
S[4]:=Chr(((A DIV 10 ) MOD 10)+48);
S[5]:=Chr(((A DIV 1 ) MOD 10)+48);
S[0]:=#5;
Zeros:=S;
End;
Begin
If Desass
Then
Begin
Adr:=0;
While Adr<LongMem do
Begin
AdrPas:=1;
If Struct[Adr] SHR 2<>0 Then Source[Adr]^:=Zeros(Struct[Adr] SHR 2)+' '
Else Source[Adr]^:=' ';
Case Struct[Adr] AND 3 Of
0 : ;
1,3 : Begin
Source[Adr]^:=Source[Adr]^+'DAT ';
Str(Mem[Adr],Temp);
Source[Adr]^:=Source[Adr]^+Temp;
End;
2 : Begin
CodOp:=Mem[Adr] DIV 1000;
R[0]:=(Mem[Adr] DIV 100) MOD 10;
R[1]:=(Mem[Adr] DIV 10) MOD 10;
R[2]:=Mem[Adr] MOD 10;
NbRegs:=0;
L:=0;
For K:=1 to NbMnem do
If CodOp=Mnem[K].CO Then L:=K;
With Mnem[L] do
Begin
Source[Adr]^:=Source[Adr]^+Id+' ';
For K:=1 to 3 do
Begin
Temp:='';
Case Ad[K] Of
'r' : Begin
Temp:='R'+Chr(R[NbRegs]+48)+' ';
Inc(NbRegs);
End;
'a' : Begin
Temp:=Zeros(Struct[Mem[Adr+1]] SHR 2)+' ';
AdrPas:=2;
End;
'b' : Begin
Temp:='['+Zeros(Struct[Mem[Adr+1]] SHR 2)+'] ';
AdrPas:=2;
End;
'i' : Begin
Str(Mem[Adr+1],Temp);
While Length(Temp)<8 Do Temp:=Temp+' ';
AdrPas:=2;
End;
End;
Source[Adr]^:=Source[Adr]^+Temp;
End;
End;
End;
End;
For I:=1 to AdrPas do
Begin
K:=38-Length(Source[Adr]^);
FillChar(Temp[1],K,' ');
Temp[0]:=Chr(K);
Source[Adr]^:=Source[Adr]^+Temp;
Str(Adr:3,Temp);
Source[Adr]^:=Source[Adr]^+';'+Temp;
Str(Mem[Adr]:5,Temp);
Source[Adr]^:=Source[Adr]^+' '+Temp;
Case Struct[Adr] AND 3 Of
1 : Source[Adr]^:=Source[Adr]^+' A';
2 : Source[Adr]^:=Source[Adr]^+' I';
3 : Source[Adr]^:=Source[Adr]^+' D';
End;
Inc(Adr);
Source[Adr]^:='';
End;
End;
End
Else
For I:=0 To LongMem-1 do
Begin
Str(Mem[I]:5,Source[I]^);
Str(I:4,Temp);
Source[I]^:=Source[I]^+' ;'+Temp;
Case Struct[I] AND 3 Of
1 : Source[I]^:=Source[I]^+' A';
2 : Source[I]^:=Source[I]^+' I';
3 : Source[I]^:=Source[I]^+' D';
End;
End;
End;
Function TInterpret.MakeInterior(R : TRect; Tpe : Byte) : PIntInterior;
Var R1 : TRect;
HScrollBar,
VScrollBar: PScrollBar;
Begin
R1.Assign(R.B.X - 1, R.A.Y + 1, R.B.X, R.B.Y - 1);
VScrollBar := New(PScrollBar, Init(R1));
VScrollBar^.Options := VScrollBar^.Options or ofPostProcess;
Insert(VScrollBar);
If Tpe=1 Then
Begin
R1.Assign(R.A.X + 2, R.B.Y - 1, R.B.X - 2, R.B.Y);
HScrollBar := New(PScrollBar, Init(R1));
HScrollBar^.Options := HScrollBar^.Options or ofPostProcess;
Insert(HScrollBar);
End Else HScrollBar:=NIL;
R.Grow(-1,-1);
MakeInterior := New(PIntInterior, Init(R, HScrollBar, VScrollBar,@Self,Tpe));
End;
Constructor TInterpret.Init(Nom : String);
Var I : Byte;
S : PDosStream;
R,R1 : TRect;
Dir : DirStr;
Name : NameStr;
Ext : ExtStr;
Temp : String;
P : PView;
Procedure InstalleStruct(Adr0 : Word);
Var Adr : Word;
Fini: Boolean;
Cod : Byte;
I : Word;
Procedure MetType(A : Word ; T : Byte);
Begin
Struct[A]:=(Struct[A] AND (Not 3)) + T;
End;
Procedure MetLabel(A : Word);
Begin
Struct[A]:=(Struct[A] AND 3) + (Etiq SHL 2);
Inc(Etiq);
End;
Begin
Adr:=Adr0;
Fini:=FALSE;
Repeat
If Struct[Adr] AND 3<>0 Then
Begin
If Struct[Adr] AND 3<>2 Then Error(12);
Exit;
End;
Cod:=Mem[Adr] DIV 1000;
Case Cod Of
00,
10,
30..36,
40..41,
50,51,53,
60 : MetType(Adr,2);
13 : Begin
MetType(Adr,2);
Inc(Adr);
MetType(Adr,3);
End;
11..12,
20..24,
52 : Begin
MetType(Adr,2);
Inc(Adr);
MetType(Adr,1);
MetLabel(Mem[Adr]);
If Cod=12 Then
If Struct[Mem[Adr]] AND 3 IN [1,2] Then Error(15);
If Cod IN [11..12] Then MetType(Mem[Adr],3);
End;
Else
Error(11);
End;
If Cod IN [60,53] Then Fini:=TRUE;
If Cod IN [21..24,52] Then InstalleStruct(Mem[Adr]);
If Cod=20 Then Adr:=Mem[Adr]
Else Inc(Adr);
Until Fini;
End;
Begin
DeskTop^.GetExtent(R);
R.Grow(-2,-2);
FSplit(Nom,Dir,Name,Ext);
TDialog.Init(R,Name);
S:=New(PDosStream,Init(Nom,stOpenRead));
LongMem:=S^.GetSize div 2;
S^.Read(Mem,LongMem*2);
Dispose(S,Done);
Etiq:=1;
FillChar(Struct,SizeOf(Struct),0);
For I:=0 to LongMem-1 do GetMem(Source[I],51);
InstalleStruct(0);
Desass:=FALSE;
ProduitListing;
GetExtent(R); R.Grow(0,-1);
R.A.X:=2;
R.B.X:=R.B.X-29;
R.B.Y:=R.B.Y-3;
Int:=MakeInterior(R,1);
Int^.GrowMode:=Int^.GrowMode OR gfGrowHiY OR gfGrowHiX;
Insert(Int);
R1.Assign(R.A.X+1,R.A.Y,R.A.X+5,R.A.Y+1);
Insert(New(PStaticText,Init(R1,'Code')));
GetExtent(R); R.Grow(0,-1);
R.A.X:=R.B.X-28;
R.B.X:=R.B.X-20;
R.B.Y:=R.B.Y-3;
Int:=MakeInterior(R,2);
Int^.GrowMode:=Int^.GrowMode OR gfGrowHiY OR gfGrowLoX OR gfGrowHiX;
Insert(Int);
R1.Assign(R.A.X+1,R.A.Y,R.A.X+5,R.A.Y+1);
P:=New(PStaticText,Init(R1,'Pile'));
P^.GrowMode:=P^.GrowMode OR gfGrowHiX OR gfGrowLoX; Insert(P);
R.A.Y:=R.B.Y-11;
R.A.X:=R.B.X+3;
R.B.X:=R.A.X+4;
R.B.Y:=R.A.Y+1;
P:=New(PStaticText,Init(R,'R0 ='));
P^.GrowMode:=P^.GrowMode OR gfGrowAll; Insert(P);
R1.Assign(R.A.X+5,R.A.Y,R.A.X+12,R.B.Y);
P:=New(PInputWord,Init(R1));
P^.GrowMode:=P^.GrowMode OR gfGrowAll; Insert(P);
R.A.Y:=R.B.Y;
R.B.Y:=R.A.Y+1;
P:=New(PStaticText,Init(R,'R1 ='));
P^.GrowMode:=P^.GrowMode OR gfGrowAll; Insert(P);
R1.Assign(R.A.X+5,R.A.Y,R.A.X+12,R.B.Y);
P:=New(PInputWord,Init(R1));
P^.GrowMode:=P^.GrowMode OR gfGrowAll; Insert(P);
R.A.Y:=R.B.Y;
R.B.Y:=R.A.Y+1;
P:=New(PStaticText,Init(R,'R2 ='));
P^.GrowMode:=P^.GrowMode OR gfGrowAll; Insert(P);
R1.Assign(R.A.X+5,R.A.Y,R.A.X+12,R.B.Y);
P:=New(PInputWord,Init(R1));
P^.GrowMode:=P^.GrowMode OR gfGrowAll; Insert(P);
R.A.Y:=R.B.Y;
R.B.Y:=R.A.Y+1;
P:=New(PStaticText,Init(R,'R3 ='));
P^.GrowMode:=P^.GrowMode OR gfGrowAll; Insert(P);
R1.Assign(R.A.X+5,R.A.Y,R.A.X+12,R.B.Y);
P:=New(PInputWord,Init(R1));
P^.GrowMode:=P^.GrowMode OR gfGrowAll; Insert(P);
R.A.Y:=R.B.Y;
R.B.Y:=R.A.Y+1;
P:=New(PStaticText,Init(R,'CO ='));
P^.GrowMode:=P^.GrowMode OR gfGrowAll; Insert(P);
R1.Assign(R.A.X+5,R.A.Y,R.A.X+12,R.B.Y);
P:=New(PInputWord,Init(R1));
P^.GrowMode:=P^.GrowMode OR gfGrowAll; Insert(P);
Dec(R.A.X,2);
R.B.X:=R.A.X+15;
R.A.Y:=R.B.Y+1;
R.B.Y:=R.A.Y+2;
P:=New(PButton,Init(R,'Desassemble',cmIntWDesassemble,bfNormal));
P^.GrowMode:=P^.GrowMode OR gfGrowAll; Insert(P);
R.A.Y:=R.B.Y;
R.B.Y:=R.A.Y+2;
P:=New(PButton,Init(R,'Un Pas',cmIntWUnPas,bfNormal));
P^.GrowMode:=P^.GrowMode OR gfGrowAll; Insert(P);
R.A.Y:=R.B.Y;
R.B.Y:=R.A.Y+2;
P:=New(PButton,Init(R,'Run',cmIntWRun,bfNormal));
P^.GrowMode:=P^.GrowMode OR gfGrowAll; Insert(P);
R.A.Y:=R.B.Y;
R.B.Y:=R.A.Y+2;
P:=New(PButton,Init(R,'Reset',cmIntWReset,bfNormal));
P^.GrowMode:=P^.GrowMode OR gfGrowAll; Insert(P);
GetExtent(R);
R.A.X:=12;
Dec(R.B.X,20);
R.A.Y:=R.B.Y-4;
R.B.Y:=R.A.Y+1;
R1.Assign(2,R.A.Y,11,R.B.Y);
P:=New(PStaticText,Init(R1,'Entrée : '));
P^.GrowMode:=P^.GrowMode OR gfGrowHiY OR gfGrowLoY; Insert(P);
P:=New(PInputLine,Init(R,60));
P^.GrowMode:=P^.GrowMode OR gfGrowHiX OR gfGrowHiY OR gfGrowLoY; Insert(P);
R.A.Y:=R.A.Y+2;
R.B.Y:=R.B.Y+2;
R1.Assign(2,R.A.Y,11,R.B.Y);
P:=New(PStaticText,Init(R1,'Sortie : '));
P^.GrowMode:=P^.GrowMode OR gfGrowHiY OR gfGrowLoY; Insert(P);
P:=New(PInputLine,Init(R,60));
P^.GrowMode:=P^.GrowMode OR gfGrowHiX OR gfGrowHiY OR gfGrowLoY; Insert(P);
Reset;
For I:=0 to 3 do Data.Regs[I]:=0;
Data.InM:='';
Options:=Options OR ofPreProcess;
Flags:=Flags OR wfGrow OR wfZoom;
End;
Procedure TInterpret.Reset;
Var I : Byte;
Begin
FillChar(Pile,SizeOf(Pile),0);
HautPile:=0;
Data.Co:=0;
Data.OutM:='';
Fin:=FALSE;
SetData(Data);
End;
Destructor TInterpret.Done;
Var I : Word;
Begin
For I:=0 To LongMem-1 do FreeMem(Source[I],51);
TDialog.Done;
End;
Procedure TInterpret.HandleEvent(Var Event : TEvent);
Begin
TDialog.HandleEvent(Event);
If Event.What=evCommand Then
Begin
GetData(Data);
Case Event.Command Of
cmIntWDesassemble : Begin Desass:=Not Desass; ProduitListing; End;
cmIntWRun : Run;
cmIntWUnPas : UnPas;
cmIntWReset : Reset;
Else
Exit;
End;
SetData(Data);
Int^.MoveTo(Data.CO);
ReDraw;
ClearEvent(Event);
End;
End;
Procedure TInterpret.UnPas;
Var TypOp : Byte;
ExOp : Byte;
R : Array[0..2] Of Byte;
I,J : Word;
Procedure SautConditionnel(Condition : Boolean);
Begin
Inc(Data.Co);
If Condition Then Data.Co:=Mem[Data.Co]-1;
End;
Procedure Empile(V : Word);
Begin
If HautPile=PilMax Then Error(13)
Else Begin Pile[HautPile]:=V; Inc(HautPile); End;
Int^.PileHaut;
End;
Function Depile : Word;
Begin
If HautPile=0 Then Error(14)
Else Begin Dec(HautPile); Depile:=Pile[HautPile]; End;
Int^.PileHaut;
End;
Begin
If VerifieCO Then Exit;
I:=Mem[Data.CO];
TypOp:=(I DIV 10000) MOD 10;
ExOp:=(I DIV 1000) MOD 10;
R[0]:=(I DIV 100) MOD 10;
R[1]:=(I DIV 10) MOD 10;
R[2]:=I MOD 10;
Case TypOp Of
1 : Case ExOp Of { Transferts }
0 : Data.Regs[R[0]]:=Data.Regs[R[1]];
1 : Begin
Inc(Data.Co);
Mem[Mem[Data.Co]]:=Data.Regs[R[0]];
ProduitListing;
End;
2 : Begin Inc(Data.Co); Data.Regs[R[0]]:=Mem[Mem[Data.Co]]; End;
3 : Begin Inc(Data.Co); Data.Regs[R[0]]:=Mem[Data.Co]; End;
End;
2 : Case ExOp Of { Sauts }
0 : SautConditionnel(TRUE);
1 : SautConditionnel(Data.Regs[R[0]]=0);
2 : SautConditionnel(Data.Regs[R[0]]<>0);
3 : SautConditionnel(Data.Regs[R[0]]>0);
4 : SautConditionnel(Data.Regs[R[0]]>=0);
End;
3 : Case ExOp Of { Operation }
0 : Data.Regs[R[0]]:=Data.Regs[R[1]]+Data.Regs[R[2]];
1 : Data.Regs[R[0]]:=Data.Regs[R[1]]-Data.Regs[R[2]];
2 : Data.Regs[R[0]]:=Data.Regs[R[1]]*Data.Regs[R[2]];
3 : Data.Regs[R[0]]:=Data.Regs[R[1]] DIV Data.Regs[R[2]];
4 : Data.Regs[R[0]]:= - Data.Regs[R[1]];
5 : Inc(Data.Regs[R[0]]);
6 : Dec(Data.Regs[R[0]]);
End;
4 : Case ExOp Of { Entrée Sortie }
0 : Begin
If Data.InM='' Then {???};
Data.Regs[0]:=Ord(Data.InM[1]);
Data.InM:=Copy(Data.InM,2,Length(Data.InM)-1);
End;
1 : Data.OutM:=Data.OutM+Chr(Data.Regs[0]);
End;
5 : Case ExOp Of { Gestion pile }
0 : Empile(Data.Regs[R[0]]);
1 : Data.Regs[R[0]]:=Depile;
2 : Begin
Empile(Data.CO+2);
Data.Co:=Mem[Data.Co+1]-1;
End;
3 : Data.Co:=Depile-1;
End;
6 : Fin:=TRUE; { END }
End;
If Not Fin Then Inc(Data.CO);
End;
Procedure TInterpret.Run;
Begin
If VerifieCO Then Exit;
Repeat UnPas;
Until Fin;
End;
{$ENDIF}
{======================================================================
Application
======================================================================}
Const
cmAbout = 100;
cmHorloge = 101;
cmAssCharge = 102;
cmAssSauve = 103;
cmIntCharge = 104;
cmIntSauve = 105;
Type
TMonApp = Object(TApplication)
Constructor Init;
Procedure HandleEvent(Var Event : TEvent); Virtual;
Procedure InitMenuBar; Virtual;
Procedure OutOfMemory; Virtual;
Procedure AssCharge;
Procedure AssSauve;
Procedure IntCharge;
Procedure Horloge;
End;
Procedure TMonApp.Horloge;
Var R : TRect;
P : PView;
Begin
{$IFDEF Hor}
P:=Message(DeskTop,evBroadCast,cmClockSearch,nil);
If P=NIL
Then
Begin
R.Assign(10,5,40,12);
P:=ValidView(New(PClock,Init(R)));
If P<>NIL Then DeskTop^.Insert(P);
End
Else P^.Select;
{$ENDIF}
End;
Procedure TMonApp.OutOfMemory;
Begin
SignaleError('Pas assez de mémoire pour l''opération');
End;
Procedure TMonApp.IntCharge;
{$IFDEF Int}
Var D : PFileDialog;
FileName : PathStr;
I : PInterpret;
begin
D := PFileDialog(ValidView(New(PFileDialog, Init('*.BIN',
'Charge un fichier code','~N~om', fdOkButton, 100))));
If D<>Nil Then
Begin
If Desktop^.ExecView(D) <> cmCancel then
Begin
D^.GetFileName(FileName);
I:=PInterpret(ValidView(New(PInterpret,Init(FileName))));
If I<>Nil Then DeskTop^.Insert(I);
End;
Dispose(D, Done);
End;
{$ELSE}
Begin
{$ENDIF}
End;
Procedure TMonApp.AssCharge;
{$IFDEF Ass}
Var D : PFileDialog;
FileName : PathStr;
A : PAssembleur;
begin
D := PFileDialog(ValidView(New(PFileDialog, Init('*.ASM',
'Charge un fichier source','~N~om', fdOkButton, 100))));
If D<>Nil Then
Begin
If Desktop^.ExecView(D) <> cmCancel then
Begin
D^.GetFileName(FileName);
A:=PAssembleur(ValidView(New(PAssembleur,Init(FileName))));
If A<>Nil Then DeskTop^.Insert(A);
End;
Dispose(D, Done);
End;
{$ELSE}
Begin
{$ENDIF}
End;
Procedure TMonApp.AssSauve;
{$IFDEF Ass}
Var D : PFileDialog;
FileName : PathStr;
A : PAssembleur;
begin
A:=Message(DeskTop,evBroadCast,cmIsAssW,nil);
D := PFileDialog(ValidView(New(PFileDialog, Init('*.BIN',
'Charge un fichier source','~N~om', fdOkButton, 100))));
If D<>Nil Then
Begin
If Desktop^.ExecView(D) <> cmCancel then
Begin
D^.GetFileName(FileName);
A^.Sauve(FileName);
End;
Dispose(D, Done);
End;
{$ELSE}
Begin
{$ENDIF}
End;
Procedure TMonApp.InitMenuBar;
Var R : TRect;
Begin
GetExtent(R);
R.B.Y:=R.A.Y+1;
MenuBar:=New(PMenuBar,Init(R,NewMenu(
NewSubMenu('≡',hcNoContext,NewMenu(
NewItem('~H~orloge...','',0,cmHorloge,hcNoContext,
NewItem('~Q~uitter...','Alt-X',kbAltX,cmQuit,hcNoContext,
nil))),
NewSubMenu('~A~ssembleur',hcNoContext,NewMenu(
NewItem('~C~harger source...','',0,cmAssCharge,hcNoContext,
NewItem('~S~auver code...','F3',kbF3,cmAssSauve,hcNoContext,
nil))),
NewSubMenu('~I~nterpréteur',hcNoContext,NewMenu(
NewItem('~C~harger code...','',0,cmIntCharge,hcNoContext,
NewItem('~S~auver source...','F3',kbF3,cmIntSauve,hcNoContext,
nil))),
nil))))));
End;
Constructor TMonApp.Init;
Begin
TApplication.Init;
End;
Procedure TMonApp.HandleEvent(Var Event : TEvent);
Begin
TApplication.HandleEvent(Event);
If Event.What=evCommand Then
Begin
Case Event.Command Of
cmAssCharge : AssCharge;
cmAssSauve : AssSauve;
cmIntCharge : IntCharge;
cmHorloge : Horloge;
Else
Exit;
End;
ClearEvent(Event);
End;
Message(DeskTop,evBroadCast,cmClockUpDate,nil);
End;
Var MonApp : TMonApp;
BEGIN
MonApp.Init;
MonApp.Run;
MonApp.Done;
END.