def test_do_operand_forwarding(self):
        self.processor.decoder_buffer = DecoderBuffer({'rs': [2, None]})
        self.processor.executer_buffer = ExecuterBuffer({'rt': [2, 7]})
        self.processor.do_operand_forwarding()
        self.assertEqual(self.processor.decoder_buffer.rs, [2, 7])

        self.processor.decoder_buffer = DecoderBuffer({'rs': [2, None]})
        self.processor.executer_buffer = ExecuterBuffer()
        self.processor.memory_buffer = MemoryBuffer({'rd': [2, 9]})
        self.processor.do_operand_forwarding()
        self.assertEqual(self.processor.decoder_buffer.rs, [2, 9])
    def __init__(self, memory, start_address):
        self.memory = memory
        self.start_address = start_address
        self.register_file = RegisterFile()
        self.data_memory_key_fn = lambda: -777
        self.data_memory = defaultdict(self.data_memory_key_fn)

        self.cycle_count = 0
        self.instr_count = 0
        self.PC = 0

        self.fetch_input_buffer = FetchInputBuffer({
            'PC':
            self.start_address,
            'instr_count':
            self.instr_count,
        })
        self.fetcher_buffer = FetcherBuffer()
        self.fetch_stage = FetchStage(self.memory, self.fetch_input_buffer,
                                      self.fetcher_buffer)

        self.decoder_buffer = DecoderBuffer()
        self.decode_stage = DecodeStage(self.fetcher_buffer,
                                        self.decoder_buffer,
                                        self.register_file)

        self.executer_buffer = ExecuterBuffer()
        self.execute_stage = ExecuteStage(self.decoder_buffer,
                                          self.executer_buffer)
        self.memory_buffer = MemoryBuffer()
        self.memory_stage = MemoryStage(self.executer_buffer,
                                        self.memory_buffer, self.data_memory)
        self.write_back_stage = WriteBackStage(self.memory_buffer,
                                               self.register_file)
    def test_execute_I_instruction_BEQ_true(self):
        self.register_file[2] = 8
        self.register_file[5] = 8
        self.set_up_execute_stage('I BEQ  R2 R5 4')

        expected_branch_PC = self.decoder_buffer.npc + 4 * 4
        self.execute_stage.execute_I_instruction()

        self.assertFalse(self.execute_stage.is_stalled)
        self.assertEqual(self.execute_stage.branch_pc, expected_branch_PC)
        self.assertEqual(self.execute_stage.executer_buffer, ExecuterBuffer())
        self.assertEqual(self.execute_stage.decoder_buffer, DecoderBuffer())
    def test_execute_I_instruction_LW(self):
        self.register_file[2] = 8
        self.set_up_execute_stage('I LW  R2 R5 4')

        executer_buffer = ExecuterBuffer({
            'instr': self.instr,
            'npc': self.decoder_buffer.npc,
            'rt': [5, None],
            'memaddr': 12,
        })

        self.execute_stage.execute_I_instruction()

        self.assertFalse(self.execute_stage.is_stalled)
        self.assertEqual(self.execute_stage.executer_buffer, executer_buffer)
        self.assertEqual(self.execute_stage.decoder_buffer, DecoderBuffer())
    def test_execute_I_instruction_ADDI(self):
        self.register_file[1] = 3
        self.set_up_execute_stage('I ADDI R1 R1 1')

        executer_buffer = ExecuterBuffer({
            'instr':
            self.instr,
            'npc':
            self.decoder_buffer.npc,
            'rt': [self.instr.rt, self.register_file[1] + 1],
        })

        self.execute_stage.execute_I_instruction()

        self.assertFalse(self.execute_stage.is_stalled)
        self.assertEqual(self.execute_stage.executer_buffer, executer_buffer)
        self.assertEqual(self.execute_stage.decoder_buffer, DecoderBuffer())
    def get_stage_output(memory, register_file, pc, instr_count, stage_name):
        """Return the output buffer of stage given the initial conditions.
        
        All the stages before stage_name will be executed.
        
        Arguments:
        - `memory`:
        - `register_file`:
        - `pc`:
        - `stage_name`:

        TODO: Maybe just take the stages as input later.
        """
        fetch_input_buffer = FetchInputBuffer({
            'PC': pc,
            'instr_count': instr_count,
        })
        fetcher_buffer = FetcherBuffer()
        fetch_stage = FetchStage(memory, fetch_input_buffer, fetcher_buffer)
        fetch_stage.fetch_instruction()

        if stage_name == 'fetch':
            return fetch_stage.fetcher_buffer

        decode_stage = DecodeStage(fetch_stage.fetcher_buffer, DecoderBuffer(),
                                   register_file)
        decode_stage.decode_instruction()

        if stage_name == 'decode':
            return decode_stage.decoder_buffer

        execute_stage = ExecuteStage(decode_stage.decoder_buffer,
                                     ExecuterBuffer())
        execute_stage.execute()
        if stage_name == 'execute':
            return execute_stage.executer_buffer

        data_memory_key_fn = lambda: -1
        data_memory = defaultdict(data_memory_key_fn)

        memory_stage = MemoryStage(execute_stage.executer_buffer,
                                   MemoryBuffer(), data_memory)
        memory_stage.do_memory_operation()

        if stage_name == 'memory':
            return memory_stage.memory_buffer
    def test_execute_R_instruction(self):
        self.register_file[1] = 3
        self.register_file[2] = 7
        self.set_up_execute_stage('R ADD  R1 R2 R3')

        executer_buffer = ExecuterBuffer({
            'instr':
            self.instr,
            'npc':
            self.decoder_buffer.npc,
            'rd':
            [self.instr.rd, self.register_file[1] + self.register_file[2]],
        })

        self.execute_stage.execute_R_instruction()

        self.assertFalse(self.execute_stage.is_stalled)
        self.assertEqual(self.execute_stage.executer_buffer, executer_buffer)
        self.assertEqual(self.execute_stage.decoder_buffer, DecoderBuffer())
    def test_execute_I_instruction_BEQ_false(self):
        self.register_file[2] = 8
        self.register_file[5] = 7
        self.set_up_execute_stage('I BEQ  R2 R5 4')
        expected_branch_PC = self.decoder_buffer.npc

        self.execute_stage.executer_buffer = ExecuterBuffer({'foo': 123})

        self.execute_stage.execute_I_instruction()
        self.assertFalse(self.execute_stage.is_stalled)
        print 'self.decoder_buffer: ', self.decoder_buffer

        self.assertEqual(self.execute_stage.branch_pc, expected_branch_PC)

        # NOTE: You need different instances of ExecuterBuffers, else,
        # just one instance gets modified and the two references will
        # turn out to be equal.
        self.assertEqual(
            self.execute_stage.executer_buffer, ExecuterBuffer({'foo': 123}),
            "execute_stage shouldn't modify its executer_buffer after a BEQ")
        self.assertEqual(self.execute_stage.decoder_buffer, DecoderBuffer())
    def test_execute_cycles_BEQ_true(self):
        instruction_list = [
            'I BEQ  R2 R5 4',
            'R ADD  R1 R2 R3',
            'R ADD  R1 R2 R3',
            'R ADD  R2 R0 R1',
            'R ADD  R3 R0 R2',
            'J J    3',
            'I ADDI R9 R9 999',
        ]
        instruction_list = [
            instruction_string.split()
            for instruction_string in instruction_list
        ]
        memory = Memory.Memory(instruction_list)
        processor = Processor.Processor(memory, 0)
        processor.execute_cycles(3)
        self.assertEqual(processor.execute_stage.branch_pc, 20)
        self.assertEqual(processor.fetch_stage.fetch_input_buffer.PC, 20)

        self.assertEqual(processor.executer_buffer, ExecuterBuffer())
        self.assertEqual(processor.decoder_buffer, DecoderBuffer())
        self.assertEqual(processor.fetcher_buffer, FetcherBuffer())