You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

354 lines
13 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import prettytable as pt
import pandas as pd
import numpy as np
# 循环次数 (循环一直执行的话会导致访问的寄存器R地址超出限制
loop_num = 3
# 初始化
# 整数寄存器
R = [i for i in range(32)]
# 浮点寄存器
F = [2.0 * i for i in range(16)]
# 内存只有1024个单元
Mem = [i for i in range(1024)]
# 跳转label对应的PC值 dictionary数据结构
label2pc = {}
# 记录真实执行的程序指令
prgm_real = []
# 每个操作对应的功能单元
op2fun = {"L.D": "Load", "MUL.D": "Mult", "S.D": "Store", "DADDUI": "Add", "BNE": "Add",
"SUB.D": "Add", "DIV.D": "Mult", "ADD.D": "Add"}
# 每个功能单元执行时间
funtime = {"L.D": "1", "MUL.D": "10", "S.D": "1", "DADDUI": "2", "BNE": "1",
"SUB.D": "2", "DIV.D": "40", "ADD.D": "2"}
# 功能单元名称
fuName = ["Load1", "Load2", "Add1", "Add2", "Add3", "Mult1", "Mult2", "Store1", "Store2"]
# 每个操作对应的操作符
op2char = {"MUL.D": "*", "DADDUI": "+", "SUB.D": "-", "DIV.D": "/", "ADD.D": "+"}
# 初始化
def init(prgm):
# 生成 InstructionStatus指令状态表
InsS = []
# 生成ReservationStations保留站
ResS = pd.DataFrame(np.empty([9, 9], str),
index=fuName,
columns=["Busy", "Op", "Vj", "Vk", "Qj", "Qk", "A", "Time", "InsNum"])
ResS['Busy'] = "No"
# 生成RegisterStatus寄存器状态表
RegS = pd.DataFrame(np.empty([1, 16], str),
index=["Qi"], columns=["F" + str(i) for i in range(0, 16, 2)] + ["R" + str(i) for i in range(0, 8, 1)])
return 0, InsS, ResS, RegS
# 指令译码
def DecIns(ins):
# 如果有Loop标签指令 从指令中去除Loop再进行译码
if ins.find("Loop: ") != -1:
ins = ins.replace("Loop: ", "")
ins = ins.replace(",", " ")
ins = ins.replace("(", " ")
ins = ins.replace(")", "")
ins = ins.split(" ")
op = ins[0]
dest = ins[1]
s1 = ins[2]
s2 = ins[3]
return op, dest, s1, s2
# 为指令分配功能部件
def GetFU(op, ResS):
fu = op2fun[op]
# 对应Load部件
if fu == "Load":
if ResS.loc["Load1", "Busy"] == "No":
fu = "Load1"
elif ResS.loc["Load2", "Busy"] == "No":
fu = "Load2"
else:
fu = "" # 没有空闲部件,则返回空字符串
# 对应Add部件
elif fu == "Add":
if ResS.loc["Add1", "Busy"] == "No":
fu = "Add1"
elif ResS.loc["Add2", "Busy"] == "No":
fu = "Add2"
elif ResS.loc["Add3", "Busy"] == "No":
fu = "Add3"
else:
fu = ""
# 对应Mult部件
elif fu == "Mult":
if ResS.loc["Mult1", "Busy"] == "No":
fu = "Mult1"
elif ResS.loc["Mult2", "Busy"] == "No":
fu = "Mult2"
else:
fu = ""
# 对应Store部件
else:
if ResS.loc["Store1", "Busy"] == "No":
fu = "Store1"
elif ResS.loc["Store2", "Busy"] == "No":
fu = "Store2"
else:
fu = ""
return fu
# 根据指令编号找到在ResS中正在执行该指令的功能部件
def GetFUbyNum(insnum, ResS):
for name in fuName:
if ResS.loc[name, "InsNum"] == insnum:
fu = name
return fu
# 指令发射
def Issue(ins, insnum, clk, InsS, ResS, RegS):
op, dest, s1, s2 = DecIns(ins)
fu = GetFU(op, ResS)
# 如果功能部件为busy直接返回
if fu != "":
InsS.append(["" for j in range(3)])
InsS[insnum][0] = clk # 指令状态表登记该指令Issue的时间
ResS.loc[fu, "InsNum"] = insnum # insnum项标记该功能部件是哪条指令在使用方便后续操作直接根据该指令找到部件
ResS.loc[fu, "Busy"] = "Yes"
ResS.loc[fu, "Op"] = op # Op记录的即为fu去除后面的编号
if fu.find("Store") != -1: # store指令
# 计算store的内存地址
addr = int(dest) + R[int(R[int(s1.replace("R", ""))])] # 寄存器间接寻址
ResS.loc[fu, "Vj"] = "#%s" % addr
# 判断WAW冲突
if RegS.loc["Qi", s2] == "":
ResS.loc[fu, "Qk"] = "#%s" % F[int(s2.replace("F", "")) // 2]
else:
ResS.loc[fu, "Qk"] = RegS.loc["Qi", s2]
elif fu.find("Load") != -1: # load指令
# 记录目的寄存器
RegS.loc["Qi", dest] = fu
# 计算地址
addr = int(s1) + R[int(R[int(s2.replace("R", ""))])] # 寄存器间接寻址
# 直接写地址立即数
ResS.loc[fu, "A"] = "#%s" % addr
elif ins.find("BNE") != -1: # BNE指令
# 判断dest是否有效
if RegS.loc["Qi", dest] == "":
if dest.find("F") != -1:
ResS.loc[fu, "Vj"] = "#%s" % F[int(dest.replace("F", "")) // 2]
elif s1.find("R") != -1:
ResS.loc[fu, "Vj"] = "#%s" % R[int(dest.replace("R", ""))]
else:
ResS.loc[fu, "Qj"] = RegS.loc["Qi", dest]
# 判断s1是否有效
if RegS.loc["Qi", s1] == "":
if s1.find("F") != -1:
ResS.loc[fu, "Vk"] = "#%s" % F[int(s1.replace("F", "")) // 2]
elif s1.find("R") != -1:
ResS.loc[fu, "Vk"] = "#%s" % R[int(s1.replace("R", ""))]
else:
ResS.loc[fu, "Qk"] = RegS.loc["Qi", s1]
else:# 其他指令
# 判断s1操作数是否有效
if RegS.loc["Qi", s1] == "":
if s1.find("F") != -1:
ResS.loc[fu, "Vj"] = "#%s" % F[int(s1.replace("F", "")) // 2]
elif s1.find("R") != -1:
ResS.loc[fu, "Vj"] = "#%s" % R[int(s1.replace("R", ""))]
else:
ResS.loc[fu, "Qj"] = RegS.loc["Qi", s1]
# 判断s2操作数是否有效
if s2.find("#") != -1: # 立即数
ResS.loc[fu, "Vk"] = s2
elif RegS.loc["Qi", s2] == "": # 或为F寄存器值
ResS.loc[fu, "Vk"] = "#%s" % F[int(s2.replace("F", "")) // 2]
else:
ResS.loc[fu, "Qk"] = RegS.loc["Qi", s2]
# 写入目的寄存器
RegS.loc["Qi", dest] = fu
return InsS, ResS, RegS
# 指令执行
def Execute(ins, insnum, clk, InsS, ResS):
op, dest, s1, s2 = DecIns(ins)
fu = GetFUbyNum(insnum, ResS)
# 当前指令尚未开始执行,则判断是否就绪,若未就绪则继续等待
if ResS.loc[fu, "Time"] == "":
if ResS.loc[fu, "Qj"] == "" and ResS.loc[fu, "Qk"] == "":
ResS.loc[fu, "Time"] = funtime[op]
else:
ResS.loc[fu, "Time"] = str(int(ResS.loc[fu, "Time"]) - 1)
if ResS.loc[fu, "Time"] == "0":
InsS[insnum][1] = clk
ResS.loc[fu, "Time"] = ""
return InsS, ResS
# 写回数据
def WriteResult(ins, insnum, clk, InsS, ResS, RegS, PC):
op, dest, s1, s2 = DecIns(ins)
fu = GetFUbyNum(insnum, ResS)
# 记录时钟
InsS[insnum][2] = clk
# Busy位置为no则释放该功能部件
ResS.loc[fu, "Busy"] = "No"
# 寄存器状态表写回
if fu.find("Load") != -1: # 对于load指令
RegS.loc["Qi", dest] = ""
F[int(dest.replace("F", "")) // 2] = Mem[int(float(ResS.loc[fu, "A"].replace("#", ""))//1)]
result = "#%s" % str(F[int(dest.replace("F", "")) // 2])
elif fu.find("Store") != -1: # 对于store指令不对表执行任何操作
Mem[int(ResS.loc[fu, "Vj"].replace("#", ""))] = float(ResS.loc[fu, "Vk"].replace("#", ""))//1
elif ins.find("BNE") != -1:
if ResS.loc[fu, "Vj"] != ResS.loc[fu, "Vk"]: # 当s1和dest不相等时跳转
PC = label2pc[s2]
else:
# 其他指令
RegS.loc["Qi", dest] = ""
if op2char[op] == "+":
dest_result = float(ResS.loc[fu, "Vj"].replace("#", "")) + float(ResS.loc[fu, "Vk"].replace("#", ""))
elif op2char[op] == "-":
dest_result = float(ResS.loc[fu, "Vj"].replace("#", "")) - float(ResS.loc[fu, "Vk"].replace("#", ""))
elif op2char[op] == "*":
dest_result = float(ResS.loc[fu, "Vj"].replace("#", "")) * float(ResS.loc[fu, "Vk"].replace("#", ""))
elif op2char[op] == "/":
dest_result = float(ResS.loc[fu, "Vj"].replace("#", "")) / float(ResS.loc[fu, "Vk"].replace("#", ""))
if dest.find("F") != -1:
F[int(dest.replace("F", "")) // 2] = dest_result
elif dest.find("R") != -1:
R[int(dest.replace("R", ""))] = dest_result
result = "#%s" % str(dest_result)
# DBS广播数据
for fuitem in fuName:
# 遍历 ReservationStations的每行找有无使用到当前写回结果的值
if ResS.loc[fuitem, "Qj"] == fu:
ResS.loc[fuitem, "Qj"] = ""
ResS.loc[fuitem, "Vj"] = result
# 广播该值后,该部件若数据已就绪可以执行,则开始计时
if ResS.loc[fuitem, "Qk"] == "" and ResS.loc[fuitem, "Time"] == "":
ResS.loc[fuitem, "Time"] = funtime[ResS.loc[fuitem, "Op"]]
if ResS.loc[fuitem, "Qk"] == fu:
ResS.loc[fuitem, "Qk"] = ""
ResS.loc[fuitem, "Vk"] = result
# 广播该值后,该部件若数据已就绪可以执行,则开始计时
if ResS.loc[fuitem, "Qj"] == "" and ResS.loc[fuitem, "Time"] == "":
ResS.loc[fuitem, "Time"] = funtime[ResS.loc[fuitem, "Op"]]
return PC, InsS, ResS, RegS
# 输出表格
def printTumasulo(prgm, InsS, ResS, RegS):
# InstructionStatusTable
print("-----------------------------------------------------------------------")
for item in ["Instruction", "Issue", "Execute", "Write result"]:
print("{0: >16}".format(item), end='')
print()
for i in range(min(len(InsS),loop_num*(len(prgm)-1))):
print("{0: >16}".format(prgm_real[i]), end='')
for j in InsS[i]:
print("{0: >16}".format(j), end='')
print()
print()
# ReservationStationsTable
print("-------------------------------------------------------------------------------")
print("{0: >10}".format(" "), end='')
for item in ["Busy", "Op", "Vj", "Vk", "Qj", "Qk", "A"]:
print("{0: >10}".format(item), end='')
print()
ResList = ResS.values.tolist()
for i in range(len(ResList)):
print("{0: >10}".format(fuName[i]), end='')
for j in range(7):
print("{0: >10}".format(ResList[i][j]), end='')
print()
print()
# RegisterStatus
print("-------------------------------------------------------------------------------------------------------------")
for item in ["Feild", "F0", "F2", "F4", "F6", "F8", "F10", "F12", "F14", "R0", "R1", "R2", "R3", "R4",
"R5", "R6", "R7"]:
print("{0: >6}".format(item), end='')
print()
print("{0: >6}".format("Qi"), end='')
for i in range(len(RegS.values.tolist())):
print("{0: >6}".format(RegS.values.tolist()[0][i]), end='')
print()
print("-------------------------------------------------------------------------------------------------------------")
# 所有指令是否全部执行完
def PrgmFinish(InsS, prgm):
# for i in range(len(prgm_real)):
for i in range(loop_num*(len(prgm)-1)):
for j in range(3):
if InsS[i][j] == "":
return False
return True
if __name__ == '__main__':
# 待执行指令程序
prgm = ["Loop: L.D F0,0(R1)",
"MUL.D F4,F0,F2",
"S.D 0(R1),F4",
"DADDUI R1,R1,#-8",
"BNE R1,R2,Loop",
"End"]
# 初始化
clk, InsS, ResS, RegS = init(prgm)
PC = 0
# 时钟周期驱动 每次循环一个时钟
while True:
clk += 1
# 对跳转分支的标签记录PC
if prgm[PC].find("Loop") == 0:
label2pc["Loop"] = PC
prgm[PC] = prgm[PC].replace("Loop: ", "")
# 第一个周期 只流出第一条指令
if clk == 1:
# 指令流出 issue
InsS, ResS, RegS = Issue(prgm[PC], PC, clk, InsS, ResS, RegS)
prgm_real.append(prgm[PC])
PC += 1
else:
# 根据已发射的指令各阶段完成状态 决定 指令当前周期处于哪个执行阶段
for i in range(len(InsS) - 1, -1, -1):
if InsS[i][1] == "":
# 执行 ex
InsS, ResS = Execute(prgm_real[i], i, clk, InsS, ResS)
elif InsS[i][2] == "":
# 写结果 write result
PC, InsS, ResS, RegS = WriteResult(prgm_real[i], i, clk, InsS, ResS, RegS, PC)
# 要不要发射新指令
if prgm[PC] != "End" and (PC == 0 or InsS[PC - 1][0] != ""):
# 发射新指令 issue
InsS, ResS, RegS = Issue(prgm[PC], len(InsS), clk, InsS, ResS, RegS)
prgm_real.append(prgm[PC])
PC += 1
print("clock:%d" % clk)
#print("++---------------------------------------------------------------------------------------------------------++")
printTumasulo(prgm, InsS, ResS, RegS)
# 判断是否全部执行完
if PrgmFinish(InsS, prgm):
break