{Program for EE 373 Lab, Tuesdays 12:30, T.A. Aihua Li, June 1, 1990} {Matthew J. Reid and Scott Langley} {Program Name is Sammy.Pas, using Turbo Pascal 4.0} {If any problems call 737-9465} program Simulator; type Memory=array [0..255] of shortint; Registers=array [10..13] of shortint; var MDR:shortint; MAR,Z,PC:byte; Mem:Memory; Regs:Registers; Info,Instr,Source,Dest,Add_Mode,Jump_Dest:string; SourceDec,SourceVal,DestDec,DestVal,Jump_DestVal:integer; Sp:byte; {string pointer to input string} Len:byte; D_Reg,S_Reg,No_Error:boolean; procedure Initialize; {Sets Memory, PC, and Registers equal to zero} var i,j:byte; begin for i:=0 to 255 do Mem[i]:=0; for i:=10 to 13 do Regs[i]:=0; Z:=0; PC:=0; No_Error:=true end; procedure Main; {main procedure that fetches, computes, and prints results of an instruction} var Oc:char; procedure Error(number:byte); {Prints appropriate message for any error} var E:string; begin if No_Error then begin No_Error:=false; case number of 1: E:='This is not a hexedecimal character.'; 2: E:='Number out of range: [-7F, 80].'; 3: E:='Number out of range: [0,FF].'; 4: E:='More input is needed for this instruction.'; 5: E:='Invalid address mode. Choose: 0, 1, or 2.'; 6: E:='Overflow. (Values below are incorrect.)'; 7: E:='Source and Destination cannot both be memory.'; 8: E:='Source is not a valid register.'; 9: E:='Invalid instruction.' end; writeln('Error: ',E); writeln; end; end; procedure Hex_to_Dec(Hexer:string;var Decer:integer); {Converts a hexidecimal string to a decimal number} var How_long,I,J,K:byte; Number,Sign:integer; begin How_long:=length(Hexer); I:=How_long; J:=0; Number:=0; Sign:=1; repeat Oc:=Hexer[I]; case Oc of 'A','B','C','D','E','F': K:=ord(Oc) - ord('A')+10; '0','1','2','3','4','5','6','7','8','9':K:=ord(Oc) - ord('0'); else begin if (Hexer[1]='-') then begin Sign:=-1; K:=0; end else Error(1); end; end; Number:=Number + round(K*exp(J*ln(16))); I:=I - 1; J:=J + 1; until (I<=0); Decer:=Sign * Number; end; procedure Dec_to_Hex(Value:integer;var Valuehex:string); {Converts a decimal number to a hexidecimal string} var I:integer; begin Valuehex:=''; if Value < 0 then Valuehex:='-'; Value:=abs(Value); I:=Value div 16; case I of 0,1,2,3,4,5,6,7,8,9: Valuehex:=Valuehex + chr(ord('0') + I); 10,11,12,13,14,15: Valuehex:=Valuehex + chr(ord('A') + I - 10); end; I:=Value mod 16; case I of 0,1,2,3,4,5,6,7,8,9: Valuehex:=Valuehex + chr(ord('0') + I); 10,11,12,13,14,15: Valuehex:=Valuehex + chr(ord('A') + I - 10); end end; procedure Get_param(var Param:string); {Get whatever parameter we need from the info string} begin if No_Error then begin Param:=''; repeat Oc:=Info[Sp]; Sp:=Sp + 1; until (Oc <> ' ') or (Sp=Len + 2); if Sp=Len + 2 then Error(4) else begin Sp:=Sp - 1; repeat Param:=Param + Oc; Sp:=Sp + 1; Oc:=Info[Sp]; until (Oc=' ') or (Sp=Len + 2); if Sp=Len + 2 then Error(4) end end end; procedure Check_param(Param:string; var ParamDec:integer; var Reg:boolean); {used to check validity and change form of Source and Destination} var How_long,I,N,M:byte; Oc:char; begin if No_Error then begin How_long:=length(Param); Reg:=false; if How_long=1 then begin Oc:=Param[1]; case Oc of 'A','B','C','D': Reg:=true; end end; Hex_to_Dec(Param,ParamDec); end end; procedure Get_Dest_AddMode_Source; {Get Destination, Address Mode and Source for instructions that require it} procedure Check_Add_Mode; {Check the validity of the Address Mode} begin if No_Error then begin if length(Add_Mode) > 1 then Error(5) else begin Oc:=Add_Mode[1]; case Oc of '0','1','2': ; else Error(5); end end end end; begin Get_param(Dest); Check_param(Dest,DestDec,D_Reg); if D_Reg then DestVal:=Regs[DestDec] else if((DestVal > 255)or(DestVal < 0)) then Error(2) else DestVal:=Mem[DestDec]; Get_param(Add_Mode); Check_Add_Mode; Get_param(Source); Check_param(Source,SourceDec,S_Reg); if No_Error then begin if ((S_Reg=true) and (Add_Mode='0')) then SourceVal:=Regs[SourceDec] else if Add_Mode='1' then begin if ((SourceDec > 255) or (SourceDec < 0)) then Error(2) else SourceVal:=Mem[SourceDec]; if ((D_Reg=false) and (S_Reg=false)) then Error(7) end else if Add_Mode='2' then begin Hex_to_Dec(Source,SourceVal); if ((SourceVal > 127) or (SourceVal < -128)) then Error(2); end else Error(8); {add mode=0 but s_reg not true} end; end; procedure Get_Dest; {Get the destination for instructions only needing a destination operand} begin Get_param(Dest); Check_param(Dest,DestDec,D_Reg); if ((DestDec > 255) or (DestDec < 0)) then Error(3) else begin if (D_Reg=true) then DestVal:=Regs[DestDec] else DestVal:=Mem[DestDec]; Add_Mode:=' '; end end; procedure Get_Jump_Dest; {Get the destination address for a Jump instruction} begin Get_param(Jump_Dest); Hex_to_dec(Jump_Dest,Jump_DestVal); if ((Jump_DestVal > 255) or (Jump_DestVal < 0)) then begin Error(3); Jump_DestVal:=PC; end end; procedure Print(Name:string;Value:integer); {Prints any machine location sent to it and its contents} var Valuehex:string; begin Dec_to_Hex(Value,Valuehex); writeln(Name,' = ',Valuehex) end; procedure Store_n_Print; {Stores the instruction result in the appropriate memory or register and} {prints out any machine locations that were changed by the instruction} begin if No_Error then begin if (DestVal > 127) then begin DestVal:=Destval mod 127; Error(6); end; if (DestVal < -128) then begin DestVal:=DestVal mod -128; Error(6); end; if D_Reg=true then begin Regs[DestDec]:=DestVal; Print(Dest,DestVal); if Add_Mode='1' then begin print('MAR',SourceDec); print('MDR',SourceVal) end end else if (instr[1] <> 'J') then begin Mem[DestDec]:=DestVal; Print('MAR',DestDec); Print('MDR',DestVal) end; if Regs[10]=0 then Z:=1 else Z:=0; Print('Z',Z); PC:=PC + 1; Print('PC',PC); writeln; DestVal:=0; Dest:=''; D_Reg:=false; end; end; procedure Get_instr; {Input from the user the instruction to be processed and store it in Info} begin write('>'); Info:=' '; readln(Info); Len:=length(Info); for Sp:=1 to Len do begin Oc:=Info[Sp]; Oc:=UpCase(Oc); Info[Sp]:=Oc end; Sp:=1; Get_param(Instr) end; procedure Adder; {Add} begin Get_Dest_AddMode_Source; DestVal:=DestVal + SourceVal; Store_n_Print end; procedure Suber; {Subtract} begin Get_Dest_AddMode_Source; DestVal:=DestVal - SourceVal; Store_n_Print; end; procedure Inc; {Increment} begin Get_Dest; DestVal:=DestVal + 1; Store_n_Print end; procedure Dec; {Decrement} begin Get_Dest; DestVal:=DestVal - 1; Store_n_Print end; procedure Ander; {And} begin Get_Dest_AddMode_Source; DestVal:=DestVal and SourceVal; Store_n_Print end; procedure Orer; {Or} begin Get_Dest_AddMode_Source; DestVal:=DestVal or SourceVal; Store_n_Print end; procedure Move; {Move} begin Get_Dest_AddMode_Source; DestVal:=SourceVal; Store_n_Print end; procedure Shler; {Shift left} begin Get_Dest; DestVal:=DestVal * 2; Store_n_Print end; procedure Shrer; {Shift right} begin Get_Dest; DestVal:=DestVal div 2; Store_n_Print end; procedure Jmp; {Jump} begin Get_Jump_Dest; PC:=Jump_DestVal - 1; Store_n_Print end; procedure Jz; {Jump if Z is set} begin Get_Jump_Dest; if Regs[10] = 0 then PC:=Jump_DestVal - 1; Store_n_Print end; procedure Rst; {Restore registers and PC} begin PC:=0; Z:=1; Regs[10]:=0; Regs[11]:=0; Regs[12]:=0; Regs[13]:=0; writeln('A = ',Regs[10]); writeln('B = ',Regs[11]); writeln('C = ',Regs[12]); writeln('D = ',Regs[13]); writeln('Z = ',Z); writeln('PC = ',PC); writeln end; begin Get_instr; if Instr='ADD' then Adder else if Instr='SUB' then Suber else if Instr='INC' then Inc else if Instr='DEC' then Dec else if Instr='AND' then Ander else if Instr='OR' then Orer else if Instr='MOV' then Move else if Instr='SHL' then Shler else if Instr='SHR' then Shrer else if Instr='JMP' then Jmp else if Instr='JZ' then Jz else if Instr='RST' then Rst else if Instr='END' then else Error(9); No_Error:=true; end; {Program starts here} begin Initialize; repeat Main; until (Instr='END'); writeln; writeln('Session Terminated.'); writeln(' Good-Bye!'); writeln; end.