Ejemplo n.º 1
0
class SimplifiedSuperScalarSimulator:
    def __init__(self, infile, outfile, num_registers=32):
        self.__disassembler = Disassembler()

        self.__input_file = infile
        self.__output_file = outfile
        self.__f = open('team13_out_pipeline.txt', 'w')

        self.__pc = 96
        self.__cycle = 0

        self.__memory = {}
        self.__last_inst = 0

        self.pre_issue_size = 4
        self.pre_alu_size = 2
        self.pre_mem_size = 2
        self.post_alu_size = 1
        self.post_mem_size = 1

        self.__pre_issue_buffer = deque(maxlen=self.pre_issue_size)

        self.__pre_mem_buffer = deque(maxlen=self.pre_mem_size)
        self.__pre_alu_buffer = deque(maxlen=self.pre_alu_size)

        self.__post_mem_buffer = deque(maxlen=self.post_mem_size)
        self.__post_alu_buffer = deque(maxlen=self.post_alu_size)

        self.__cache_to_load = deque(maxlen=2)

        self.__register_file = RegisterFile(num_registers)
        self.__wb = WriteBackUnit(self.__register_file)
        self.__cache = Cache(self.__memory)
        self.__alu = ALU()
        self.__mem = MemoryUnit(self.__cache)
        self.__if = IFUnit(self.__cache, self.__register_file)
        self.__iu = IssueUnit(self.__register_file, self.__pre_issue_buffer,
                              self.__pre_mem_buffer, self.__pre_alu_buffer,
                              self.__post_mem_buffer, self.__post_alu_buffer)

        self.__read_file()

    def __read_file(self):
        """
        Reads the designated input file and stores each line as a decimal integer
        """
        pc = 96
        with open(self.__input_file, 'r') as f:
            for line in f:
                self.__memory[pc] = int(line, 2)
                if int(line, 2) == Disassembler.break_inst:
                    self.__last_inst = pc
                pc += 4

    def __update_space(self):
        self.__pre_issue_space = self.pre_issue_size - len(
            self.__pre_issue_buffer)
        self.__pre_alu_space = self.pre_alu_size - len(self.__pre_alu_buffer)
        self.__pre_mem_space = self.pre_mem_size - len(self.__pre_mem_buffer)
        self.__post_alu_space = self.post_alu_size - len(
            self.__post_alu_buffer)
        self.__post_mem_space = self.post_mem_size - len(
            self.__post_mem_buffer)

    def __are_buffers_empty(self):
        self.__update_space()
        # print self.__pre_issue_space, \
        #     self.__pre_alu_space, \
        #     self.__pre_mem_space, \
        #     self.__post_alu_space, \
        #     self.__post_mem_space
        return self.__pre_issue_space == 4 and \
               self.__pre_alu_space == 2 and \
               self.__pre_mem_space == 2 and \
               self.__post_alu_space == 1 and \
               self.__post_mem_space == 1

    def run(self):
        run = True

        while run:
            run = False

            self.__cycle += 1
            print self.__cycle

            # Run WriteBackUnit
            if len(self.__post_mem_buffer) > 0:
                wb_in = self.__post_mem_buffer.popleft()
                self.__wb.run(wb_in, 'mem')
            if len(self.__post_alu_buffer) > 0:
                wb_in = self.__post_alu_buffer.popleft()
                self.__wb.run(wb_in, 'alu')

            self.__update_space()

            # Run ALU
            # If pre-buffer not empty and post-buffer not full
            if len(self.__pre_alu_buffer) > 0 and self.__post_alu_space > 0:
                alu_in = self.__pre_alu_buffer.popleft()
                alu_out = self.__alu.run(alu_in)
                self.__post_alu_buffer.append(alu_out)
                run = True

            self.__update_space()

            # Run MemoryUnit
            # If pre-buffer not empty and post-buffer not full
            if len(self.__pre_mem_buffer) > 0 and self.__post_mem_space > 0:
                mem_in = self.__pre_mem_buffer.popleft()
                mem_out = self.__mem.run(mem_in)
                if not mem_out:
                    self.__cache_to_load.append(mem_in['rn_val'] +
                                                mem_in['offset'])
                elif mem_out is not None:
                    self.__post_mem_buffer.append(mem_out)
                run = True

            self.__update_space()

            # Run Issue Unit (twice)
            # TODO Hazard detection
            if len(self.__pre_issue_buffer) > 0:
                self.__iu.run(self.__pre_mem_space, self.__pre_alu_space)
                run = True
                self.__update_space()

            # Run IF Unit
            # If pre-issue buffer not full
            result = True
            if self.__pc < self.__last_inst:
                if self.__pre_issue_space == 0:
                    continue
                elif self.__pre_issue_space == 1:
                    result = self.__if.run(self.__pc, 1)
                else:
                    result = self.__if.run(self.__pc, 2)
                if not result:
                    self.__cache_to_load.append(self.__pc)
                else:
                    insts = result[0]
                    self.__pc = result[1]
                    for inst in insts:
                        self.__pre_issue_buffer.append(inst)
                run = True

            self.__update_space()
            self.__print_state()

            while len(self.__cache_to_load) > 0:
                address = self.__cache_to_load.popleft()
                self.__cache.load(address)

    def __print_buffer(self, buffer):
        for i in range(buffer.maxlen):
            try:
                item = '[' + buffer[i]['assembly'] + ']'
            except IndexError:
                item = ''
            if item == '':
                self.__f.write('\tEntry {}:\n'.format(i, item))
            else:
                self.__f.write('\tEntry {}:\t{}\n'.format(i, item))

    def __print_buffers(self):
        self.__f.write('Pre-Issue Buffer:\n')
        self.__print_buffer(self.__pre_issue_buffer)

        self.__f.write('Pre_ALU Queue:\n')
        self.__print_buffer(self.__pre_alu_buffer)

        self.__f.write('Post_ALU Queue:\n')
        self.__print_buffer(self.__post_alu_buffer)

        self.__f.write('Pre_MEM Queue:\n')
        self.__print_buffer(self.__pre_mem_buffer)

        self.__f.write('Post_MEM Queue:\n')
        self.__print_buffer(self.__post_mem_buffer)

        self.__f.write('\n')

    def __print_registers(self):
        self.__f.write('Registers\n')
        for i in range(4):
            self.__f.write('R{:02d}:'.format(i * 8))
            for j in range(8):
                value = self.__register_file.read_register(i * 8 + j)
                self.__f.write('\t{}'.format(value))
            self.__f.write('\n')
        self.__f.write('\n')

    def __print_cache(self):
        self.__f.write('Cache\n')
        for s, set in enumerate(self.__cache.get_cache()):
            self.__f.write('Set {}: LRU={}\n'.format(s, set['lru']))
            for b, block in enumerate(set['blocks']):
                valid = int(block['valid'])
                dirty = int(block['dirty'])
                tag = int(block['tag']) if block['tag'] is not None else '0'
                content1 = '{0:032b}'.format(block['content'][0]) if (
                    block['content'][0] != 0
                    and block['content'][0] is not None) else '0'
                content2 = '{0:032b}'.format(block['content'][1]) if (
                    block['content'][1] != 0
                    and block['content'][1] is not None) else '0'

                self.__f.write('\tEntry {}:[({},{},{})<{},{}>]\n'.format(
                    b, valid, dirty, tag, content1, content2))

        self.__f.write('\n')

    def __print_memory(self):
        self.__f.write('Data\n')

        # Filter data out of memory
        data = dict(self.__memory)
        for a in range(96, self.__last_inst + 4, 4):
            del data[a]

        # Fix stupid formatting, thanks Greg
        if len(data) > 0:
            # Add 0s from beginning to first
            first_data = min(data.keys())
            for a in range(self.__last_inst + 4, first_data, 4):
                data[a] = 0

            # Add 0s from last to end of line
            last_data = max(data.keys())
            a = last_data + 4
            while (a - first_data) % 8 != 0:
                data[a] = 0
                a += 4

        # Print useful information
        addresses = list(data.keys())
        addresses.sort()
        for i, addr in enumerate(addresses):
            if i % 8 == 0:
                self.__f.write('\n{}:\t{}'.format(addr, data[addr]))
            else:
                self.__f.write('\t{}'.format(data[addr]))
        self.__f.write('\n' * 2)

    def __print_state(self):
        self.__f.write('-' * 20 + '\n')
        self.__f.write('Cycle:{}\n\n'.format(self.__cycle))
        self.__print_buffers()
        self.__print_registers()
        self.__print_cache()
        self.__print_memory()