From e89d766fbf1c424ef65af0c973b198df42679a97 Mon Sep 17 00:00:00 2001 From: pl7xmnuv6 <382399691@qq.com> Date: Tue, 22 Nov 2022 21:47:04 +0800 Subject: [PATCH] ADD file via upload --- TomasuloAlgorithm.py | 733 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 733 insertions(+) create mode 100644 TomasuloAlgorithm.py diff --git a/TomasuloAlgorithm.py b/TomasuloAlgorithm.py new file mode 100644 index 0000000..7dcbb06 --- /dev/null +++ b/TomasuloAlgorithm.py @@ -0,0 +1,733 @@ +# -*- coding: utf-8 -*- + +import sys + +LD = "L.D" # exe steps: 2 +SD = "S.D" # 1 +ADDD = "ADD.D" # 2 +SUBD = "SUB.D" # 2 +MULD = "MUL.D" # 10 +DIVD = "DIV.D" # 40 + + +class Tomasulo: + + def __init__(self, insts, adder_num, multiplier_num, load_buffer_num, + store_buffer_num, float_reg_num, int_reg_num, mem_size): + i = 0 + for inst in insts: + inst_ = "" + for term in inst.split(" "): + inst_ = inst_ + term.split(",")[0] + " " + insts[i] = inst_.split("\n")[0] + i += 1 + self.instruction_status = [ + instruction_status(insts[i], i) for i in range(len(insts)) + ] + + self.reservation_station = reservation_station(adder_num, + multiplier_num) + self.load_buffers = [load_buffer(i) for i in range(load_buffer_num)] + self.store_buffers = [store_buffer(i) for i in range(store_buffer_num)] + + self.register_result_status = register_result_status( + float_reg_num, int_reg_num) + self.mem = [mem(i) for i in range(mem_size)] + self.clock = 1 + + def lbIsFull(self): + for lb in self.load_buffers: + if lb.busy == False: return lb.index # return free buffer's index + return "True" # indicate Full by returning "True" + + def sbIsFull(self): + for sb in self.store_buffers: + if sb.busy == False: return sb.index # return free buffer's index + return "True" # indicate Full by returning "True" + + def print(self): + print("Cycle " + str(self.clock) + ":") + print("\nInstruction Status: ") + print("\t\t\t\t\t\t%s\t%s %s" % + ("Issue", "Complete", "Write_Result")) + for IS in self.instruction_status: + IS.print() + self.reservation_station.print() + print("-\n") + # print("Load/Store Buffer:") + # print("\t\t\tBusy\tAddress\t\tFu") + # for lb in self.load_buffers: + # lb.print() + # for sb in self.store_buffers: + # sb.print() + # print("-\n") + self.register_result_status.print() + + # print("Memory: \n") + # mem_name = "\t\t " + # mem_value = "\t\tValue: " + # for mem in self.mem: + # if int(mem.name.split("_")[-1]) % 8 == 0: + # mem_name += ("\tMem_" + + # str(int(int(mem.name.split("_")[-1]) / 8) + 1)) + # mem_value += ("\t" + str(mem.value)) + # print(mem_name + "\n") + # print(mem_value) + # print("-\n") + + def isFinished(self): # check whether the insts are finished + for IS in self.instruction_status: + if IS.write == -1: return False + return True + + def writeResult(self): + for RS in self.reservation_station.adders: + self.broadcast(RS) + + for RS in self.reservation_station.multipliers: + self.broadcast(RS) + + for RS in self.load_buffers: + self.broadcast(RS) + + for RS in self.store_buffers: + if RS.busy == True and RS.time == 0: + if RS.qk != "null": + if RS.qk.split("_")[0] == "Add": + fus = self.reservation_station.adders + elif RS.qk.split("_")[0] == "Mult": + fus = self.reservation_station.multipliers + for fu in fus: # store buffer所等待的function unit(reservation station) + if RS.qk == fu.name and self.clock == self.instruction_status[ + fu.inst_index].write + 1: + self.mem[RS.address].value = fu.result + RS.last_time_write = self.clock # 记录instruction最近一次的write_result时间 + self.instruction_status[ + RS.inst_index].write = self.clock + fu.result = -1 # reset the result + RS.reset() + + # 对沒有dependence的修改vk + elif RS.qk == "null": # source register(rt) 未占用 + self.mem[RS.address].value = RS.vk + self.vk_broadcasted_cycle = self.clock + RS.last_time_write = self.clock # 记录instruction的write_result时间 + self.instruction_status[RS.inst_index].write = self.clock + RS.reset() + + def broadcast(self, RS): + if RS.busy == True and RS.time == 0: + RS.last_time_write = self.clock + self.instruction_status[ + RS.inst_index].write = self.clock # write result + + # broadcast to all awaiting reservation stations + for reg in self.register_result_status.float_regs: + if reg.qi != "null" and reg.qi == RS.name: + reg.value = RS.result + reg.qi = "null" + + for RSs in self.reservation_station.adders: # search for matched Qj or Qk + if RSs.busy == True and RSs.qj == RS.name: + RSs.vj = RS.result + RSs.vj_broadcasted_cycle = self.clock + RSs.qj = "null" + if RSs.busy == True and RSs.qk == RS.name: + RSs.vk = RS.result + RSs.vk_broadcasted_cycle = self.clock + RSs.qk = "null" + + for RSs in self.reservation_station.multipliers: # search for matched Qj or Qk + if RSs.busy == True and RSs.qj == RS.name: + RSs.vj = RS.result + RSs.vj_broadcasted_cycle = self.clock + RSs.qj = "null" + if RSs.busy == True and RSs.qk == RS.name: + RSs.vk = RS.result + RSs.vk_broadcasted_cycle = self.clock + RSs.qk = "null" + + for RSs in self.load_buffers: # search for matched Qj + if RSs.busy == True and RSs.qj == RS.name: + RSs.vj = RS.result + RSs.vj_broadcasted_cycle = self.clock + RSs.qj = "null" + RS.reset() + + def execute(self): + for RS in self.reservation_station.adders: + if RS.busy == True and RS.vj != "null" and RS.vk != "null" and RS.qj == "null" and RS.qk == "null": + if RS.vj_broadcasted_cycle == self.clock or RS.vk_broadcasted_cycle == self.clock: + continue + else: + RS.time = RS.time - 1 + if RS.time == 0: + if RS.op == ADDD: RS.result = RS.vj + RS.vk + elif RS.op == SUBD: RS.result = RS.vj - RS.vk + self.instruction_status[ + RS.inst_index].complete = self.clock + + for RS in self.reservation_station.multipliers: + if RS.busy == True and RS.vj != "null" and RS.vk != "null" and RS.qj == "null" and RS.qk == "null": + if RS.vj_broadcasted_cycle == self.clock or RS.vk_broadcasted_cycle == self.clock: + continue + else: + RS.time = RS.time - 1 + if RS.time == 0: + if RS.op == MULD: RS.result = RS.vj * RS.vk + elif RS.op == DIVD: RS.result = RS.vj / RS.vk + self.instruction_status[ + RS.inst_index].complete = self.clock + + for RS in self.load_buffers: + if RS.busy == True and RS.vj != "null" and RS.qj == "null": + if RS.vj_broadcasted_cycle == self.clock: + continue + else: + RS.time = RS.time - 1 + if RS.time == 1: + RS.address = RS.address + RS.vj + elif RS.time == 0: + RS.result = self.mem[RS.address].value + self.instruction_status[ + RS.inst_index].complete = self.clock + + for RS in self.store_buffers: + #if RS.busy == True and RS.vk != "null" and RS.qk == "null": + #if RS.busy == True and RS.vk != "null": + if RS.busy == True: + #if RS.vk_broadcasted_cycle == self.clock: continue + #else: + if RS.time != 0: + RS.time = RS.time - 1 + if RS.time == 0: + RS.address = RS.address + RS.vj + self.instruction_status[ + RS.inst_index].complete = self.clock + + def issue(self): + for inst in self.instruction_status: + if inst.issue == -1: # only issue the unissued instructions + if inst.name == LD: + index = self.lbIsFull() # index 为 free load_buffer's index + if index != "True" and self.load_buffers[ + index].last_time_write != self.clock: + self.load_buffers[index].time = 2 + inst.issue = self.clock + self.load_buffers[index].inst_index = inst.index + # load or store + if self.register_result_status.int_regs[ + inst.rsIndex].qi != "null": + self.load_buffers[ + index].qj = self.register_result_status.int_regs[ + inst.rsIndex].qi + else: + self.load_buffers[ + index].vj = self.register_result_status.int_regs[ + inst.rsIndex].value # base address + self.load_buffers[index].qj = "null" + self.load_buffers[ + index].address = inst.offset # save offset(immd. value) to address + self.load_buffers[index].busy = True + + # load only + self.register_result_status.float_regs[ + inst.rtIndex].qi = self.load_buffers[index].name + + elif inst.name == SD: + index = self.sbIsFull() + if index != "True" and self.store_buffers[ + index].last_time_write != self.clock: + inst.issue = self.clock + self.store_buffers[index].time = 1 + self.store_buffers[index].inst_index = inst.index + # load or store + if self.register_result_status.int_regs[ + inst.rsIndex].qi != "null": + self.store_buffers[ + index].qj = self.register_result_status.int_regs[ + inst.rsIndex].qi + else: + self.store_buffers[ + index].vj = self.register_result_status.int_regs[ + inst.rsIndex].value # base address + self.store_buffers[index].qj = "null" + self.store_buffers[ + index].address = inst.offset # save offset(immd. value) to address + self.store_buffers[index].busy = True + + # store only + if self.register_result_status.float_regs[ + inst.rtIndex].qi != "null": + self.store_buffers[ + index].qk = self.register_result_status.float_regs[ + inst.rtIndex].qi + else: + self.store_buffers[ + index].vk = self.register_result_status.float_regs[ + inst.rtIndex].value # source register (rt) + self.store_buffers[index].qk = "null" + + elif inst.name == ADDD or inst.name == SUBD or inst.name == MULD or inst.name == DIVD: + if inst.name == ADDD or inst.name == SUBD: + index = self.reservation_station.isFull( + self.reservation_station.adders) + if index != "True" and self.reservation_station.adders[ + index].last_time_write != self.clock: + inst.issue = self.clock + self.reservation_station.adders[ + index].inst_index = inst.index + if inst.name == ADDD: + self.reservation_station.adders[ + index].op = ADDD + elif inst.name == SUBD: + self.reservation_station.adders[ + index].op = SUBD + self.reservation_station.adders[index].time = 2 + if self.register_result_status.float_regs[ + inst.rsIndex].qi != "null": + self.reservation_station.adders[ + index].qj = self.register_result_status.float_regs[ + inst.rsIndex].qi + else: + self.reservation_station.adders[ + index].vj = self.register_result_status.float_regs[ + inst.rsIndex].value + self.reservation_station.adders[ + index].qj = "null" + + if self.register_result_status.float_regs[ + inst.rtIndex].qi != "null": + self.reservation_station.adders[ + index].qk = self.register_result_status.float_regs[ + inst.rtIndex].qi + else: + self.reservation_station.adders[ + index].vk = self.register_result_status.float_regs[ + inst.rtIndex].value # base address + self.reservation_station.adders[ + index].qk = "null" + self.reservation_station.adders[index].busy = True + self.register_result_status.float_regs[ + inst. + rdIndex].qi = self.reservation_station.adders[ + index].name + + elif inst.name == MULD or inst.name == DIVD: + index = self.reservation_station.isFull( + self.reservation_station.multipliers) + if index != "True" and self.reservation_station.multipliers[ + index].last_time_write != self.clock: + inst.issue = self.clock + self.reservation_station.multipliers[ + index].inst_index = inst.index + if inst.name == MULD: + self.reservation_station.multipliers[ + index].time = 10 + self.reservation_station.multipliers[ + index].op = MULD + elif inst.name == DIVD: + self.reservation_station.multipliers[ + index].time = 40 + self.reservation_station.multipliers[ + index].op = DIVD + + if self.register_result_status.float_regs[ + inst.rsIndex].qi != "null": + self.reservation_station.multipliers[ + index].qj = self.register_result_status.float_regs[ + inst.rsIndex].qi + else: + self.reservation_station.multipliers[ + index].vj = self.register_result_status.float_regs[ + inst.rsIndex].value + self.reservation_station.multipliers[ + index].qj = "null" + + if self.register_result_status.float_regs[ + inst.rtIndex].qi != "null": + self.reservation_station.multipliers[ + index].qk = self.register_result_status.float_regs[ + inst.rtIndex].qi + else: + self.reservation_station.multipliers[ + index].vk = self.register_result_status.float_regs[ + inst.rtIndex].value + self.reservation_station.multipliers[ + index].qk = "null" + self.reservation_station.multipliers[ + index].busy = True + self.register_result_status.float_regs[ + inst. + rdIndex].qi = self.reservation_station.multipliers[ + index].name + + break # issue one instruction per cycle, so break from for loop anyway + + +class instruction_status: + + def __init__(self, inst, i): + inst = inst.split() + self.name = inst[0] + self.issue = self.complete = self.write = self.rs = self.rt = self.rd = self.offset = -1 + self.index = i # instruction index for reservation_station mapping + + if self.name == LD or self.name == SD: # target address: rt = base(rs) + offset + self.offset = int(inst[-1].split("(")[0]) + + self.rs = inst[-1].split("(")[-1].split(")")[0] # base address + self.rsIndex = int(self.rs.split( + 'R')[-1]) # rs index for register_result_status mapping + + self.rt = inst[1] # destination register + self.rtIndex = int(int(self.rt.split('F')[-1]) / 2) + else: + self.rd = inst[1] # destination register + self.rdIndex = int(int(self.rd.split('F')[-1]) / 2) + + self.rs = inst[2] # source register 1 + self.rsIndex = int(int(self.rs.split('F')[-1]) / 2) + + self.rt = inst[3] # source register 2 + self.rtIndex = int(int(self.rt.split('F')[-1]) / 2) + + def print(self): + if self.issue == -1: issue = "" + else: issue = self.issue + if self.complete == -1: complete = "" + else: complete = self.complete + if self.write == -1: write = "" + else: write = self.write + + if self.name == LD or self.name == SD: + print("\t\t%s\t%s\t%s\t%s\t %s\t %s\t\t %s" % + (self.name, self.rt, self.offset, self.rs, issue, complete, + write)) + else: + print( + "\t\t%s\t%s\t%s\t%s\t %s\t %s\t\t %s" % + (self.name, self.rd, self.rs, self.rt, issue, complete, write)) + + +class reservation_station: + + def __init__(self, adder_num, multiplier_num): + self.adders = [adder(i) for i in range(adder_num)] + self.multipliers = [multiplier(i) for i in range(multiplier_num)] + + def isFull(self, RS): + for rs in RS: + if rs.busy == False: return rs.index + return "True" + + def print(self): + print("-\n\nResevation Station:") + print("\t\tTime\tName\tBusy\tOp\tVj\tVk\tQj\tQk") + for adder in self.adders: + self.print_RS(adder) + for multiplier in self.multipliers: + self.print_RS(multiplier) + + def print_RS(self, RS): + if RS.time == -1: time = "" + else: time = RS.time + if RS.busy == False: busy = "No" + else: busy = "Yes" + if RS.op == "null": op = "" + else: op = RS.op + if RS.vj == "null": vj = "" + else: vj = RS.vj + if RS.vk == "null": vk = "" + else: vk = RS.vk + if RS.qj == "null": qj = "" + else: + qj = qj = RS.qj.split("_")[0] + "_" + str( + int(RS.qj.split("_")[-1]) + 1) + if RS.qk == "null": qk = "" + else: + qk = RS.qk.split("_")[0] + "_" + str(int(RS.qk.split("_")[-1]) + 1) + name = RS.name.split("_")[0] + "_" + str( + int(RS.name.split("_")[-1]) + 1) + print("\t\t%4s\t%s\t%s\t%s\t%s\t%s\t%s\t%s" % + (time, name, busy, op, vj, vk, qj, qk)) + + def adderIsFull(self, RS): + for adder in self.adders: + if adder.busy == False: return False + return True + + def multiplierIsFull(self, RS): + for multiplier in self.multipliers: + if multiplier.busy == False: return False + return True + + +class adder: + + def __init__(self, i): + self.index = i + self.name = "Add_" + str(i) + self.time = -1 + self.busy = False + self.op = "null" + self.vj = "null" + self.vk = "null" + self.qj = "null" + self.qk = "null" + self.result = 0 + self.inst_index = -1 + self.vj_broadcasted_cycle = -1 + self.vk_broadcasted_cycle = -1 + self.last_time_write = -1 + + def reset(self): + self.time = -1 + self.busy = False + self.op = "null" + self.vj = "null" + self.vk = "null" + self.qj = "null" + self.qk = "null" + #self.result = 0 + #self.inst_index = -1 + self.vj_broadcasted_cycle = -1 + self.vk_broadcasted_cycle = -1 + + +class multiplier: + + def __init__(self, i): + self.index = i + self.name = "Mult_" + str(i) + self.time = -1 + self.busy = False + self.op = "null" + self.vj = "null" + self.vk = "null" + self.qj = "null" + self.qk = "null" + self.result = 0 + self.inst_index = -1 + self.vj_broadcasted_cycle = -1 + self.vk_broadcasted_cycle = -1 + self.last_time_write = -1 + + def reset(self): + self.time = -1 + self.busy = False + self.op = "null" + self.vj = "null" + self.vk = "null" + self.qj = "null" + self.qk = "null" + #self.result = 0 + #self.inst_index = -1 + self.vj_broadcasted_cycle = -1 + self.vk_broadcasted_cycle = -1 + + +class load_buffer: + + def __init__(self, i): + self.index = i # index for register_result_status mapping + self.name = "Load_" + str(i) + self.time = -1 + self.busy = False + self.vj = "null" # base address + self.qj = "null" # the function unit which is processing base address + self.address = 0 + self.result = 0 + self.inst_index = -1 + self.vj_broadcasted_cycle = -1 + self.last_time_write = -1 + + def reset(self): + self.time = -1 + self.busy = False + self.vj = "null" + self.qj = "null" + self.address = 0 + #self.result = 0 + #self.inst_index = -1 + self.vj_broadcasted_cycle = -1 + + def print(self): + if self.busy == False: busy = "No" + else: busy = "Yes" + if self.qj == "null": qj = "" + else: + qj = self.qj.split("_")[0] + "_" + str( + int(self.qj.split("_")[-1]) + 1) + name = self.name.split("_")[0] + "_" + str( + int(self.name.split("_")[-1]) + 1) + print("\t\t%s\t%s\t%s\t\t%s" % (name, busy, self.address, qj)) + + +class store_buffer: + # mem[rs + immd.(offset)] = rt + def __init__(self, i): + self.index = i # index for register_result_status mapping + self.name = "Store_" + str(i) + self.time = -1 + self.busy = False + self.vj = "null" # base address register(rs) + self.vk = "null" # source register (rt) + self.qj = "null" + self.qk = "null" # the function unit which is processing base address + self.address = 0 + self.result = 0 + self.inst_index = -1 # reservation_station 处理的是哪一个 instruction + self.vk_broadcasted_cycle = -1 # 为了不让RS在broadcast的cycle就开始执行,因此必须在RS记录得到broadcast的时间(cycle) + self.last_time_write = -1 # 为了禁止在write result之后的下个cycle释放station后,马上被新的指令issue并放入station中, + # 因此记录该 station 上个指令的 write result 时间,让下个指令必须2个cycle才能issue。 + + def reset(self): + self.time = -1 + self.busy = False + self.vj = "null" + self.vk = "null" + self.qj = "null" + self.qk = "null" + self.address = 0 + #self.result = 0 + #self.inst_index = -1 + self.vk_broadcasted_cycle = -1 + + def print(self): + if self.busy == False: busy = "No" + else: busy = "Yes" + if self.qk == "null": qk = "" + else: + qk = self.qk.split("_")[0] + "_" + str( + int(self.qk.split("_")[-1]) + 1) + name = self.name.split("_")[0] + "_" + str( + int(self.name.split("_")[-1]) + 1) + print("\t\t%s\t%s\t%s\t\t%s" % (name, busy, self.address, qk)) + + +class mem: # 内存8个Double(64-bit)的(64-Bytes),初始值1 + + def __init__(self, i): + self.name = "Mem_" + str(i) + if i % 8 == 0: self.value = 1 + else: self.value = 0 + + +class register_result_status: + + def __init__(self, float_reg_num, int_reg_num): + self.float_regs = [float_reg(i) for i in range(float_reg_num) + ] # 浮点寄存器F0、F2、F4、…、F30,初始值1; + self.int_regs = [int_reg(i) + for i in range(int_reg_num)] # 整数寄存器R0、R1、…、R31 + self.int_regs[1].value = 16 + + def print(self): + print("Register result status:") + a = "" + for fr in self.float_regs: + a += fr.name + "\t" + print("\t\t\t" + a) + + a = "" + for fr in self.float_regs: + if fr.qi == "null": qi = "" + else: + qi = fr.qi.split("_")[0] + "_" + str( + int(fr.qi.split("_")[-1]) + 1) + a += str(qi) + "\t" + print("\t\tQi:\t" + a) + + a = "" + for fr in self.float_regs: + a += str(fr.value) + "\t" + print("\t\tvalue:\t" + a) + # print("\n") + + # a = "" + # for ir in self.int_regs: + # a += ir.name + "\t" + # print("\t\t\t" + a) + + # a = "" + # for ir in self.int_regs: + # if ir.qi == "null": qi = "" + # else: + # qi = ir.qi.split("_")[0] + "_" + str( + # int(ir.qi.split("_")[-1]) + 1) + # a += str(qi) + "\t" + # print("\t\tQi:\t" + a) + + # a = "" + # for ir in self.int_regs: + # a += str(ir.value) + "\t" + # print("\t\tvalue:\t" + a) + print("-\n") + + +class float_reg: + + def __init__(self, i): + self.name = "F" + str(i * 2) + self.value = 1 + self.qi = "null" # 正在等待的 function unit + + def print(self): + print("reg %s, value: %d" % (self.name, self.value)) + + +class int_reg: + + def __init__(self, i): + self.name = "R" + str(i) + self.value = 0 + self.qi = "null" # 正在等待的 function unit + + def print(self): + print("reg %s, value: %d" % (self.name, self.value)) + + +def __main__(): + # read argument from command lind + # input_argv = "Computer Architecture\TomasuloAlgorithm-master\sample1.txt" + # f = open(input_argv, 'r') + # insts = f.readlines() # read instructions from text file + insts = [ + 'L.D F6, 8(R2)', + 'L.D F2, 40(R3)', + 'MUL.D F0, F2, F4', + 'SUB.D F8, F6, F2', + 'DIV.D F10, F0, F6', + 'ADD.D F6, F8, F2', + ] + + # f.close() + + adder_num = 3 + multiplier_num = load_buffer_num = store_buffer_num = 2 + float_reg_num = 16 # 浮点寄存器, from F0, F2, F4, …, to F30, 初始值为1; + int_reg_num = 32 # 整数寄存器, from R0, R1, …, to R31 + mem_size = 64 # 64-byte memory(8 double-precision space) + tomasulo = Tomasulo(insts, adder_num, multiplier_num, load_buffer_num, + store_buffer_num, float_reg_num, int_reg_num, mem_size) + + # original_stdout = sys.stdout + # sys.stdout = open( + # r"Computer Architecture\TomasuloAlgorithm\output.txt", "w") + while (True): + #ipdb.set_trace() + tomasulo.writeResult() # 执行已完成Execution的指令 + tomasulo.execute() # 执行已完成Issue的指令,维护指令 + tomasulo.issue() # issue指令 + + tomasulo.print() + tomasulo.clock += 1 # steps one clock cycle + + if tomasulo.isFinished(): break + #if tomasulo.clock > 71: break + # sys.stdout = original_stdout + + +if __name__ == "__main__": + __main__()