def test_conditional_instructions_incorrect_prediction_no_commit(self): """Test that Conditional Instructions with incorrect predicate do not commit.""" # Initialize units. root = FlushableLog() rs = FeedLog() lsq = FeedLog() rob = ReorderBuffer(self.rf, rs, lsq, capacity=32) rob.set_pipeline_flush_root(root) rob.WIDTH = 4 self.rf['r4'] = 0 self.rf['r5'] = 10 # Initialize instructions to be fed. cond = Blth('r4', 'r5', 100) cond.branch_info = BranchInfo(False, 100, 1, None) cond.DELAY = 0 add = AddI('r1', 'r1', 1) add.DELAY = 0 # Feed pairs of (cond, add) instructions. n_pairs = 5 for i in range(n_pairs): rob.feed(cond) rob.feed(add) rob.tick() # Insert into current queue. # Receive result for each pair in turn. for i in range(0, n_pairs, 2): rob.receive(Result(rs.log[i].tag, True)) rob.receive(Result(rs.log[i + 1].tag, 0)) rob.tick() self.assertEqual(self.rf['r1'], 0) self.assertEqual(self.rf['pc'], 100)
def test_execute(self): ins = Binary('ROB10', lambda o1, o2: o1 + o2, 'ROB3', 'ROB4') with self.assertRaises(ValueError): ins.execute() ins.receive(Result('ROB3', 5)) ins.receive(Result('ROB4', 7)) self.assertEqual(ins.execute(), Result('ROB10', 12))
def test_conditional_instructions_correct_prediction_commit(self): """Test Conditional Instructions with correct predicate commit OK.""" # Initialize units. rs = FeedLog() lsq = FeedLog() rob = ReorderBuffer(self.rf, rs, lsq, capacity=32) rob.WIDTH = 4 self.rf['r4'] = 0 self.rf['r5'] = 0 # Initialize instructions to be fed. cond = Blth('r4', 'r5', 2) cond.branch_info = BranchInfo(False, 2, 2, None) cond.DELAY = 0 add = AddI('r1', 'r1', 1) add.DELAY = 0 # Feed pairs of (cond, add) instructions. n_pairs = 5 for i in range(n_pairs): rob.feed(cond) rob.feed(add) rob.tick() # Insert into current queue. # Receive result for each pair in turn. r1_value = 0 for i in range(0, n_pairs, 2): rob.receive(Result(rs.log[i].tag, False)) rob.receive(Result(rs.log[i + 1].tag, r1_value)) rob.tick() self.assertEqual(self.rf['r1'], r1_value) r1_value += 1
def test_load_execute(self): memory = Memory(64) memory[10] = 5 load = Load('ROB1', 'ROB2') with self.assertRaises(ValueError): load.execute(memory) load.receive(Result('ROB2', 10)) self.assertEqual(load.execute(memory), Result('ROB1', 5))
def test_store_execute(self): memory = Memory(64) memory[10] = 0 store = Store('ROB1', 'ROB3', 'ROB4') for result in [Result('ROB3', 10), Result('ROB4', 5)]: with self.assertRaises(ValueError): store.execute(memory) store.receive(result) store.execute(memory) self.assertEqual(memory[10], 5)
def test_receive_and_can_dispatch(self): ins = Unconditional('ROB1', 'ROB2') self.assertFalse(ins.can_dispatch()) ins.receive(Result('ROB4', 0)) self.assertFalse(ins.can_dispatch()) ins.receive(Result('ROB2', 5)) self.assertTrue(ins.can_dispatch()) ins.receive(Result('ROB3', 0)) self.assertTrue(ins.can_dispatch())
def test_inorder_commit(self): """Ensure instruction Results are committed in-order.""" for _ in range(30): for capacity in [1, 5, 25, 200]: # Initialize test components. self.log.reset() zeros = {'r%d' % i: 0 for i in range(capacity)} act_rf = RegisterFile(capacity, init_values=zeros) exp_rf = RegisterFile(capacity, init_values=zeros) width = random.randint(1, 2 * capacity) rob = ReorderBuffer(act_rf, self.log, self.lsq, capacity=capacity, width=width) # Feed instructions into ROB. n_ins = random.randint(1, capacity) register_names = [] for i in range(n_ins): add = self.generate_add(capacity) register_names.append(add.rd) rob.feed(add) rob.tick() # Generate a Result value for each fed instruction. result_vals = [random.randint(1, 10000) for _ in range(n_ins)] # Publish all but first result in reverse order to ROB. Should be # no updates to act_rf as the first instruction is stalled! for i in reversed(range(1, n_ins)): rob.receive(Result(self.log.log[i].tag, result_vals[i])) rob.tick() self.assertEqual(exp_rf, act_rf) # Publish result of first instruction - all can now be comitted in # turn. rob.receive(Result(self.log.log[0].tag, result_vals[0])) # Group updates into ROB width chunks. updates = list(zip(register_names, result_vals)) group_updates = [ updates[i:i + rob.width] for i in range(0, len(updates), rob.width) ] # Ensure in-order commit of width instructions per tick. for group in group_updates: rob.tick() for (name, result) in group: exp_rf[name] = result self.assertEqual(exp_rf, act_rf) rob.tick()
def test_load_receive_and_can_dispatch_execute(self): ins = Load('ROB1', 'ROB2') self.assertFalse(ins.can_dispatch()) ins.receive(Result('ROB4', 0)) self.assertFalse(ins.can_dispatch()) ins.receive(Result('ROB1', 0)) self.assertFalse(ins.can_dispatch()) ins.receive(Result('ROB2', 7)) self.assertEqual(ins.address, 7) self.assertTrue(ins.can_dispatch())
def test_store_receive_and_can_dispatch_execute(self): ins = Store('ROB1', 'ROB7', 'ROB8') self.assertFalse(ins.can_dispatch()) ins.receive(Result('ROB4', 0)) self.assertFalse(ins.can_dispatch()) ins.receive(Result('ROB7', 0)) self.assertEqual(ins.address, 0) self.assertFalse(ins.can_dispatch()) ins.receive(Result('ROB8', 7)) self.assertTrue(ins.can_dispatch())
def test_result_equality(self): result = Result('r0', 10) none = Result('r1', 11) self.assertFalse(result == none, 'no attributes equal') val = Result('r2', 10) self.assertFalse(result == val, 'val equal but not dest') dest = Result('r0', 11) self.assertFalse(result == dest, 'dest equal but not val') val_dest = Result('r0', 10) self.assertTrue(result == val_dest, 'both attributes equal')
def test_inorder_execute(self): """Ensure Instructions are executed in-order.""" capacity = 16 lsq = LoadStoreQueue(self.memory, self.bus, capacity) # Fill LSQ with MemoryAccess Instructions. instructions = [] for i in range(capacity): ins = self.generate_memory_access(capacity) instructions.append(ins) lsq.feed(ins) lsq.tick() # Ensure all execute dependencies are met. for i in range(capacity): lsq.receive(Result('ROB%d' % i, i)) # Tick max # times req. for all Instructions to have completed. for _ in range(sum([ins.DELAY for ins in instructions])): lsq.tick() # Compute expected sequence of Results published by LoadStoreQueue. self.reset_memory() exp_results = [] for ins in instructions: result = ins.execute(self.memory) if result: exp_results.append(result) self.assertListEqual(self.bus.log, exp_results)
def test_receive_and_can_dispatch(self): ins = Binary('ROB1', lambda o1, o2: o1 + o2, 'ROB2', 'ROB3') self.assertFalse(ins.can_dispatch()) ins.receive(Result('ROB4', 0)) self.assertFalse(ins.can_dispatch()) ins.receive(Result('ROB2', 5)) self.assertFalse(ins.can_dispatch()) ins.receive(Result('ROB1', 0)) self.assertFalse(ins.can_dispatch()) ins.receive(Result('ROB3', 7)) self.assertTrue(ins.can_dispatch()) ins.receive(Result('ROB0', 0)) self.assertTrue(ins.can_dispatch())
def test_correct_result(self): """Test correct Result computed by IntegerUnit and published.""" add = IntegerLogical('ROB1', lambda o1, o2: o1 + o2, 5, 6) add.DELAY = 1 unit = IntegerUnit(self.bus_log) unit.feed(add) unit.trigger() unit.tick() self.assertEqual(self.bus_log.log, [Result('ROB1', 11)])
def test_instructions_receive_published_results(self): """Test Instructions receive published results and dispatch OK.""" ins = IntegerLogical('ROB1', lambda o1, o2: o1 - o2, 'ROB2', 'ROB3') self.rs.register(self.feed_log) self.rs.feed(ins) self.rs.trigger() self.rs.receive(Result('ROB4', 100)) self.rs.tick() self.assertListEqual(self.feed_log.log, []) self.rs.receive(Result('ROB3', 100)) self.rs.tick() self.assertListEqual(self.feed_log.log, []) self.rs.receive(Result('ROB2', 50)) self.rs.tick() self.assertListEqual(self.feed_log.log, [ins])
def test_instructions_receive_published_results(self): """Test Instructions receive published results OK.""" load = Load('ROB1', 'ROB2') store = Store('ROB3', 'ROB4', 'ROB2') lsq = LoadStoreQueue(self.memory, self.bus, 32) lsq.feed(load) lsq.feed(store) lsq.tick() lsq.receive(Result('ROB2', 10)) self.assertEqual(load.address, 10) self.assertEqual(store.value, 10)
def test_correct_result(self): """Test correct Result computed by BranchUnit and published.""" tests = [] cond = Conditional('ROB1', lambda o1, o2: o1 < o2, 5, 6) cond.DELAY = 1 tests.append((cond, Result('ROB1', True, typ=Branch))) cond = Conditional('ROB1', lambda o1, o2: o1 < o2, 6, 6) cond.DELAY = 1 tests.append((cond, Result('ROB1', False, typ=Branch))) uncond = Unconditional('ROB2', 10) uncond.DELAY = 1 tests.append((uncond, Result('ROB2', 10, typ=Branch))) for ins, exp_result in tests: self.bus_log.reset() unit = BranchUnit(self.bus_log) unit.feed(ins) unit.trigger() unit.tick() self.assertListEqual(self.bus_log.log, [exp_result])
def test_instructions_removed_from_queue_on_commit(self): """Test that commit frees a slot in the ROB.""" for capacity in [1, 5, 25, 200]: log = FeedLog() rob = ReorderBuffer(self.rf, log, self.lsq, capacity=capacity, width=4) # Half fill. for _ in range(capacity // 2): rob.feed(self.generate_add(self.n_gpr_registers)) rob.tick() # Instructions now in current queue. # Remove all fed from ROB queue by giving values. self.assertEqual(capacity // 2, len(log.log)) for ins in log.log: rob.receive(Result(ins.tag, 5)) for _ in range(math.ceil(capacity / rob.width)): rob.tick() # Should now be able to feed capacity instructions. for _ in range(capacity): rob.feed(self.generate_add(self.n_gpr_registers))
def execute(self): if not self.can_dispatch(): raise ValueError('unable to execute: operand not available') return Result(self.tag, self.operand, typ=Branch)
def execute(self): if not self.can_dispatch(): raise ValueError('unable to execute: operand(s) not available') value = self.operation(self.operand_1, self.operand_2) return Result(self.tag, value, typ=Branch)
def execute(self, memory): if not self.can_dispatch(): raise ValueError('unable to execute: operand(s) not available') return Result(self.tag, memory[self.address])
def test_execute(self): ins = Unconditional('ROB10', 'ROB4') with self.assertRaises(ValueError): ins.execute() ins.receive(Result('ROB4', 7)) self.assertEqual(ins.execute(), Result('ROB10', 7, Branch))