Problem1391--实现一个模拟器,将1383题中编译器生成的文件执行一下,验证1383中的编译器是否正常工作,将汇编源程序编译之后的二进制文件运行,查看结果是否正确

1391: 实现一个模拟器,将1383题中编译器生成的文件执行一下,验证1383中的编译器是否正常工作,将汇编源程序编译之后的二进制文件运行,查看结果是否正确

Time Limit: 1 Sec  Memory Limit: 128 MB
Submit: 20  Solved: 2
[Submit] [Status] [Web Board] [Creator:]

Description

C语言编制一个模拟器,能够模拟简单计算机执行汇编程序生成的目标代码,得到运行结果。

1383题中使用的汇编指令系统如下:



32条指令以及伪指令和它们的功能如下:

(1) 停机指令:HLT

功能:终止程序运行。

(2) 无条件转移指令:JMP label

功能:将控制转移至标号label处,执行标号label后的指令。

(3) 比较运算转移指令:CJMP label

功能:如果程序状态字中比较标志位c的值为1(即关系运算的结果为真),则将控制转移至标号label处,执行标号label后的指令;否则,顺序往下执行。

(4) 溢出转移指令:OJMP

功能:如果程序状态字中比较标志位o的值为1(即算术运算的结果发生溢出),则将控制转移至标号label处,执行标号label后的指令;否则,顺序往下执行。

(5) 调用子程序指令:CALL label

功能:将通用寄存器A~G、程序状态字PSW、程序计数器PC中的值保存到ES,然后调用以标号label开始的子程序,将控制转移至标号label处,执行标

 

(6) 子程序返回指令:RET

功能:将ES中保存的通用寄存器A~Z、程序状态字PSW和程序字数器PC的值恢复,控制转移到子程序被调用的地方,执行调用指令的下一条指令。

(7) 入栈指令:PUSH reg0

功能:将通用寄存器reg0的值压入堆栈SS,reg0可以是A~G和Z八个通用寄存器之一。

(8) 出栈指令:POP reg0

功能:从堆栈SS中将数据出栈到寄存器reg0,reg0可以是A~G七个通用寄存器之一,但不能是通用寄存器Z。

(9) 取字节数据指令:LOADB reg0 symbol

功能:从字节数据或字节数据块symbol中取一个字节的数据存入寄存器reg0,所取的字节数据在数据块symbol中的位置由寄存器G的值决定。用C的语法可将此指令的功能描述为:

reg0 = symbol[G]

例如,假设用伪指令定义了以下字节数据块num:

BYTE num[10] = {5,3,2,8,6,9,1,7,4,0}

如果要将字节数据块num中第5个单元的值(即下标为4的元素)取到寄存器C,指令如下:

LOADI G 5

LOADB C num

后面的指令LOADW、STOREB和STOREW在操作上与此指令类似。

(10) 取双字节数据指令:LOADW reg0 symbol

功能:从双字节数据或双字节数据块symbol中取一个双字节的数据存入寄存器reg0,所取的双字节数据在数据块symbol中的位置由寄存器G的值决定。

(11) 存字节数据指令:STOREB reg0 symbol

功能:将寄存器reg0的值存入字节数据或字节数据块symbol中的某个单元,存入单元的位置由寄存器G的值决定。用C的语法可将此指令的功能描述为:

symbol[G] = reg0

(12) 存双字节数据指令:STOREW reg0 symbol

功能:将寄存器reg0的值存入双字节数据或双字节数据块symbol中的某个单元,存入单元的位置由寄存器G的值决定。

 

(13) 取立即数指令:LOADI reg0 immediate

功能:将指令中的立即数immediate存入寄存器reg0。立即数被当作16位

有符号数,超出16位的高位部分被截掉。例如:

LOADI B 65535

寄存器B的值为-1。

LOADI B 65537

寄存器B的值为1。

(14) 空操作指令:NOP

功能:不执行任何操作,但耗用一个指令执行周期。

(15) 控制台输入指令:IN reg0 0

功能:从输入端口(即键盘输入缓冲区)取一个字符数据,存入寄存器reg0。

(16) 控制台输出指令:OUT reg0 15

功能:将寄存器reg0的低字节作为字符数据输出到输出端口(即显示器)。

(17) 加运算指令:ADD reg0 reg1 reg2

功能:将寄存器reg1的值加上reg2的值,结果存入寄存器reg0。如果结

果超过16位有符号数的表示范围,将发生溢出,使程序状态字的溢出标志位o置为1;如果未发生溢出,则使程序状态字的溢出标志位o置为0。

(18) 加立即数指令:ADDI reg0 immediate

功能:将寄存器reg0的值加上立即数immediate,结果仍存入寄存器reg0。如果结果超过16位有符号数的表示范围,将发生溢出,使程序状态字的溢出标

志位o置为1;如果未发生溢出,则使程序状态字的溢出标志位o置为0。

(19) 减运算指令:SUB reg0 reg1 reg2

功能:将寄存器reg1的值减去reg2的值,结果存入寄存器reg0。如果结

果超过16位有符号数的表示范围,将发生溢出,使程序状态字的溢出标志位o置为1;如果未发生溢出,则使程序状态字的溢出标志位o置为0。

(20) 减立即数指令:SUBI reg0 immediate

功能:将寄存器reg0的值减去立即数immediate,结果仍存入寄存器reg0。如果结果超过16位有符号数的表示范围,将发生溢出,使程序状态字的溢出标

志位o置为1;如果未发生溢出,则使程序状态字的溢出标志位o置为0。

(21) 乘运算指令:MUL reg0 reg1 reg2

功能:将寄存器reg1的值乘以reg2的值,结果存入寄存器reg0。

如果结果超过16位有符号数的表示范围,将发生溢出,使程序状态字的溢出标志位置为1;如果未发生溢出,则使程序状态字的溢出标志位o置为0。

(22) 除运算指令:DIV reg0 reg1 reg2

功能:将寄存器reg1的值除以reg2的值,结果存入寄存器reg0,这里进

行的是整数除运算。如果寄存器reg2的值为零,将发生除零错。

(23) 按位与运算指令:AND reg0 reg1 reg2

功能:将寄存器reg1的值与reg2的值进行按位与运算,结果存入寄存器

reg0。

(24) 按位或运算指令:OR reg0 reg1 reg2

功能:将寄存器reg1的值与reg2的值进行按位或运算,结果存入寄存器

reg0。

(25) 按位异或运算指令:NOR reg0 reg1 reg2

功能:将寄存器reg1的值与reg2的值进行按位异或(按位加)运算,结果存

入寄存器reg0。

(26) 按位取反运算指令:NOTB reg0 reg1

功能:将寄存器reg1的值按位取反后,结果存入寄存器reg0。

(27) 算术左移运算指令:SAL reg0 reg1 reg2

功能:将寄存器reg1的值算术左移reg2位,结果存入寄存器reg0。在进

行算术左移时,低位空位用0填充。

(28) 算术右移运算指令:SAR reg0 reg1 reg2

功能:将寄存器reg1的值算术右移reg2位,结果存入寄存器reg0。在进

行算术右移时,高位空位用符号位填充。

(29) 相等关系运算指令:EQU reg0 reg1

功能:将两个寄存器reg0和reg1的值进行相等比较关系运算:reg0 == reg1,

关系运算的结果为逻辑真或逻辑假,存入程序状态字中的比较标志位c。

(30) 小于关系运算指令:LT reg0 reg1

功能:将两个寄存器reg0和reg1的值进行小于关系运算:reg0 < reg1,

关系运算的结果为逻辑真或逻辑假,存入程序状态字中的比较标志位c。

(31) 小于等于关系运算指令:LTE reg0 reg1

功能:将两个寄存器reg0和reg1的值进行小于等于关系运算:reg0 <= reg1,

关系运算的结果为逻辑真或逻辑假,存入程序状态字中的比较标志位c。

(32) 比较标志位取反指令:NOTC

功能:将程序状态字中的比较标志位c求反,即将逻辑真变为逻辑假,将逻

 

(33) 字节数据定义伪指令:BYTE symbol[n] = {...} 蓝色字体部分为可选项

:BYTE symbol[n] = "..." 蓝色字体部分为可选项

功能:定义长度为1字节的字节型数据或数据块,字节型数据块类似于C的字符数组。

(34) 字数据定义伪指令:WORD symbol[n] = {...} 蓝色字体部分为可选项

功能:定义长度为2字节的双字节型数据或数据块,双字节型数据块类似于C的整型数组(16位系统)。



模拟器实现建议,先向系统申请动态存储区,模拟内存,然后定位好CS、DS、SS、ES的初始地址,其中CS段的地址为模拟内存的初始地址,输入目标代码,加载到模拟内存,指令计数器也随着改变,此时SS段的地址则是PC的地址,在通过上面所述的变量总共占的字节数,计算出DS此时的地址,ES的地址则是模拟内存的末端减去一个ES的长度(ES的长度为变量结构的长度)。接下来就可以让PC重新指向MEM顶端的第一条指令,然后模拟处理器去执行命令,最后一次正确写出32个函数和两个伪指令的解码方法。


Sample Input

0x61000000
0x62000001
0x63000064
0x6400000a
0x6500001e
0x81120000
0x8a000001
0xf2300000
0x10000014
0xad140000
0xa6450000
0x96160000
0x36000000
0x8f000001
0x81500000
0xe8100000
0x10000024
0x39000000
0x89000030
0x7900000f
0x9f000001
0xe8700000
0x10000044
0x00000000
0x00000000

Sample Output

5050

HINT

汇编器生成的十六进制数据可以一行一行输入,作为字符串输出,然后转换为对应的整数。转换函数可以参考如下:
long int htoi(char s[]) 
{
int i; 
long int n = 0;
if (s[0] == '0' && (s[1]=='x' || s[1]=='X'))
{
i = 2;
}
else
{
i = 0;
}
for (; (s[i] >= '0' && s[i] <= '9') || (s[i] >= 'a' && s[i] <= 'z') || (s[i] >='A' && s[i] <= 'Z');++i)
{
if (tolower(s[i]) > '9')
{
n = 16 * n + (10 + tolower(s[i]) - 'a');
}
else

n = 16 * n + (tolower(s[i]) - '0');


return n; 
}
在主函数中读入的时候可以参考如下代码:
char xpc[300];
 scanf("%s",xpc);
long int ll = htoi(xpc);



可以将每条指令设计为一个函数,可以如下设计
short GR[8];/*8个通用寄存器*/  
int pos=0;/*记录程序运行的位置*/ 

int HLT(void) 

pos++; 
return 0; 

int JMP(void) 

pos=ADDRESS/4; 
pc=(unsigned long *)(op+ADDRESS/4); 
return 1; 

int CJMP(void) 

if(state.compare) 

pos=ADDRESS/4; 
pc=(unsigned long *)(op+ADDRESS/4); 

else {
pos++; 
}
return 1; 

int OJMP(void) 

if(state.overflow) 

pos=ADDRESS/4; 
pc=(unsigned long *)(op+ADDRESS/4); 

else {
pos++; 
}

return 1; 

int CALL(void) 

int i; 
p=head; 
if(head==NULL) 

p=(struct list *)malloc(sizeof(struct list)); 
p->pt=pos; 
for(i=0;i<8;i++) 
p->G[i]=GR[i]; 
p->s=state; 
p->next=NULL; 
head=p; 

else 

for(;p!=NULL;p=p->next) 
q=p; 
p=(struct list *)malloc(sizeof(struct list)); 
p->pt=pos; 

for(i=0;i<8;i++) 
p->G[i]=GR[i]; 
p->s=state; 
p->next=NULL; 
q->next=p; 

pos=ADDRESS/4; 
pc=(unsigned long *)(op+ADDRESS/4); 
return 1; 

int RET(void) 

int i; 
p=head; 
q=p; 
for(;p->next!=NULL;p=p->next) 
q=p; 
pc=(unsigned long *)(op+p->pt+1); 
pos=p->pt+1; 
state=p->s; 
for(i=0;i<8;i++) 
GR[i]=p->G[i]; 
q->next=NULL; 
return 1; 

int PUSH(void) 

if(x>=100) 

printf("ERROR:too many numbers\n"); 
exit(0); 

if(REG0==0) 

printf("ERROR:wrong register\n"); 
exit(0); 

x++; 
ss[x]=GR[REG0]; 
pos++; 
return 1; 

int POP(void) 

if(x==0) 

printf("ERROR:too few numbers\n"); 
exit(0); 

GR[REG0]=ss[x]; 
x--; 
pos++; 
return 1; 

int LOADB(void) 

GR[REG0]=num[ADDRESS+GR[7]-1]; 
pos++; 
return 1; 

int LOADW(void) 

GR[REG0]=num[ADDRESS+GR[7]-1]+(num[ADDRESS+GR[7]]<<8); 
pos++; 
return 1; 

int STOREB(void) { 
num[ADDRESS+GR[7]-1]=GR[REG0]; 
pos++; 
return 1; 

int STOREW(void) { 
num[ADDRESS+GR[7]-1]=GR[REG0]&0xff; 
num[ADDRESS+GR[7]]=(GR[REG0]>>8)&0xff; 
pos++; 
return 1; 

int LOADI(void) 

GR[REG0]=IMMEDIATE; 
pos++; 
return 1; 

int NOP(void) 

pos++; 
return 1; 

int IN(void) 

scanf("%c",&GR[REG0]); 
pos++; 
return 1; 

int OUT(void) 

printf("%c",GR[REG0]&(0xff)); 
pos++; 
return 1; 

int ADD(void) 

long int a,b,c; 
b=GR[REG1]; 
c=GR[REG2]; 
GR[REG0]=GR[REG1]+GR[REG2]; 
a=GR[REG0]; 
if((b+c)!=a){
state.overflow=1; 
}
else{
state.overflow=0; 


pos++; 
return 1; 

int ADDI(void) 

int k; 
long int a,b,c; 
b=GR[REG0]; 
c=IMMEDIATE; 
k=GR[REG0]+IMMEDIATE; 
a=k; 
if((b+c)!=a){
state.overflow=1; 
}else{
state.overflow=0;
}
 
GR[REG0]=k; 
pos++; 
return 1; 

int SUB(void) 

long int a,b,c; 
b=GR[REG1]; 
c=GR[REG2]; 
GR[REG0]=GR[REG1]-GR[REG2]; 
a=GR[REG0]; 
if((b-c)!=a){
state.overflow=1;
}else{
state.overflow=0; 

pos++; 
return 1; 

int SUBI(void) 

int k; 
long int a,b,c; 
b=GR[REG0]; 
c=IMMEDIATE; 
k=GR[REG0]-IMMEDIATE; 
a=k; 
if((b-c)!=a){
state.overflow=1; 
}else{
state.overflow=0; 
}

GR[REG0]=k; 
pos++; 
return 1; 

int MUL(void) 

long int a,b,c; 
b=GR[REG1]; 
c=GR[REG2]; 
GR[REG0]=GR[REG1]*GR[REG2]; 
a=GR[REG0]; 
if((b*c)!=a){
state.overflow=1;
}else{
state.overflow=0;
}
 
pos++; 
return 1; 

int DIV(void) 

long int a,b,c; 
if(GR[REG2]==0) 

printf("WRONG NUMBER\n"); 
exit(0); 

b=GR[REG1]; 
c=GR[REG2]; 
 
GR[REG0]=GR[REG1]/GR[REG2]; 
a=GR[REG0]; 
if((b/c)!=a){
state.overflow=1; 
}else {
state.overflow=0;
}
 
pos++; 
return 1; 

int AND(void) 

GR[REG0]=GR[REG1]&GR[REG2]; 
pos++; 
return 1; 

int OR(void) 

GR[REG0]=GR[REG1]|GR[REG2]; 
pos++; 
return 1; 

int NOR(void) 

GR[REG0]=GR[REG1]^GR[REG2]; 
pos++; 
return 1; 

int NOTB(void) 

GR[REG0]=~GR[REG1]; 
pos++; 
return 1; 

int SAL(void) 

GR[REG0]=GR[REG1]<<GR[REG2]; 
pos++; 
return 1; 

int SAR(void) 

GR[REG0]=GR[REG1]>>GR[REG2]; 
pos++; 
return 1; 


int EQU(void) 

if(GR[REG0]==GR[REG1]) {
state.compare=1; 
}else{
state.compare=0;
}
 
pos++; 
return 1; 

int LT(void) 

if(GR[REG0]<GR[REG1]) 
state.compare=1; 
else 
state.compare=0; 
pos++; 
return 1; 

int LTE(void) 

if(GR[REG0]<=GR[REG1]) 
state.compare=1; 
else 
state.compare=0; 
pos++; 
return 1; 

int NOTC(void) 

if(state.compare==1){
state.compare=0;
}else {
state.compare=1; 


pos++; 
return 1; 



Source/Category

 

[Submit] [Status]