""" Mitch Alsup 6600-style LD/ST scoreboard Dependency Cell
-Relevant comments (p45-46):
-
-* If there are no WAR dependencies on a Load instruction with a computed
- address it can assert Bank_Addressable and Translate_Addressable.
-
-* If there are no RAW dependencies on a Store instruction with both a
- write permission and store data present it can assert Bank_Addressable
-
Relevant bugreports:
* http://bugs.libre-riscv.org/show_bug.cgi?id=81
def __init__(self, n_ls=1):
self.n_ls = n_ls
# inputs
- self.load_i = Signal(n_ls, reset_less=True) # load pend in (top)
- self.stor_i = Signal(n_ls, reset_less=True) # store pend in (top)
- self.issue_i = Signal(reset_less=True) # Issue in (top)
- self.go_die_i = Signal(reset_less=True) # Issue in (top)
+ self.load_h_i = Signal(reset_less=True) # load in (left)
+ self.stor_h_i = Signal(reset_less=True) # store in (left)
+ self.load_v_i = Signal(n_ls, reset_less=True) # load in (top)
+ self.stor_v_i = Signal(n_ls, reset_less=True) # store in (top)
+ self.issue_i = Signal(reset_less=True) # Issue in (left)
+ self.go_die_i = Signal(reset_less=True) # Issue in (left)
# load / store hit - basically connect these to go_wr from LD/STCompUnit
# LD.go_wr -> load_hit_i, ST.go_wr -> stwd_hit_i.
issue = Repl(self.issue_i, self.n_ls)
die = Repl(self.go_die_i, self.n_ls)
- # issue & store & load - used for both WAR and RAW Setting
+ # issue & store & load - used for WAR Setting. LD is left, ST is top
+ i_s = Signal(reset_less=True)
i_s_l = Signal(self.n_ls, reset_less=True)
- m.d.comb += i_s_l.eq(issue & self.stor_i & self.load_i)
+ m.d.comb += i_s.eq(issue & self.stor_h_i) # horizontal single-signal
+ m.d.comb += i_s_l.eq(Repl(i_s, self.n_ls) & self.load_v_i) # multi, vert
+
+ # issue & load & store - used for RAW Setting. ST is left, LD is top
+ i_l = Signal(reset_less=True)
+ i_l_s = Signal(self.n_ls, reset_less=True)
+ m.d.comb += i_l.eq(issue & self.load_h_i) # horizontal single-signal
+ m.d.comb += i_l_s.eq(Repl(i_l, self.n_ls) & self.stor_v_i) # multi, vert
# write after read latch: loads block stores
m.d.comb += war_l.s.eq(i_s_l)
- m.d.comb += war_l.r.eq(die | self.load_i) # reset on LD
+ m.d.comb += war_l.r.eq(die | ~self.load_v_i) # reset on LD
# read after write latch: stores block loads
m.d.comb += raw_l.s.eq(i_s_l)
- m.d.comb += raw_l.r.eq(die | self.stor_i) # reset on ST
+ m.d.comb += raw_l.r.eq(die | ~self.stor_v_i) # reset on ST
# Hold results (read out horizontally, accumulate in OR fashion)
m.d.comb += self.ld_hold_st_o.eq((war_l.qn & self.load_hit_i).bool())
return m
def __iter__(self):
- yield self.load_i
- yield self.stor_i
+ yield self.load_h_i
+ yield self.load_v_i
+ yield self.stor_h_i
+ yield self.stor_h_i
yield self.issue_i
yield self.load_hit_i
yield self.stwd_hit_i
write permission and store data present it can assert Bank_Addressable
Relevant bugreports:
+
* http://bugs.libre-riscv.org/show_bug.cgi?id=81
+Notes:
+
+* Load Hit (or Store Hit with Data) are asserted by the LD/ST Computation
+ Unit when it has data and address ready
+
+* Asserting the ld_hit_i (or stwd_hit_i) *requires* that the output be
+ captured or at least taken into consideration for the next LD/STs
+ *right then*. Failure to observe the xx_hold_xx_o *will* result in
+ data corruption, as they are *only* asserted if xx_hit_i is asserted
+
+* The hold signals still have to go through "maybe address clashes"
+ detection, they cannot just be used as-is to stop a LD/ST.
+
"""
from nmigen.compat.sim import run_simulation
self.stwd_hit_i = Signal(n_ldst, reset_less=True) # store w/data hit in
# outputs
- self.ld_hold_st_o = Signal(reset_less=True) # load holds st out
- self.st_hold_ld_o = Signal(reset_less=True) # st holds load out
+ self.ld_hold_st_o = Signal(n_ldst, reset_less=True) # load holds st out
+ self.st_hold_ld_o = Signal(n_ldst, reset_less=True) # st holds load out
def elaborate(self, platform):
m = Module()
# ---
- # matrix of dependency cells
+ # matrix of dependency cells. actually, LDSTDepCell is a row, now
# ---
- dm = Array(LDSTDepCell() for f in range(self.n_ldst))
+ dm = Array(LDSTDepCell(self.n_ldst) for f in range(self.n_ldst))
for fu in range(self.n_ldst):
setattr(m.submodules, "dm_fu%d" % (fu), dm[fu])
# ---
- # connect Function Unit vector
+ # connect Function Unit vector, all horizontal
# ---
lhs_l = []
shl_l = []
sh_l = []
for fu in range(self.n_ldst):
dc = dm[fu]
- # accumulate load-hold-store / store-hold-load bits
+ # accumulate load-hold-store / store-hold-load bits (horizontal)
lhs_l.append(dc.ld_hold_st_o)
shl_l.append(dc.st_hold_ld_o)
# accumulate inputs (for Cat'ing later) - TODO: must be a better way
- load_l.append(dc.load_i)
- stor_l.append(dc.stor_i)
+ load_l.append(dc.load_h_i)
+ stor_l.append(dc.stor_h_i)
issue_l.append(dc.issue_i)
- lh_l.append(dc.load_hit_i)
- sh_l.append(dc.stwd_hit_i)
+
+ # load-hit and store-with-data-hit go in vertically (top)
+ m.d.comb += [dc.load_hit_i.eq(self.load_hit_i),
+ dc.stwd_hit_i.eq(self.stwd_hit_i)
+ ]
# connect cell inputs using Cat(*list_of_stuff)
m.d.comb += [Cat(*load_l).eq(self.load_i),
Cat(*stor_l).eq(self.stor_i),
Cat(*issue_l).eq(self.issue_i),
- Cat(*lh_l).eq(self.load_hit_i),
- Cat(*sh_l).eq(self.stwd_hit_i),
]
- # set the load-hold-store / store-hold-load OR-accumulated outputs
- m.d.comb += self.ld_hold_st_o.eq(Cat(*lhs_l).bool())
- m.d.comb += self.st_hold_ld_o.eq(Cat(*shl_l).bool())
+ # connect the load-hold-store / store-hold-load OR-accumulated outputs
+ m.d.comb += self.ld_hold_st_o.eq(Cat(*lhs_l))
+ m.d.comb += self.st_hold_ld_o.eq(Cat(*shl_l))
+
+ # the load/store input also needs to be connected to "top" (vertically)
+ for fu in range(self.n_ldst):
+ load_v_l = []
+ stor_v_l = []
+ for fux in range(self.n_ldst):
+ dc = dm[fux]
+ load_v_l.append(dc.load_v_i[fu])
+ stor_v_l.append(dc.stor_v_i[fu])
+ m.d.comb += [Cat(*load_v_l).eq(self.load_i),
+ Cat(*stor_v_l).eq(self.stor_i),
+ ]
return m