def setUp(self): self.clock = Clock() self.bus = BusLog() self.memory = Memory(10) for i in range(len(self.memory)): self.memory[i] = i self.n_gpr = 6 self.rf = RegisterFile(self.n_gpr, 'r', init_values={'r%d' % i: i for i in range(self.n_gpr)}) iu1 = IntegerUnit(self.bus) iu2 = IntegerUnit(self.bus) iu3 = IntegerUnit(self.bus) rs = ReservationStation() rs.register(iu1) rs.register(iu2) rs.register(iu3) lsq = LoadStoreQueue(self.memory, self.bus) self.rob = ReorderBuffer(self.rf, rs, lsq) self.clock.register(self.rob) self.clock.register(lsq) self.clock.register(rs) self.clock.register(iu3) self.clock.register(iu2) self.clock.register(iu1) self.bus.subscribe(self.rob) self.bus.subscribe(rs) self.bus.subscribe(lsq)
class TestIntegration(unittest.TestCase): def setUp(self): self.clock = Clock() self.bus = BusLog() self.memory = Memory(10) for i in range(len(self.memory)): self.memory[i] = i self.n_gpr = 6 self.rf = RegisterFile(self.n_gpr, 'r', init_values={'r%d' % i: i for i in range(self.n_gpr)}) iu1 = IntegerUnit(self.bus) iu2 = IntegerUnit(self.bus) iu3 = IntegerUnit(self.bus) rs = ReservationStation() rs.register(iu1) rs.register(iu2) rs.register(iu3) lsq = LoadStoreQueue(self.memory, self.bus) self.rob = ReorderBuffer(self.rf, rs, lsq) self.clock.register(self.rob) self.clock.register(lsq) self.clock.register(rs) self.clock.register(iu3) self.clock.register(iu2) self.clock.register(iu1) self.bus.subscribe(self.rob) self.bus.subscribe(rs) self.bus.subscribe(lsq) def test_straightline_integration(self): instructions = [Add('r2', 'r3', 'r4'), Store('r1', 'r2'), Load('r1', 'r2'), AddI('r1', 'r1', 1), Store('r1', 'r2')] for ins in instructions: self.rob.feed(ins) # Enough clock ticks to ensure completion. for _ in range(100): self.clock.tick() self.assertListEqual([self.rf['r%d' % i] for i in range(self.n_gpr)], [0, 2, 7, 3, 4, 5]) self.assertListEqual([self.memory[i] for i in range(len(self.memory))], [0, 1, 2, 3, 4, 5, 6, 2, 8, 9])
def test_feed_full(self): """Test full operation when feeding Instructions.""" for rob_capacity in [1, 5, 25, 200]: for rs_capacity in [1, 5, 25, 200]: for lsq_capacity in [1, 5, 25, 200]: register_limit = min(rob_capacity, rs_capacity) memory_limit = min(rob_capacity, lsq_capacity) rs = ReservationStation(capacity=rs_capacity) lsq = LoadStoreQueue(self.memory, self.bus, capacity=lsq_capacity) rob = ReorderBuffer(self.rf, rs, lsq, capacity=rob_capacity) for _ in range(register_limit): ins = self.generate_add(self.n_gpr_registers) self.assertFalse( rob.full(ins), 'ReorderBuffer should not be full after < %d feeds' % register_limit) rob.feed(ins) self.assertTrue( rob.full(self.generate_add(self.n_gpr_registers)), 'ReorderBuffer should be full after %d feeds' % register_limit) with self.assertRaises(AssertionError): rob.feed(self.generate_add(self.n_gpr_registers))
def test_flush(self): """Ensure flush of ReorderBuffer, LoadStoreQueue and ReservationStation.""" rs = FlushableLog() rs.full = lambda: False rs.feed = lambda x: None lsq = FlushableLog() lsq.full = lambda: False lsq.feed = lambda x: None for rob_capacity in [1, 5, 25, 200]: for rs_capacity in [1, 5, 25, 200]: for lsq_capacity in [1, 5, 25, 200]: register_limit = min(rob_capacity, rs_capacity) rs.reset() lsq.reset() rob = ReorderBuffer(self.rf, rs, lsq, capacity=rob_capacity) for _ in range(register_limit): rob.feed(self.generate_add(self.n_gpr_registers)) rob.flush() self.assertFalse( rob.full(self.generate_add(self.n_gpr_registers)), 'ReorderBuffer should not be full after flush') self.assertEqual( rs.n_flush, 1, 'ReorderBuffer must flush ReservationStation') self.assertEqual( lsq.n_flush, 1, 'ReorderBuffer must flush LoadStoreQueue')
def test_get_queue_id(self): """Test that _get_queue_id throws an error on wrap-around.""" for capacity in [1, 5, 25, 200]: rob = ReorderBuffer(self.rf, self.log, self.lsq, capacity=capacity) for _ in range(capacity): rob._get_queue_id() with self.assertRaises(AssertionError): rob._get_queue_id()
if args.always_taken: branch_predictor = AlwaysTaken() elif args.never_taken: branch_predictor = NeverTaken() elif args.back_taken_forward_not: branch_predictor = BackTakenForwardNot() elif args.branch_history_table: branch_predictor = BranchHistoryTable( n_entries=args.branch_history_table[0], n_prediction_bits=args.branch_history_table[1]) else: branch_predictor = BranchHistoryTable(n_entries=2**8, n_prediction_bits=2) reorder_buffer = ReorderBuffer(register_file, reservation_station, load_store_queue, branch_predictor=branch_predictor, capacity=args.capacity, width=args.superscalar_width) decode = Decode(reorder_buffer, capacity=args.capacity, width=args.superscalar_width) fetch = Fetch(register_file, program.PROGRAM, decode, branch_predictor, width=args.superscalar_width) # Add additional connections. broadcast_bus.subscribe(reservation_station)
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 test_invalid_capacity(self): """Test exception thrown when initialized with invalid capacity.""" for _ in range(100): invalid = random.randint(-1000, 0) with self.assertRaises(ValueError): ReorderBuffer(self.rf, self.log, self.lsq, capacity=invalid)
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_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_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()