From: Luke Kenneth Casson Leighton Date: Wed, 24 Nov 2021 22:46:04 +0000 (+0000) Subject: convert hazard bitvectors to Reset-Priority SRLatch from nmutil X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=e54224a6c62347541fb7dd41804943b7b2a7dde6;p=soc.git convert hazard bitvectors to Reset-Priority SRLatch from nmutil the read/write port were seriously getting in the way, by way of the operand forwarding etc. etc. need instead to get either the immediate-latched value (combinatorial) or the sync-delayed one, depending on circumstances. --- diff --git a/src/soc/regfile/regfiles.py b/src/soc/regfile/regfiles.py index adbe1363..58c7526f 100644 --- a/src/soc/regfile/regfiles.py +++ b/src/soc/regfile/regfiles.py @@ -33,6 +33,7 @@ from openpower.consts import StateRegsEnum, XERRegsEnum, FastRegsEnum from nmigen import Module from nmigen.cli import rtlil +from nmutil.latch import SRLatch def create_ports(rf, wr_spec, rd_spec): @@ -285,21 +286,9 @@ class RegFiles: def make_hazard_vec(self, rf, name): if isinstance(rf, VirtualRegPort): - vec = VirtualRegPort(rf.nregs, rf.nregs, rd2=True, wr2=True) + vec = SRLatch(sync=False, llen=rf.nregs, name=name) else: - vec = VirtualRegPort(rf.depth, rf.depth, rd2=True, wr2=True) - # get read/write port specs and create bitvector ports with same names - wr_spec, rd_spec = rf.get_port_specs() - # ok, this is complicated/fun. - # issue phase for checking whether to issue only needs one read port - # however during regfile-read, the corresponding bitvector needs to - # be *WRITTEN* to (a 1), and during regfile-write, the corresponding - # bitvector *ALSO* needs to be wrtten (a 0). therefore we need to - # MERGE the wr_spec and rd_spec with some appropriate name prefixes - # to make sure they do not clash - rd_bvspec = {'issue': 'full_rd', 'whazard': 'full_rd2'} - wr_bvspec = {'set': 'full_wr', 'clr': 'full_wr2'} - create_ports(vec, wr_bvspec, rd_bvspec) + vec = SRLatch(sync=False, llen=rf.depth, name=name) return vec def elaborate_into(self, m, platform): diff --git a/src/soc/simple/core.py b/src/soc/simple/core.py index 72140d81..5b0cc8ea 100644 --- a/src/soc/simple/core.py +++ b/src/soc/simple/core.py @@ -450,7 +450,7 @@ class NonProductionCore(ControlBase): # for checking if the read port has an outstanding write if self.make_hazard_vecs: wv = regs.wv[regfile.lower()] - wvchk = wv.r_ports["issue"] # write-vec bit-level hazard check + wvchk = wv.q_int # write-vec bit-level hazard check # if a hazard is detected on this read port, simply blithely block # every FU from reading on it. this is complete overkill but very @@ -558,7 +558,7 @@ class NonProductionCore(ControlBase): continue # read the write-hazard bitvector (wv) for any bit that is - wvchk_en = Signal(len(wvchk.ren), name="wv_chk_addr_en_"+name) + wvchk_en = Signal(len(wvchk), name="wv_chk_addr_en_"+name) issue_active = Signal(name="rd_iactive_"+name) # XXX combinatorial loop here comb += issue_active.eq(fu_active & rf) @@ -576,7 +576,7 @@ class NonProductionCore(ControlBase): # read-hazard is ANDed with (filtered by) what is actually # being requested. - comb += rhazard.eq((wvchk.o_data & wvchk_en).bool()) + comb += rhazard.eq((wvchk & wvchk_en).bool()) wvens.append(wvchk_en) @@ -595,8 +595,9 @@ class NonProductionCore(ControlBase): # enable the read bitvectors for this issued instruction # and return whether any write-hazard bit is set - comb += wvchk.ren.eq(ortreereduce_sig(wvens)) - comb += hazard_detected.eq(wvchk.o_data.bool()) + wvchk_and = Signal(len(wvchk), name="wv_chk_"+name) + comb += wvchk_and.eq(wvchk & ortreereduce_sig(wvens)) + comb += hazard_detected.eq(wvchk_and.bool()) return hazard_detected def connect_rdports(self, m, fu_bitdict, fu_selected): @@ -671,7 +672,7 @@ class NonProductionCore(ControlBase): # the detection of what shall be written to is based # on *issue* print ("write vector (for regread)", regfile, wvset) - wviaddr_en = Signal(len(wvset.wen), name="wv_issue_addr_en_"+name) + wviaddr_en = Signal(len(wvset), name="wv_issue_addr_en_"+name) issue_active = Signal(name="iactive_"+name) comb += issue_active.eq(fu.issue_i & fu_active & wrflag) with m.If(issue_active): @@ -683,7 +684,7 @@ class NonProductionCore(ControlBase): # deal with write vector clear: this kicks in when the regfile # is written to, and clears the corresponding bitvector entry print ("write vector", regfile, wvclr) - wvaddr_en = Signal(len(wvclr.wen), name="wvaddr_en_"+name) + wvaddr_en = Signal(len(wvclr), name="wvaddr_en_"+name) if rfile.unary: comb += wvaddr_en.eq(addr_en) else: @@ -733,9 +734,10 @@ class NonProductionCore(ControlBase): # to RAISE the bitvector (set it to 1), which, duh, requires a WRITE if self.make_hazard_vecs: wv = regs.wv[regfile.lower()] - wvset = wv.w_ports["set"] # write-vec bit-level hazard ctrl - wvclr = wv.w_ports["clr"] # write-vec bit-level hazard ctrl - wvchk = wv.r_ports["whazard"] # write-after-write hazard check + wvset = wv.s # write-vec bit-level hazard ctrl + wvclr = wv.r # write-vec bit-level hazard ctrl + wvchk = wv.q # write-after-write hazard check + wvchk_qint = wv.q_int # write-after-write hazard check, delayed fspecs = fspec if not isinstance(fspecs, list): @@ -850,11 +852,10 @@ class NonProductionCore(ControlBase): wvaddr_en, wv_issue_en = res wvclren.append(wvaddr_en) # set only: no data => clear bit wvseten.append(wv_issue_en) # set data same as enable - wvsets.append(wv_issue_en) # because enable needs a 1 # read the write-hazard bitvector (wv) for any bit that is fu_requested = fu_bitdict[funame] - wvchk_en = Signal(len(wvchk.ren), name="waw_chk_addr_en_"+name) + wvchk_en = Signal(len(wvchk), name="waw_chk_addr_en_"+name) issue_active = Signal(name="waw_iactive_"+name) whazard = Signal(name="whaz_"+name) if wf is None: @@ -884,7 +885,7 @@ class NonProductionCore(ControlBase): # write-hazard is ANDed with (filtered by) what is actually # being requested. the wvchk data is on a one-clock delay, # and wvchk_en comes directly from the main decoder - comb += whazard.eq((wvchk.o_data & wvchk_en).bool()) + comb += whazard.eq((wvchk_qint & wvchk_en).bool()) with m.If(whazard): comb += fu._waw_hazard.eq(1) @@ -904,17 +905,8 @@ class NonProductionCore(ControlBase): return # for write-vectors - comb += wvclr.wen.eq(ortreereduce_sig(wvclren)) # clear (regfile write) - comb += wvset.wen.eq(ortreereduce_sig(wvseten)) # set (issue time) - comb += wvset.i_data.eq(ortreereduce_sig(wvsets)) - - # for write-after-write. this gets the write vector one cycle - # late but that's ok... no, actually it's essential, and here's why: - # on issue, the write-to-bitvector occurs, but occurs one cycle late. - # if we were not reading the write-bitvector one cycle early (its - # previous state on the previous cycle), we would end up reading - # our *own* write-request as a write-after-write hazard! - comb += wvchk.ren.eq(-1) # always enable #ortreereduce_sig(wvens)) + comb += wvclr.eq(ortreereduce_sig(wvclren)) # clear (regfile write) + comb += wvset.eq(ortreereduce_sig(wvseten)) # set (issue time) def connect_wrports(self, m, fu_bitdict, fu_selected): """connect write ports