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