這裏的虛擬機是是Tiny語言的運行環境,源代碼如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#define IADDR_SIZE 1024 //指令存儲區大小
#define DADDR_SIZE 1024 //數據區大小
#define No_REGS 8 //寄存器數量
#define PC_REG 7 //程序寄存器,只有這一個爲專用寄存器
//操作符類型
typedef enum
{
opclRR, //寄存器操作
opclRM, //寄存器&內存操作
opclRA, //寄存器&地址操作
}OPCLASS;
//opCode定義
typedef enum {
opHALT,
opIN,
opOUT,
opADD,
opSUB,
opMUL,
opDIV,
opRRLim,
opLD,
opST,
opRMLim,
opLDA,
opLDC,
opJLT,
opJLE,
opJGT,
opJGE,
opJEQ,
opJNE,
opRALim
} OPCODE;
char * opCodeTab[]
= {"HALT","IN","OUT","ADD","SUB","MUL","DIV","????",
"LD","ST","????",
"LDA","LDC","JLT","JLE","JGT","JGE","JEQ","JNE","????"
};
int iloc = 0 ;
int dloc = 0 ;
int traceflag = FALSE;
int icountflag = FALSE;
typedef enum {
srOKAY,
srHALT,
srIMEM_ERR,
srDMEM_ERR,
srZERODIVIDE
} STEPRESULT;
char * stepResultTab[]
= {"OK","Halted","Instruction Memory Fault",
"Data Memory Fault","Division by 0"
};
//指令定義
typedef struct {
int iop ;
int iarg1 ;
int iarg2 ;
int iarg3 ;
} INSTRUCTION;
//指令區
INSTRUCTION iMem[IADDR_SIZE];
//內存區
int dMem[DADDR_SIZE];
//寄存器
int reg[No_REGS];
FILE *pgm;
#define LINESIZE 256
#define WORDSIZE 20
char in_Line[LINESIZE];
int lineLen;
int inCol;
int num;
char word[WORDSIZE];
char ch;
int done;
//取得本行中下一個不是空格的字符
int nonBlank(void)
{
while((inCol<lineLen)
&& (in_Line[inCol]==' '))
inCol++;
if(inCol<lineLen)
{
ch=in_Line[inCol];
return TRUE;
}
else
{
ch=' ';
return FALSE;
}
}
int atEOL(void)
{ return ( ! nonBlank ());
}
//得到下一個字符
void getCh()
{
if(++inCol<lineLen)
ch=in_Line[inCol];
else
ch = '
';
}
//跳過一個字符
int skipCh(char c)
{
int temp = FALSE;
if(nonBlank() &&
(ch==c))
{
getCh();
temp=TRUE;
}
return temp;
}
//得到下一個單詞
int getWord()
{
int temp = FALSE;
int length=0;
if(nonBlank())
{
while(isalnum(ch))
{
if(length<WORDSIZE-1)
word[length++]=ch;
getCh();
}
word[length] = '\0';
temp = (length!=0);
}
return temp;
}
//得到本行中的一個整數
int getNum()
{
int sign;
int term;
int temp=FALSE;
num=0;
do{
sign =1;
while(nonBlank() && ((ch=='+') ||
(ch=='-')))
{
temp =
FALSE;
if(ch=='-')
sign=-sign;
getCh();
}
term = 0;
nonBlank();
while(isdigit(ch))
{
temp =
TRUE;
term = term *
10 + ch - '0';
getCh();
}
num = num + (term*sign);
}
while(nonBlank()
&& ((ch=='+') || (ch=='-')));
return temp;
}
int error( char * msg, int lineNo, int instNo)
{ printf("Line %d",lineNo);
if (instNo >= 0) printf("
(Instruction %d)",instNo);
printf("
%s\n",msg);
return FALSE;
}
int opClass( int c )
{
if
( c <= opRRLim) return ( opclRR );
else if ( c <= opRMLim) return (
opclRM );
else
return ( opclRA );
}
//讀取指令
int readInstructions()
{
OPCODE op;
int arg1, arg2, arg3;
int regNo;
int loc;
int lineNo;
//寄存器清零
for(regNo=0; regNo<No_REGS;
regNo++)
reg[regNo]=0;
//初始化數據區
dMem[0]=DADDR_SIZE-1;
for(loc=1; loc < DADDR_SIZE;
loc++)
dMem[loc]=0;
//初始化指令區
for(loc=0;loc<IADDR_SIZE;loc++)
{
iMem[loc].iop = opHALT;
iMem[loc].iarg1=0;
iMem[loc].iarg2=0;
iMem[loc].iarg3=0;
}
lineNo = 0;
while(!feof(pgm))
{
//讀入一行代碼
fgets(in_Line, LINESIZE,
pgm);
inCol=0;
lineNo++;
lineLen=strlen(in_Line)-1;
if(in_Line[lineLen]=='\n')
in_Line[lineLen]='\0';
if(nonBlank()
&& ch!='*') /
r = currentinstruction.iarg1 ;
s = currentinstruction.iarg2 ;
t = currentinstruction.iarg3 ;
break;
case
opclRM :
r = currentinstruction.iarg1 ;
s = currentinstruction.iarg3 ;
m = currentinstruction.iarg2 + reg[s] ; //此時m代表數據區地址
if ( (m < 0) || (m >
DADDR_SIZE))
return srDMEM_ERR ;
break;
case
opclRA :
r = currentinstruction.iarg1 ;
s = currentinstruction.iarg3 ;
m = currentinstruction.iarg2 + reg[s] ;
break;
}
switch ( currentinstruction.iop)
{
case opHALT
:
printf("HALT: %1d,%1d,%1d\n",r,s,t);
return srHALT ;
case opIN
:
do
{ printf("Enter value for IN instruction: ") ;
fflush (stdin);
fflush (stdout);
gets(in_Line);
lineLen = strlen(in_Line) ;
inCol = 0;
ok = getNum();
if ( ! ok ) printf ("Illegal value\n");
else reg[r] = num;
}
while (! ok);
break;
case
opOUT :
printf ("OUT instruction prints: %d\n", reg[r] ) ;
break;
case opADD
: reg[r] = reg[s] + reg[t] ;
break;
case opSUB
: reg[r] = reg[s] - reg[t] ;
break;
case opMUL
: reg[r] = reg[s] * reg[t] ;
break;
case
opDIV :
if ( reg[t] != 0 ) reg[r] = reg[s] / reg[t];
else return srZERODIVIDE ;
break;
case opLD
: reg[r] =
dMem[m] ; break; //數據區複製給寄存器
case opST
: dMem[m] =
reg[r] ; break; //寄存器複製給數據區
case opLDA
: reg[r] = m
; break;
case opLDC
: reg[r] =
currentinstruction.iarg2 ;
break;
case opJLT
: if ( reg[r]
< 0 ) reg[PC_REG] = m ;
break;
case opJLE
: if ( reg[r]
<= 0 ) reg[PC_REG] = m ;
break;
case opJGT
: if ( reg[r]
> 0 ) reg[PC_REG] = m ;
break;
case opJGE
: if ( reg[r]
>= 0 ) reg[PC_REG] = m ;
break;
case opJEQ
: if ( reg[r]
== 0 ) reg[PC_REG] = m ; break;
case opJNE
: if ( reg[r]
!= 0 ) reg[PC_REG] = m ; break;
}
return srOKAY ;
return srOKAY;
}
//執行指令
int doCommand (void)
{ char cmd;
int stepcnt=0, i;
int printcnt;
int stepResult;
int regNo, loc;
do
{ printf ("Enter command: ");
fflush
(stdin);
fflush
(stdout);
gets(in_Line);
lineLen =
strlen(in_Line);
inCol =
0;
}
while (! getWord ());
cmd = word[0] ;
switch ( cmd )
{ case 't' :
traceflag = ! traceflag ;
printf("Tracing now ");
if ( traceflag ) printf("on.\n"); else printf("off.\n");
break;
case 'h'
:
printf("Commands are:\n");
printf(" s(tep
<n>
"\
"Execute n (default 1) TM instructions\n");
printf("
g(o
"\
"Execute TM instructions until HALT\n");
printf("
r(egs
"\
"Print the contents of the registers\n");
printf(" i(Mem
<b
<n>>
"\
"Print n iMem locations starting at b\n");
printf(" d(Mem
<b
<n>>
"\
"Print n dMem locations starting at b\n");
printf("
t(race
"\
"Toggle instruction trace\n");
printf("
p(rint
"\
"Toggle print of total instructions executed"\
" ('go' only)\n");
printf("
c(lear
"\
"Reset simulator for new execution of program\n");
printf("
h(elp
"\