Esempio n. 1
0
 def __init__(self,cycle=0,fp=None,int=None,mem=None,use_trace=False, no_fma=False):
     self.no_fma = no_fma
     self.cycle = cycle
     self.counter = defaultdict(lambda:0)
     self.fp = fp   if fp  is not None else RegisterFile(FPRegister,Core.fpregisters)
     self.int = int if int is not None else RegisterFile(IntRegister,Core.intregisters)
     self.mem = mem if mem is not None else [0.0]*Core.memsize
     self.hazards = Pipeline('Register')
     self.units = Pipeline('Logic Unit')
     self.inuse_src = Pipeline('Registers unavailable as source (non-hazard)')
     self.inuse_dst = Pipeline('Registers unavailable as destination (non-hazard)')
     self.writethrough = WriteThrough()
     self.regnames = dict()
     self.fppool = set(self.fp.keys())
     self.fpeternal = set()
     self.trace = self.trace_print if use_trace else self.trace_none
     self.use_trace = use_trace # storing this is a dirty hack, only used externally
     self.cv = CViewer(self)
Esempio n. 2
0
class Core:
    memsize = 32                # Number of doubles
    fpregisters = 32
    intregisters = 32
    inline_asm = ''

    def __init__(self,cycle=0,fp=None,int=None,mem=None,use_trace=False, no_fma=False):
        self.no_fma = no_fma
        self.cycle = cycle
        self.counter = defaultdict(lambda:0)
        self.fp = fp   if fp  is not None else RegisterFile(FPRegister,Core.fpregisters)
        self.int = int if int is not None else RegisterFile(IntRegister,Core.intregisters)
        self.mem = mem if mem is not None else [0.0]*Core.memsize
        self.hazards = Pipeline('Register')
        self.units = Pipeline('Logic Unit')
        self.inuse_src = Pipeline('Registers unavailable as source (non-hazard)')
        self.inuse_dst = Pipeline('Registers unavailable as destination (non-hazard)')
        self.writethrough = WriteThrough()
        self.regnames = dict()
        self.fppool = set(self.fp.keys())
        self.fpeternal = set()
        self.trace = self.trace_print if use_trace else self.trace_none
        self.use_trace = use_trace # storing this is a dirty hack, only used externally
        self.cv = CViewer(self)

    def __str__(self):
        return ('Core(cycle=%r,\n\tfp=%s,\n\tint=%s,\n\tmem=%r,\n\tregnames=%s,\n\tcounter=%s)'
                % (self.cycle,self.fp,self.int,self.mem,self.regnames,dict(self.counter)))
    def __repr__(self):
        return ('Core(cycle=%r,\n\tfp=%r,\n\tint=%r,\n\tmem=%r,\n\tregnames=%r)'
                % (self.cycle,self.fp,self.int,self.mem,self.regnames))
    def flush_pipeline(self):
        self.hazards.flush()
        self.inuse_src.flush()
        self.inuse_dst.flush()
        self.units.flush()
        self.writethrough.flush()
    def name_registers(self,**args):
        self.regnames.update(args)
        self.fppool.difference_update(args.values())
    def gc(self):
        raise Exception('Garbage collector not implemented')
    def get_fpregister(self,reg,allocate=True):
        if isinstance(reg,Register): # The register has been named explicitly
            self.fppool.discard(reg)
            return reg
        elif isinstance(reg,str): # It is a string, find a concrete register
            phys = self.regnames.get(reg)
            if phys is None:
                if not allocate: 
                    raise Exception('Register "%s" has not been allocated' % (reg,))
                if len(self.fppool) < 1:
                    self.gc()
                try:
                    phys = self.fppool.pop()
                except KeyError:
                    raise Exception('Cannot find a free register')
                self.regnames[reg] = phys
            return phys
        else:
            raise Exception('Invalid register: %r' % reg)
    def access_fpregisters(self,*args):
        return (self.fp[self.get_fpregister(reg)] for reg in args)
    def acquire_fpregisters(self,numbers):
        regs = list(map(FPRegister,numbers)) # Have to make this a list because otherwise set.update(regs) modifies regs
        self.fpeternal.update(regs)
        self.fppool.difference_update(regs)
        return regs
    def next_cycle(self):
        self.cycle += 1
        self.hazards.retire()
        self.inuse_src.retire()
        self.inuse_dst.retire()
        self.units.retire()
        self.writethrough.retire()
    def trace_none(self,msg):
        pass
    def trace_print(self,msg):
        if isinstance(msg,isa.Instruction):
            print('[%2d] %s' % (self.cycle,msg))
        else:
            print('[%2d] -- %s' % (self.cycle,msg))
    def print_inline(self,instr):
        self.inline_asm += '%s\n' % self.cv.named_view(instr)
    def execute_one(self,instr):
        while self.units.stall((instr.unit,)) > 0:
            self.trace('Instruction unit in use: %s' % (instr.unit,))
            self.next_cycle()
        while self.hazards.stall(map(self.get_fpregister,instr.read)) > 0:
            def format_hazards(odict):
                return ', '.join('(%s:%s,%d)' % (reg,self.get_fpregister(reg,allocate=False),cost) for (reg,cost) in odict.items())
            self.trace('Register hazards: %s' % format_hazards(self.hazards.conflicts(instr.read)))
            self.next_cycle()
        while self.inuse_src.stall(map(self.get_fpregister,instr.read)) > 0:
            def format_inuse_src(odict):
                return ', '.join('(%s:%s,%d)' % (reg,self.get_fpregister(reg,allocate=False),cost) for (reg,cost) in odict.items())
            self.trace('Register inuse_src: %s' % format_inuse_src(self.inuse_src.conflicts(instr.read)))
            self.next_cycle()
        while self.inuse_dst.stall(map(self.get_fpregister,instr.write)) > 0:
            def format_inuse_dst(odict):
                return ', '.join('(%s:%s,%d)' % (reg,self.get_fpregister(reg,allocate=False),cost) for (reg,cost) in odict.items())
            self.trace('Register inuse_dst: %s' % format_inuse_dst(self.inuse_dst.conflicts(instr.read)))
            self.next_cycle()
        while self.writethrough.stall(instr.writethrough):
            self.trace('WriteThrough tokens in use')
            self.next_cycle()
        self.trace(instr)
        instr.run(self)
        self.print_inline(instr)
        self.counter[instr.unit] += 1
        self.units[instr.unit] = instr.ithroughput
        for reg in instr.write:
            self.hazards[reg] = instr.latency
        for reg,(src_latency,dst_latency) in instr.inuse_regs.items():
            self.inuse_src[reg] = src_latency
            self.inuse_dst[reg] = dst_latency
        self.writethrough.issue(instr.writethrough)
    def execute(self,code):
        cycle_start = self.cycle
        for instr in code:
            self.execute_one(instr)
        return self.cycle - cycle_start
    def cost(self,instr):
        cost = max(self.units.stall((instr.unit,)),
                   self.hazards.stall((self.get_fpregister(reg,allocate=False) for reg in instr.read)),
                   self.inuse_src.stall((self.get_fpregister(reg,allocate=False) for reg in instr.read)),
                   self.inuse_dst.stall((self.get_fpregister(reg,allocate=False) for reg in instr.write)),
                   self.writethrough.stall(instr.writethrough))
        return cost
    def schedule_one(self,istream):
        def get_candidates(stream):
            'generator for safe instructions'
            stream_write = set() # Preserves order for read-after-write
            stream_read  = set() # Preserves order for write-after-read
            for i,instr in enumerate(stream):
                instr_read = instr.read.union(instr.iread)
                instr_write = instr.write.union(instr.iwrite)
                if stream_write.isdisjoint(instr_read) and stream_read.isdisjoint(instr_write):
                    yield i,instr
                stream_write.update(instr_write)
                stream_read.update(instr_read)
        candidates = list(get_candidates(istream))
        if len(candidates) < 1:
            raise Exception('Cannot find a safe instruction')
        (i,instr) = min(candidates, key=lambda c:self.cost(c[1]))
        self.execute_one(instr)
        del istream[i]
    def schedule(self,istream):
        cycle_start = self.cycle
        while len(istream) > 0:
            self.schedule_one(istream)
        return self.cycle - cycle_start