+ # argh. an experiment to merge RA and RB in the INT regfile
+ # (we have too many read/write ports)
+ #if regfile == 'INT':
+ #fuspecs['rabc'] = [fuspecs.pop('rb')]
+ #fuspecs['rabc'].append(fuspecs.pop('rc'))
+ #fuspecs['rabc'].append(fuspecs.pop('ra'))
+ #if regfile == 'FAST':
+ # fuspecs['fast1'] = [fuspecs.pop('fast1')]
+ # if 'fast2' in fuspecs:
+ # fuspecs['fast1'].append(fuspecs.pop('fast2'))
+
+ # for each named regfile port, connect up all FUs to that port
+ for (regname, fspec) in sort_fuspecs(fuspecs):
+ print("connect rd", regname, fspec)
+ self.connect_rdport(m, fu_bitdict, rdpickers, regfile,
+ regname, fspec)
+
+ def connect_wrport(self, m, fu_bitdict, wrpickers, regfile, regname, fspec):
+ comb, sync = m.d.comb, m.d.sync
+ fus = self.fus.fus
+ regs = self.regs
+
+ print("connect wr", regname, fspec)
+ rpidx = regname
+
+ # select the required write port. these are pre-defined sizes
+ print(regfile, regs.rf.keys())
+ rfile = regs.rf[regfile.lower()]
+ wport = rfile.w_ports[rpidx]
+
+ fspecs = fspec
+ if not isinstance(fspecs, list):
+ fspecs = [fspecs]
+
+ pplen = 0
+ writes = []
+ ppoffs = []
+ for i, fspec in enumerate(fspecs):
+ # get the regfile specs for this regfile port
+ (rf, read, write, wid, fuspec) = fspec
+ print ("fpsec", i, fspec, len(fuspec))
+ ppoffs.append(pplen) # record offset for picker
+ pplen += len(fuspec)
+
+ # create a priority picker to manage this port
+ wrpickers[regfile][rpidx] = wrpick = PriorityPicker(pplen)
+ setattr(m.submodules, "wrpick_%s_%s" % (regfile, rpidx), wrpick)
+
+ wsigs = []
+ wens = []
+ addrs = []
+ for i, fspec in enumerate(fspecs):
+ # connect up the FU req/go signals and the reg-read to the FU
+ # these are arbitrated by Data.ok signals
+ (rf, read, write, wid, fuspec) = fspec
+ for pi, (funame, fu, idx) in enumerate(fuspec):
+ pi += ppoffs[i]
+
+ # write-request comes from dest.ok
+ dest = fu.get_out(idx)
+ fu_dest_latch = fu.get_fu_out(idx) # latched output
+ name = "wrflag_%s_%s_%d" % (funame, regname, idx)
+ wrflag = Signal(name=name, reset_less=True)
+ comb += wrflag.eq(dest.ok & fu.busy_o)
+
+ # connect request-write to picker input, and output to go-wr
+ fu_active = fu_bitdict[funame]
+ pick = fu.wr.rel_o[idx] & fu_active # & wrflag
+ comb += wrpick.i[pi].eq(pick)
+ # create a single-pulse go write from the picker output
+ wr_pick = Signal()
+ comb += wr_pick.eq(wrpick.o[pi] & wrpick.en_o)
+ comb += fu.go_wr_i[idx].eq(rising_edge(m, wr_pick))
+
+ # connect the regspec write "reg select" number to this port
+ # only if one FU actually requests (and is granted) the port
+ # will the write-enable be activated
+ addr_en = Signal.like(write)
+ wp = Signal()
+ comb += wp.eq(wr_pick & wrpick.en_o)
+ comb += addr_en.eq(Mux(wp, write, 0))
+ if rfile.unary:
+ wens.append(addr_en)
+ else:
+ addrs.append(addr_en)
+ wens.append(wp)
+
+ # connect regfile port to input
+ print("reg connect widths",
+ regfile, regname, pi, funame,
+ dest.shape(), wport.data_i.shape())
+ wsigs.append(fu_dest_latch)
+
+ # here is where we create the Write Broadcast Bus. simple, eh?
+ comb += wport.data_i.eq(ortreereduce_sig(wsigs))
+ if rfile.unary:
+ # for unary-addressed
+ comb += wport.wen.eq(ortreereduce_sig(wens))
+ else:
+ # for binary-addressed
+ comb += wport.addr.eq(ortreereduce_sig(addrs))
+ comb += wport.wen.eq(ortreereduce_sig(wens))
+
+ def connect_wrports(self, m, fu_bitdict):
+ """connect write ports
+
+ orders the write regspecs into a dict-of-dicts, by regfile,
+ by regport name, then connects all FUs that want that regport
+ by way of a PriorityPicker.
+
+ note that the write-port wen, write-port data, and go_wr_i all need to
+ be on the exact same clock cycle. as there is a combinatorial loop bug
+ at the moment, these all use sync.
+ """
+ comb, sync = m.d.comb, m.d.sync
+ fus = self.fus.fus
+ regs = self.regs
+ # dictionary of lists of regfile write ports
+ byregfiles_wr, byregfiles_wrspec = self.get_byregfiles(False)
+
+ # same for write ports.
+ # BLECH! complex code-duplication! BLECH!
+ wrpickers = {}
+ for regfile, spec in byregfiles_wr.items():
+ fuspecs = byregfiles_wrspec[regfile]
+ wrpickers[regfile] = {}
+
+ # argh, more port-merging
+ if regfile == 'INT':
+ fuspecs['o'] = [fuspecs.pop('o')]
+ fuspecs['o'].append(fuspecs.pop('o1'))
+ if regfile == 'FAST':
+ fuspecs['fast1'] = [fuspecs.pop('fast1')]
+ if 'fast2' in fuspecs:
+ fuspecs['fast1'].append(fuspecs.pop('fast2'))
+
+ for (regname, fspec) in sort_fuspecs(fuspecs):
+ self.connect_wrport(m, fu_bitdict, wrpickers,
+ regfile, regname, fspec)
+
+ def get_byregfiles(self, readmode):
+
+ mode = "read" if readmode else "write"
+ regs = self.regs
+ fus = self.fus.fus
+ e = self.e # decoded instruction to execute
+
+ # dictionary of lists of regfile ports
+ byregfiles = {}
+ byregfiles_spec = {}
+ for (funame, fu) in fus.items():
+ print("%s ports for %s" % (mode, funame))
+ for idx in range(fu.n_src if readmode else fu.n_dst):
+ if readmode:
+ (regfile, regname, wid) = fu.get_in_spec(idx)
+ else:
+ (regfile, regname, wid) = fu.get_out_spec(idx)
+ print(" %d %s %s %s" % (idx, regfile, regname, str(wid)))
+ if readmode:
+ rdflag, read = regspec_decode_read(e, regfile, regname)
+ write = None
+ else:
+ rdflag, read = None, None
+ wrport, write = regspec_decode_write(e, regfile, regname)
+ if regfile not in byregfiles:
+ byregfiles[regfile] = {}
+ byregfiles_spec[regfile] = {}
+ if regname not in byregfiles_spec[regfile]:
+ byregfiles_spec[regfile][regname] = \
+ (rdflag, read, write, wid, [])
+ # here we start to create "lanes"
+ if idx not in byregfiles[regfile]:
+ byregfiles[regfile][idx] = []
+ fuspec = (funame, fu, idx)
+ byregfiles[regfile][idx].append(fuspec)
+ byregfiles_spec[regfile][regname][4].append(fuspec)
+
+ # ok just print that out, for convenience
+ for regfile, spec in byregfiles.items():
+ print("regfile %s ports:" % mode, regfile)
+ fuspecs = byregfiles_spec[regfile]
+ for regname, fspec in fuspecs.items():
+ [rdflag, read, write, wid, fuspec] = fspec
+ print(" rf %s port %s lane: %s" % (mode, regfile, regname))
+ print(" %s" % regname, wid, read, write, rdflag)
+ for (funame, fu, idx) in fuspec:
+ fusig = fu.src_i[idx] if readmode else fu.dest[idx]
+ print(" ", funame, fu, idx, fusig)
+ print()
+
+ return byregfiles, byregfiles_spec