from nmutil.latch import SRLatch, latchregister
from soc.decoder.power_decoder2 import Data
from soc.decoder.power_enums import InternalOp
+from soc.regfile.regfile import ortreereduce
+from nmutil.util import treereduce
from soc.experiment.compldst import CompLDSTOpSubset
from soc.decoder.power_decoder2 import Data
# for testing purposes
from soc.experiment.testmem import TestMemory
-
class PortInterface(RecordObject):
"""PortInterface
def __init__(self, name=None):
layout = (('data', 128),
- ('byte_enable', 16)
+ ('en', 16)
)
Record.__init__(self, Layout(layout), name=name)
-# TODO:
+ #FIXME: make resetless
+# TODO: unit test
class DataMerger(Elaboratable):
"""DataMerger
- Merges data based on an address-match matrix
-
+ Merges data based on an address-match matrix.
+ Identifies (picks) one (any) row, then uses that row,
+ based on matching address bits, to merge (OR) all data
+ rows into the output.
+
+ Basically, by the time DataMerger is used, all of its incoming data is
+ determined not to conflict. The last step before actually submitting
+ the request to the Memory Subsystem is to work out which requests,
+ on the same 128-bit cache line, can be "merged" due to them being:
+ (A) on the same address (bits 4 and above) (B) having byte-enable
+ lines that (as previously mentioned) do not conflict.
+
+ Therefore, put simply, this module will:
+ (1) pick a row (any row) and identify it by an index labelled "idx"
+ (2) merge all byte-enable lines which are on that same address, as
+ indicated by addr_match_i[idx], onto the output
"""
def __init__(self, array_size):
"""
- :addr_array_i: an NxN Array of Signals with bits set indicating address match
+ :addr_array_i: an NxN Array of Signals with bits set indicating address
+ match. bits across the diagonal (addr_array_i[x][x])
+ will always be set, to indicate "active".
:data_i: an Nx Array of Records {data: 128 bit, byte_enable: 16 bit}
- :data_o: an Output Record of same type {data: 128 bit, byte_enable: 16 bit}
+ :data_o: an Output Record of same type
+ {data: 128 bit, byte_enable: 16 bit}
"""
self.array_size = array_size
ul = []
- for i in range(0, array_size):
- ul2 = []
- for j in range(0, array_size):
- ul2.append(Signal())
- ul.append(ul2)
+ for i in range(array_size):
+ ul.append(Signal(array_size,
+ reset_less=True,
+ name="addr_match_%d" % i))
self.addr_array_i = Array(ul)
ul = []
- for i in range(0, array_size):
+ for i in range(array_size):
ul.append(DataMergerRecord())
self.data_i = Array(ul)
self.data_o = DataMergerRecord()
+ def elaborate(self, platform):
+ m = Module()
+ comb = m.d.comb
+ #(1) pick a row
+ m.submodules.pick = pick = PriorityEncoder(self.array_size)
+ for j in range(self.array_size):
+ comb += pick.i[j].eq(self.addr_array_i[j].bool())
+ valid = ~pick.n
+ idx = pick.o
+ #(2) merge
+ with m.If(valid):
+ l = []
+ for j in range(self.array_size):
+ select = self.addr_array_i[idx][j]
+ r = DataMergerRecord()
+ with m.If(select):
+ comb += r.eq(self.data_i[j])
+ l.append(r)
+ comb += self.data_o.data.eq(ortreereduce(l,"data"))
+ comb += self.data_o.en.eq(ortreereduce(l,"en"))
+
+ return m
+
class LDSTPort(Elaboratable):
def __init__(self, idx, regwid=64, addrwid=48):
assert data == result, "data %x != %x" % (result, data)
assert data2 == result2, "data2 %x != %x" % (result2, data2)
+def data_merger_merge(dut):
+ print("TODO")
+ yield
def test_l0_cache():
run_simulation(dut, l0_cache_ldst(dut),
vcd_name='test_l0_cache_basic.vcd')
+def test_data_merger():
+
+ dut = DataMerger(8)
+ #vl = rtlil.convert(dut, ports=dut.ports())
+ #with open("test_data_merger.il", "w") as f:
+ # f.write(vl)
+
+ run_simulation(dut, data_merger_merge(dut),
+ vcd_name='test_data_merger.vcd')
+
if __name__ == '__main__':
test_l0_cache()
+ #test_data_merger()