一、题目要求
使用Python/C/C++语言实现一个Y86-64模拟器(可参考附件实现),要求: 1)能够从文件中读取Y86-64机器码(Xilinx coe文件格式) 2)能够解释执行Y86-64指令 3)能够将存储器/寄存器值输出
提示:可采用多周期、流水线实现 使用Xilinx coe格式输入文件(参考:Xilinx COE文件生成_xilinx coe-CSDN博客)
测试: 使用Y86-64指令实现从1加到100,并将结果保存到存储器中
ps: 说实话这个实验比较简单,没有什么太大的自由发挥时间,python相较于C语言会更好写一点 不过多周期流水线???我没想出来怎么写
二、代码开源(就当是学姐给你们的馈赠了哈哈哈哈哈哈哈哈)
import sys
class InstructionType:
halt = '00'
nop = '10'
rrmovq = '20'
cmovle = '21'
cmovl = '22'
cmove = '23'
cmovne = '24'
cmovge = '25'
cmovg = '26'
irmovq = '30'
rmmovq = '40'
mrmovq = '50'
addq = '60'
subq = '61'
andq = '62'
xorq = '63'
jmp = '70'
jle = '71'
jl = '72'
je = '73'
jne = '74'
jge = '75'
jg = '76'
call = '80'
ret = '90'
pushq = 'A0'
popq = 'B0'
Y86=InstructionType()
mem = [0]*10010 #指令存储器
reg = [0]*16 #15个常用寄存器
iReg = '' #当前指令
pReg = 0 #PC
ZF = 0 #零
SF = 0 #符号
OF = 0 #溢出
reg[4] = 10000 #%rsp栈指针
def loadProgram(file): #把文件地址和指令读入存储器中
global mem, reg, iReg, pReg,ZF,OF,SF #声明全局变量
fil = open(file,'r') #读文件
first = True #现在是不是第一行
lineno = 0 #行数
while True:
line = fil.readline() #读一行
line=line.rstrip('\n')
line = line.rstrip(',')
line =line.rstrip(';')
lineno += 1 #行数
if line == '':
break #读完就退出
fids = line.split() #以词为数组
try:
address = int(fids[0],16) #地址 读入第1个词,默认16进制
instruc = fids[1] #指令
if first:
pReg = address #开头
first = False
mem[address] = instruc
except:
if (lineno>2):
print(f'File {file} line {lineno} has error') #提供信息报错!!!
pass
fil.close
def imm(str): #处理立即数 "把小端正过来"
n = len(str)
s =''
for i in range(n-2,-1,-2):
s = s+str[i:i+2]
return s
Count = 1 #???
def cycle():
global mem, reg, iReg, pReg,OF,ZF,SF,Count #声明全局变量
iReg = str(mem[pReg]) #当前指令
pReg = len(iReg)//2 + pReg #PC+1
opcode = iReg[0:2]
if opcode == Y86.halt:
return False #终止运行
elif opcode == Y86.nop:
return True #空操作
elif opcode == Y86.rrmovq:
rA = int(iReg[2],16)
rB = int(iReg[3],16)
reg[rB] = reg[rA]
elif opcode == Y86.cmovle:
rA = int(iReg[2],16)
rB = int(iReg[3],16)
if ZF or SF:
reg[rB] = reg[rA]
elif opcode == Y86.cmovl:
rA = int(iReg[2],16)
rB = int(iReg[3],16)
if SF:
reg[rB] = reg[rA]
elif opcode == Y86.cmove:
rA = int(iReg[2],16)
rB = int(iReg[3],16)
if ZF:
reg[rB] = reg[rA]
elif opcode == Y86.cmovne:
rA = int(iReg[2],16)
rB = int(iReg[3],16)
if not ZF:
reg[rB] = reg[rA]
elif opcode == Y86.cmovge:
rA = int(iReg[2],16)
rB = int(iReg[3],16)
if ZF or (not SF):
reg[rB] = reg[rA]
elif opcode == Y86.cmovg:
rA = int(iReg[2],16)
rB = int(iReg[3],16)
if not SF:
reg[rB] = reg[rA]
elif opcode == Y86.irmovq:
rB = int(iReg[3],16)
imm0 = int(imm(iReg[4:]),16)
reg[rB] = imm0
elif opcode == Y86.rmmovq:
rA = int(iReg[2],16)
rB = int(iReg[3],16)
imm1 = int(imm(iReg[4:]),16)
mem[reg[rB]+imm1] = reg[rA]
elif opcode == Y86.mrmovq:
rA = int(iReg[2],16)
rB = int(iReg[3],16)
imm2 = int(imm(iReg[4:]),16)
reg[rA] = mem[reg[rB]+imm2]
elif opcode == Y86.addq:
rA = int(iReg[2],16)
rB = int(iReg[3],16)
flag = 0
if reg[rA]>0 and reg[rB]>0: flag=1
if reg[rA]<0 and reg[rB]<0: flag=2
reg[rB] = reg[rA]+reg[rB]
if reg[rB]==0:
ZF=1
else: ZF=0
if reg[rB]<0:
SF=1
else: SF=0
if (flag==1 and reg[rB]<0) or (flag==2 and reg[rB]>0):
OF=1
else: OF=0
elif opcode == Y86.subq:
rA = int(iReg[2],16)
rB = int(iReg[3],16)
flag = 0
if reg[rA]>0 and reg[rB]>0: flag=1
if reg[rA]<0 and reg[rB]<0: flag=2
reg[rB] = reg[rB]-reg[rA]
if reg[rB]==0:
ZF=1
else:
ZF=0
if reg[rB]<0:
SF=1
else: SF=0
if (flag==1 and reg[rB]<0) or (flag==2 and reg[rB]>0):
OF=1
else: OF=0
elif opcode == Y86.andq:
rA = int(iReg[2],16)
rB = int(iReg[3],16)
reg[rB] = reg[rA]®[rB]
if reg[rB]==0:
ZF=1
else:
ZF=0
if reg[rB]<0: SF=1
else: SF=0
OF=0
elif opcode == Y86.xorq:
rA = int(iReg[2],16)
rB = int(iReg[3],16)
reg[rB] = reg[rA]^reg[rB]
if reg[rB]==0:
ZF=1
else:
ZF=0
if reg[rB]<0: SF=1
else: SF=0
OF=0
elif opcode == Y86.jmp:
pReg = int(imm(iReg[2:]),16)
elif opcode == Y86.jle:
if ZF or SF:
pReg = int(imm(iReg[2:]),16)
elif opcode == Y86.jl:
if SF:
pReg = int(imm(iReg[2:]),16)
elif opcode == Y86.je:
if ZF:
pReg = int(imm(iReg[2:]),16)
elif opcode == Y86.jne:
if not ZF:
pReg = int(imm(iReg[2:]),16)
elif opcode == Y86.jge:
if ZF or (not SF):
pReg = int(imm(iReg[2:]),16)
elif opcode == Y86.jg:
if not SF:
pReg = int(imm(iReg[2:]),16)
elif opcode == Y86.call:
mem[reg[4]-8] = pReg
reg[4] = reg[4]-8
pReg = int(imm(iReg[2:]),16)
elif opcode == Y86.ret:
pReg = mem[reg[4]]
reg[4] = reg[4]+8
elif opcode == Y86.pushq:
rA = int(iReg[2],16)
mem[reg[4]-8] = reg[rA]
reg[4] = reg[4] - 8
elif opcode == Y86.popq:
rA = int(iReg[2],16)
reg[rA] = mem[reg[4]]
reg[4] = reg[4]+8
else:
print(f'Unknow opcode {opcode}')
return True
def run(file): #运行程序
global mem, reg, iReg, pReg,OF,SF,ZF
loadProgram(file)
while True:
if not cycle():
break
path0='Y86-64jiqi.coe'
run(path0)
print(f'寄存器的值:{reg[0]}')
print(f'%rax的值放到地址为100处,即0x64处的存储器的值:{mem[100]}')
三、读入coe文件
MEMORY_INITIALIZATION_RADIX=16;
MEMORY_INITIALIZATION_VECTOR=
000 6300,
002 6333,
004 30F80100000000000000,
00E 30F96400000000000000,
018 6083,
01A 6030,
01C 2032,
01E 6192,
020 741800000000000000,
029 40090000000000000000,
033 00;