class Mips(object): def __init__(self, instructions=None, data_forwarding=False): instructions = instructions.split("\n") if instructions else [] self.instructions = [instruction for instruction in instructions if instruction.strip()] self.data_forwarding = data_forwarding self.registers = Registers(size=REGISTERS_SIZE) self.memory = Memory(size=MEMORY_SIZE) self.history = [] self.pc = 0 self.clock = 0 self.instructions_completed = 0 self._if = InstructionFetch(self) self._id = InstructionDecode(self) self._ex = Execute(self) self._mem = MemoryAccess(self) self._wb = WriteBack(self) self.pipeline = (self._if, self._id, self._ex, self._mem, self._wb) def run(self, life=MIPS_MAX_AGE): while True: self.history.append(self.current_state()) self.execute_pipeline() self.clock += 1 if self.clock > life or (all(isinstance(p.instruction, StallInstruction) for p in self.pipeline) and self.pc == 4 * len(self.instructions)): self.history.append(self.current_state()) break def _go_forward_pipeline(self): if self.pipeline[4].done: self.pipeline[4].instruction = None for a, b in reversed(zip(self.pipeline[:-1], self.pipeline[1:])): if a.done and b.instruction is None: b.instruction = a.instruction a.instruction = None def execute_pipeline(self): self._go_forward_pipeline() for phase in self.pipeline: phase.execute() if not phase.instruction: phase.instruction = StallInstruction() def jump(self, pc): self._if.instruction.unlock_registers(self) self._if.instruction = StallInstruction() self._id.instruction.unlock_registers(self) self._id.instruction = StallInstruction() self.pc = pc def current_state(self): instructions_completed = self.instructions_completed throughput = instructions_completed / self.clock if self.clock > 0 else 0 state = {"pipeline":[p.instruction.current_state() for p in self.pipeline], "registers":self.registers.current_state(), "memory":self.memory.history[-4:], "clock":self.clock, "pc":self.pc, "instructions_completed":instructions_completed, "throughput":throughput} return state