Program MADM_Prototype_Simulator(input,output);

{ Desc : Non-Graphics Based MADM Mk-I Prototype Simulator Program }
{        Written for Turbo Pascal V6.0                            }

Uses
    CRT;

Const
    Trace = False; {True;}  {False}

Type
    LineType = LongInt;
    StoreType = array[0..31] of LineType;

Var
    A  : LineType;      { Accumulator Tube }
    CI : LineType;      { Control Tube - Current Instruction Line }
    PI : LineType;      { Control Tube - Program Instruction Line }
    S  : StoreType;     { Store Tube - 32 x 32 bits }
    Run : boolean;


Procedure ClearStore(var S : StoreType);

{ Desc : Zeros out Store Tube }

var
    i : integer;

begin {ClearStore}
    for i := 0 to 31 do
	S[i] := 0;
end;  {ClearStore}


Procedure Execute(var A, CI, PI : LineType;
		  var S : StoreType;
		  var Run : Boolean);

{ Desc : Executes One Madm Mk I Instruction
	 CI := CI + 1;
	 PI := S[CI]
	 Instruction PI is executed }

var
    Fcn,
    Line       : LongInt;

begin  { Execute }
    CI := (CI + 1) Mod 32;               { Increment CI }
    PI := S[CI];                         { Fetch current instruction}

    Fcn :=  (PI AND $0000E000) SHR 13;   { Extract Opcode }
    Line := (PI AND $0000001F);          { Extract Operand }

    Case Fcn of                          { Execute }
	0 : CI := S[Line];                    { Jump }
	1 : CI := CI + S[Line];               { Jump relative }
	2 : A := -S[Line];                    { Load Negative }
	3 : S[Line] := A;                     { Store }
	4 : A := A - S[line];                 { Subtract }
	5 : A := A - S[Line];                 {     "    }
	6 : If A < 0 Then                     { Skip if A < 0 }
		CI := (CI + 1) AND $0000001F;
	7 : Run := False;                     { Halt }
     end ; (* case *)

end; { Execute }


Function Assemble(Op : String; Line : Integer):LongInt;

{ Desc : Assembler Utility to Generate Madm Mk I Code. Converts
	 the string 'JMP', 'JMR', 'LDN', 'STO', 'SUB', 'SKN',
	 and 'HLT' to corresponding Madm Mk I codes. Line is
	 operand address from 0 to 31 }

Begin {Assemble}
    if Op = 'JMP' then
	Assemble := $0000 + Line Mod 32
    else if OP = 'JMR' then
	Assemble := $2000 + Line Mod 32
    else if OP = 'LDN' then
	Assemble := $4000 + Line Mod 32
    else if OP = 'STO' then
	Assemble := $6000 + Line Mod 32
    else if OP = 'SUB' then
	Assemble := $8000 + Line Mod 32
    else if OP = 'SKN' then
	Assemble := $C000 + Line Mod 32
    else if OP = 'HLT' then
	Assemble := $E000 + Line Mod 32
end; {Assemble}


Procedure TextDisplayStore(A, CI, PI : LineType;
			   var S : StoreType);

{ Desc : Displays A, C, and Store Tubes }

var
    i : integer;

    procedure WriteLineType(var L : LineType);

    var
	j : LongInt;
    begin
	for j := 0 to 31 do
	    if L AND (1 SHL j) <> 0 then
		write(output,'1')
	    else
		write(output,'0');
    end;

Begin {TextDisplayStore}
    CRT.ClrScr;
    CRT.GotoXY(1,3);
    write(output,'A    ');
    WriteLineType(A);

    CRT.GotoXY(42,3);
    write(output,'CI   ');
    WriteLineType(CI);
    CRT.GotoXY(42,4);
    write(output,'PI   ');
    WriteLineType(PI);

    for i := 0 to 15 do
	begin
	CRT.GotoXY(1, 6+i);
	write(output,'S' + chr(i DIV 10 + 48) + chr(i MOD 10 + 48)+'  ');
	WriteLineType(S[i]);
	end;

    for i := 16 to 31 do
	begin
	CRT.GotoXY(42, i - 10);
	write(output,'S' + chr(i DIV 10 + 48) + chr(i MOD 10 + 48)+'  ');
	WriteLineType(S[i]);
	end;

    CRT.GotoXY(1,25);
End;{TextDisplayStore}


Procedure  Multiply(var S : StoreType);

{ Desc : Assembles Multiplication Routine for Madm Mk I
	 S[31] := S[30] * S[29]                           }

begin
    S[1] := Assemble('LDN',30);
    S[2] := Assemble('SKN',0);
    S[3] := Assemble('JMP',27);
    S[4] := Assemble('SUB',28);
    S[5] := Assemble('STO',30);
    S[6] := Assemble('LDN',30);
    S[7] := Assemble('STO',30);
    S[8] := Assemble('LDN',31);
    S[9] := Assemble('SUB',29);
    S[10] := Assemble('STO',31);
    S[11] := Assemble('LDN',31);
    S[12] := Assemble('STO',31);
    S[13] := Assemble('JMP',0);
    S[14] := Assemble('HLT',0);
    S[27] := 13;
    S[28] := -1;
    S[29] := 16;
    S[30] := 16;
    S[31] := 0;
end;


Procedure FreezeDisplay;

{ Desc : Freezes Display until Key Pressed }

var
    ch : char;

begin {FreezeDisplay}
    CRT.GotoXY(28,25);
    write(output,'Hit Any Key to Continue');
    While Not CRT.KeyPressed do;
    ch := CRT.ReadKey;
end; {FreezeDisplay}


Begin  { Main Code Sequence }

    { Zero Out A, C, and Store Tubes }

    A := 0;
    CI := 0;
    PI := 0;
    ClearStore(S);

    { Enter Program Instructions Here }

    Multiply(S);

    { Execute Program }

    Run := True;
    While Run Do
	begin
	if Trace then
	    begin
	    TextDisplayStore(A, CI, PI, S);
	    FreezeDisplay;
	    end;
	Execute(A, CI, PI, S, Run);
	end;

    { Signal End and Display Store }

    CRT.Sound(250);
    CRT.Delay(400);
    CRT.NoSound;
    TextDisplayStore(A, CI, PI, S);

    { Pause Display }

    FreezeDisplay;

End.