def printHistory(clkHistory): # Convert clkHistory to history board history = [[" " for i in range(len(clkHistory))] for i in range(len(G_MEM.INST))] for i in range(len(clkHistory)): for exe in clkHistory[i]: if exe[2]: # Idle history[exe[1][0]][i] = " " # history[exe[1][0]][i] = "(" + exe[0] + ")" # Show idle stages else: history[exe[1][0]][i] = exe[0] # Print header and column titles print("╔═════╦════════════════════════╦" + "═"*(6*len(clkHistory)) + "╗") print("║ Mem ║ " + "Clock #".center(22) + " ║", end="") for i in range(len(clkHistory)): print(str(i).center(5), end=" ") print("║") print("╠═════╬════════════════════════╬" + "═"*(6*len(clkHistory)) + "╣") # Print history board for i in range(len(history)): print("║ {:>3} ║ {:>22} ║".format(i*4, instTranslator.decode(G_MEM.INST[i])), end="") for j in range(len(history[0])): print(history[i][j].center(5), end=" ") print("║") print("╚═════╩════════════════════════╩" + "═"*(6*len(clkHistory)) + "╝")
def printInstMem(): print( "╔═════╦═════════════════════════════[PROGRAM]═══════════╦════════════════════════╗" ) for i in range(len(G_MEM.INST)): print("║ {:>3} ║ 0x{:08X} = 0b{:032b} ║ {:<22} ║".format( i * 4, G_MEM.INST[i], G_MEM.INST[i], instTranslator.decode(G_MEM.INST[i]))) print( "╚═════╩═════════════════════════════════════════════════╩════════════════════════╝" )
def main(): filename = "program.asm" # Read .asm program = utils.readFile(filename) programLength = len(program) # Encode and load .asm into memory for i in range(programLength): # Remove comments if not program[i] or program[i][0] == "#": continue encoded = instTranslator.encode(program[i].split("#")[0]) # Detect errors, if none then continue loading if encoded not in G_UTL.ERROR: G_MEM.INST.append(encoded) else: print("ERROR @ '{}':".format(filename)) print("\tLine {}: '{}'".format(i + 1, program[i])) if encoded == G_UTL.EINST: print("\t\tCouldn't parse the instruction") elif encoded == G_UTL.EARG: print("\t\tCouldn't parse one or more arguments") elif encoded == G_UTL.EFLOW: print("\t\tOne or more arguments are under/overflowing") return # Print the program as loaded utils.printInstMem() print() # Doesn't print memory after each clock silent = ("-s" in sys.argv) # Skips clock stepping skipSteps = silent # Run simulation, will run until all pipeline stages are empty clkHistory = [] clk = 0 while clk == 0 or (G_UTL.ran["IF"][1] != 0 or G_UTL.ran["ID"][1] != 0 or G_UTL.ran["EX"][1] != 0 or G_UTL.ran["MEM"][1] != 0): if silent: print("─" * 20 + " CLK #{} ".format(clk) + "─" * 20) else: print("─" * 38 + " CLK #{} ".format(clk) + "─" * 38) clkHistory.append([]) # Run all stages "in parallel" stages.EX_fwd() stages.WB() stages.MEM() stages.EX() stages.ID() stages.ID_hzd() stages.IF() # Keep only the 32 LSB from memory for i in range(len(G_MEM.REGS)): G_MEM.REGS[i] &= 0xFFFFFFFF for i in range(len(G_MEM.DATA)): G_MEM.DATA[i] &= 0xFFFFFFFF # Report if stage was run for stage in ["IF", "ID", "EX", "MEM", "WB"]: if G_UTL.ran[stage][1] != 0: idle = " (idle)" if G_UTL.wasIdle[stage] else "" clkHistory[clk].append( (stage, G_UTL.ran[stage], G_UTL.wasIdle[stage])) print("> Stage {}: #{} = [{}]{}.".format( stage, G_UTL.ran[stage][0] * 4, instTranslator.decode(G_UTL.ran[stage][1]), idle)) # Print resulting memory if not silent: print("─" * (83 + len(str(clk)))) utils.printPC() if G_UTL.data_hzd or G_UTL.ctrl_hzd: utils.printFwdAndHazard() utils.printPipelineRegs() utils.printRegMem() utils.printDataMem() print("─" * (83 + len(str(clk)))) clk += 1 # Clock step prompt if not skipSteps: try: opt = input("| step: [ENTER] | end: [E|Q] | ").lower() skipSteps = (opt == "e" or opt == "q") except KeyboardInterrupt: print("\nExecution aborted.") exit() if silent: print() utils.printPipelineRegs() utils.printRegMem() utils.printDataMem() else: print("Empty pipeline, ending execution...") print() print("Program ran in {} clocks.".format(clk)) print() utils.printHistory(clkHistory) return