import re import copy ########################### #### Instruction CLASS #### ########################### class Instruction: def __init__(self, mnemonic, dest, opA, program_counter, opB, imm=None): self.pc = program_counter self.mnemonic = mnemonic self.dest = dest self.opA = opA self.opB = opB self.imm = imm def is_register(self, operand): return isinstance(operand, str) and operand.startswith('x') @classmethod def parse(cls, text, pc): parts=[] imm = None partss = text.split() for part in partss: parts.append(re.sub(",", "", part)) mnemonic = parts[0] dest = int(parts[1][1:]) opA = int(parts[2][1:]) if mnemonic == "addi": imm = int(parts[3]) opB = int(parts[3]) else: opB = int(parts[3][1:]) return cls(mnemonic, dest, opA, pc, opB, imm=imm) def rename(self, new_dest, register_map_table, physical_opA, physical_opB): renamed_instruction = copy.deepcopy(self) renamed_instruction.dest = new_dest renamed_instruction.opA = physical_opA if self.mnemonic == "addi": renamed_instruction.opB = self.imm else: renamed_instruction.opB = physical_opB return renamed_instruction def get_data(self): return [ self.pc, self.mnemonic, self.dest, self.opA, self.opB, self.imm] ################################## #### RenamedInstruction CLASS #### ################################## class RenamedInstruction: def __init__(self, instruction, physical_destination): self.mnemonic = instruction.mnemonic self.logical_destination = instruction.dest self.physical_destination = physical_destination self.opA = instruction.opA self.opB = instruction.opB self.imm = instruction.imm self.pc = instruction.pc def is_register(self, operand): return isinstance(operand, str) and operand.startswith('x') @classmethod def from_instruction(cls, instruction, physical_destination): return cls(instruction, physical_destination) def update_destination(self, new_physical_destination): self.physical_destination = new_physical_destination def update_sources(self, register_map_table): if self.opA is not None and isinstance(self.opA, str): logical_source = self.opA physical_source = register_map_table.get_physical_register(logical_source) self.opA = physical_source if self.opB is not None and isinstance(self.opB, str): logical_source = self.opB physical_source = register_map_table.get_physical_register(logical_source) self.opB = physical_source ################################ #### PhysicalRegister CLASS #### ################################ class PhysicalRegisterFile: def __init__(self, num_registers): self.registers = [0] * num_registers self.ready_flags = [True] * num_registers def write(self, index, value): self.registers[index] = value self.ready_flags[index] = True def read(self, index): return self.registers[index] def is_ready(self, index): return self.ready_flags[index] def mark_busy(self, index): self.ready_flags[index] = False def mark_ready(self, index): self.ready_flags[index] = True def has_free_registers(self): return any(flag for flag in self.ready_flags) def get_data(self): return self.registers ################################ #### ActiveList ENTRY CLASS #### ################################ class ActiveListEntry: def __init__(self, done=False, exception=False, physical_destination=0, logical_destination=0, old_destination=0, pc=0,): self.done = done self.exception = exception self.logical_destination = logical_destination self.old_destination = old_destination self.pc = pc self.physical_destination = physical_destination def to_dict(self): return { "Done": self.done, "Exception": self.exception, "LogicalDestination": self.logical_destination, "OldDestination": self.old_destination, "PC": self.pc } ########################### #### Active List CLASS #### ########################### class ActiveList: def __init__(self): self.entries = [] def get_last_entry(self): if len(self.entries) == 0: return None return self.entries[-1] def remove_last_entry(self): if len(self.entries) == 0: return self.entries.pop() def is_empty(self): return len(self.entries)==0 def add_entry(self, entry): self.entries.append(entry) def remove_entry(self, entry_to_remove_pc): index = None for i, entry in enumerate(self.entries): if entry.pc == entry_to_remove_pc: index = i break if index is not None: self.entries.pop(index) def has_capacity(self): return len(self.entries) < 32 def get_entry_by_logical_dest(self, logical_dest): for entry in self.entries: if entry.logical_destination == logical_dest: return entry return None def get_entry_by_pc(self, pc): for entry in self.entries: if entry.pc == pc: return entry return None def get_data(self): return [entry.to_dict() for entry in self.entries] def get_entries(self): return self.entries def clear_busy_bits(self, physical_register): for entry in self.entries: if entry.old_destination == physical_register: entry.done = True entry.exception = False ################################## #### GERQUEUE ENTRY CLASS #### ################################## class IntegerQueueEntry: def __init__(self, dest_register, op_code, pc, op_a_is_ready=False, op_a_reg_tag=0, op_a_value=0, op_b_is_ready=False, op_b_reg_tag=0, op_b_value=0): self.dest_register = dest_register self.op_a_is_ready = op_a_is_ready self.op_a_reg_tag = op_a_reg_tag self.op_a_value = op_a_value self.op_b_is_ready = op_b_is_ready self.op_b_reg_tag = op_b_reg_tag self.op_b_value = op_b_value self.op_code = op_code self.pc = pc def to_dict(self): return { "DestRegister": self.dest_register, "OpAIsReady": self.op_a_is_ready, "OpARegTag": self.op_a_reg_tag, "OpAValue": self.op_a_value, "OpBIsReady": self.op_b_is_ready, "OpBRegTag": self.op_b_reg_tag, "OpBValue": self.op_b_value, "OpCode": self.op_code, "PC": self.pc } ############################ #### INTEGERQUEUE CLASS #### ############################ class IntegerQueue: def __init__(self): self.entries = [] def add_entry(self, entry): self.entries.append(entry) def remove_entry(self, index): self.entries.pop(index) def remove_entry_by_pc(self, pc): self.entries = [entry for entry in self.entries if entry.pc != pc] def get_entry_by_pc(self, pc): for entry in self.entries: if entry.pc == pc: return entry return None def get_entry(self, index): return self.entries[index] def get_entry_by_dest_register(self, dest_register): for entry in self.entries: if entry.dest_register == dest_register: return entry return None def update_entry_ready(self, dest_register, op_a_ready, op_b_ready): entry = self.get_entry_by_dest_register(dest_register) if entry is not None: entry.op_a_is_ready = op_a_ready entry.op_b_is_ready = op_b_ready def has_capacity(self): return len(self.entries) < 32 def get_data(self): return self.entries.copy() ############################ #### BusyBitTable CLASS #### ############################ class BusyBitTable: def __init__(self, size): self.bits = [False] * size self.instructions = [None] * size def get_data(self): return self.bits def set_busy(self, index, instruction): self.bits[index] = True self.instructions[index] = instruction def set_free(self, index): self.bits[index] = False self.instructions[index] = None def is_busy(self, physical_register): return self.bits[physical_register] def get_busy_instruction(self, physical_register): return self.instructions[physical_register] def get_physical_register(self, reg_tag, register_map_table): physical_register = register_map_table.get_physical_register(reg_tag) return physical_register def set_busy_bits(self, instruction, register_map_table): # Set busy bits for source operands if instruction.opA and instruction.is_register(instruction.opA): physical_source = register_map_table.get_physical_register(instruction.opA) self.set_busy(physical_source, instruction) if instruction.opB and instruction.is_register(instruction.opB): physical_source = register_map_table.get_physical_register(instruction.opB) self.set_busy(physical_source, instruction) def has_capacity(self, instruction, register_map_table): # Check if all source operands are available if instruction.opA and instruction.is_register(instruction.opA) and self.is_busy(register_map_table.get_physical_register(instruction.opA)): return False if instruction.opB and instruction.is_register(instruction.opB) and self.is_busy(register_map_table.get_physical_register(instruction.opB)): return False return True ############################### #### Program Counter CLASS #### ############################### class ProgramCounter: def __init__(self): self.value = 0 def get_data(self): return self.value def increment(self, amount=1): self.value += amount def set(self, val): self.value = val ######################## #### FreeList CLASS #### ######################## class FreeList: def __init__(self): self.free_registers = list(range(32, 64)) def get_data(self): return self.free_registers def remove_register(self, register_index): self.free_registers.remove(register_index) def allocate(self): if not self.free_registers: raise Exception("No free registers available") return self.free_registers.pop(0) def free(self, reg): self.free_registers.append(reg) def get(self): if not self.free_registers: raise Exception("No more free registers in the free list") return self.free_registers.pop(0) def has_capacity(self): return bool(self.free_registers) ################################ #### RegisterMapTable CLASS #### ################################ class RegisterMapTable: def __init__(self): self.mapping = list(range(32)) def get_data(self): return self.mapping def add_entry(self, logical_register, physical_register): if 0 <= logical_register <= 31: self.mapping[logical_register] = physical_register else: raise Exception(f"Invalid architectural register {logical_register}") def update_mapping(self, logical_register, physical_register): if 0 <= logical_register <= 31: self.mapping[logical_register] = physical_register else: raise Exception(f"Invalid architectural register {logical_register}") def get_physical_register(self, logical_register): if 0 <= logical_register <= 31: return self.mapping[logical_register] else: raise Exception(f"Invalid architectural register {logical_register}") def get_logical_register(self, physical_register): for i in range(len(self.mapping)): if self.mapping[i] == physical_register: return i ########################## #### DecodedPCS CLASS #### ########################## class DecodedPCs: def __init__(self): self.pc_values = [] def get_data(self): return self.pc_values def add_pc(self, pc): self.pc_values.append(pc) def set_data(self, pc_values): self.pc_values = pc_values def remove_pc(self, pc): if pc in self.pc_values: self.pc_values.remove(pc) else: raise Exception(f"PC value {pc} not found in DecodedPCs") ############################# #### ExceptionFlag CLASS #### ############################# class ExceptionFlag: def __init__(self): self.flag = False def set(self): self.flag = True def clear(self): self.flag = False def is_set(self): return self.flag def get_data(self): return self.flag ############################ #### ExceptionPCS CLASS #### ############################ class ExceptionPC: def __init__(self): self.pc = 0 def set(self, pc): self.pc = pc def get_data(self): return self.pc