* http://bugs.libre-riscv.org/show_bug.cgi?id=216
"""
-from nmigen import Elaboratable, Module, Signal, Record, Array, Const
+#from soc.experiment.pimem import PortInterface
+
+from nmigen import Elaboratable, Module, Signal, Record, Array, Const, Cat
from nmutil.latch import SRLatch, latchregister
from nmigen.back.pysim import Simulator, Delay
from nmigen.cli import verilog, rtlil
from soc.scoreboard.addr_match import LenExpand
#from nmutil.queue import Queue
+
class LDData(Record):
def __init__(self, dwidth, name=None):
Record.__init__(self, (('err', 1), ('data', dwidth)), name=name)
def ports(self):
return list(self)
+def byteExpand(signal):
+ if(type(signal)==int):
+ ret = 0
+ shf = 0
+ while(signal>0):
+ bit = signal & 1
+ ret |= (0xFF * bit) << shf
+ signal = signal >> 1
+ shf += 8
+ return ret
+ lst = []
+ for i in range(len(signal)):
+ bit = signal[i]
+ for j in range(8): #TODO this can be optimized
+ lst += [bit]
+ return Cat(*lst)
+
class LDSTSplitter(Elaboratable):
- def __init__(self, dwidth, awidth, dlen):
+ def __init__(self, dwidth, awidth, dlen, pi=None):
self.dwidth, self.awidth, self.dlen = dwidth, awidth, dlen
- #cline_wid = 8<<dlen # cache line width: bytes (8) times (2^^dlen)
- cline_wid = dwidth # TODO: make this bytes not bits
+ # cline_wid = 8<<dlen # cache line width: bytes (8) times (2^^dlen)
+ cline_wid = dwidth*8 # convert bytes to bits
+
self.addr_i = Signal(awidth, reset_less=True)
+ # no match in PortInterface
self.len_i = Signal(dlen, reset_less=True)
self.valid_i = Signal(reset_less=True)
self.valid_o = Signal(reset_less=True)
self.is_ld_i = Signal(reset_less=True)
self.is_st_i = Signal(reset_less=True)
- self.ld_data_o = LDData(dwidth, "ld_data_o")
- self.st_data_i = LDData(dwidth, "st_data_i")
+ self.ld_data_o = LDData(dwidth*8, "ld_data_o") #port.ld
+ self.st_data_i = LDData(dwidth*8, "st_data_i") #port.st
+
+ self.exc = Signal(reset_less=True) # pi.exc TODO
+ # TODO : create/connect two outgoing port interfaces
self.sld_valid_o = Signal(2, reset_less=True)
self.sld_valid_i = Signal(2, reset_less=True)
self.sld_data_i = Array((LDData(cline_wid, "ld_data_i1"),
- LDData(cline_wid, "ld_data_i2")))
+ LDData(cline_wid, "ld_data_i2")))
self.sst_valid_o = Signal(2, reset_less=True)
self.sst_valid_i = Signal(2, reset_less=True)
self.sst_data_o = Array((LDData(cline_wid, "st_data_i1"),
- LDData(cline_wid, "st_data_i2")))
+ LDData(cline_wid, "st_data_i2")))
def elaborate(self, platform):
m = Module()
dlen = self.dlen
mlen = 1 << dlen
mzero = Const(0, mlen)
- m.submodules.ld1 = ld1 = LDLatch(self.dwidth, self.awidth-dlen, mlen)
- m.submodules.ld2 = ld2 = LDLatch(self.dwidth, self.awidth-dlen, mlen)
+ m.submodules.ld1 = ld1 = LDLatch(self.dwidth*8, self.awidth-dlen, mlen)
+ m.submodules.ld2 = ld2 = LDLatch(self.dwidth*8, self.awidth-dlen, mlen)
m.submodules.lenexp = lenexp = LenExpand(self.dlen)
+ #comb += self.pi.addr_ok_o.eq(self.addr_i < 65536) #FIXME 64k limit
+ #comb += self.pi.busy_o.eq(busy)
+
+
+ # FIXME bytes not bits
# set up len-expander, len to mask. ld1 gets first bit, ld2 gets rest
comb += lenexp.addr_i.eq(self.addr_i)
comb += lenexp.len_i.eq(self.len_i)
mask1 = Signal(mlen, reset_less=True)
mask2 = Signal(mlen, reset_less=True)
- comb += mask1.eq(lenexp.lexp_o[0:mlen]) # Lo bits of expanded len-mask
- comb += mask2.eq(lenexp.lexp_o[mlen:]) # Hi bits of expanded len-mask
+ comb += mask1.eq(lenexp.lexp_o[0:mlen]) # Lo bits of expanded len-mask
+ comb += mask2.eq(lenexp.lexp_o[mlen:]) # Hi bits of expanded len-mask
# set up new address records: addr1 is "as-is", addr2 is +1
comb += ld1.addr_i.eq(self.addr_i[dlen:])
- comb += ld2.addr_i.eq(self.addr_i[dlen:] + 1) # TODO exception if rolls
+ ld2_value = self.addr_i[dlen:] + 1
+ comb += ld2.addr_i.eq(ld2_value)
+ # exception if rolls
+ with m.If(ld2_value[self.awidth-dlen]):
+ comb += self.exc.eq(1)
# data needs recombining / splitting via shifting.
ashift1 = Signal(self.dlen, reset_less=True)
ashift2 = Signal(self.dlen, reset_less=True)
comb += ashift1.eq(self.addr_i[:self.dlen])
- comb += ashift2.eq((1<<dlen)-ashift1)
+ comb += ashift2.eq((1 << dlen)-ashift1)
+
+ #expand masks
+ mask1 = byteExpand(mask1)
+ mask2 = byteExpand(mask2)
+ mzero = byteExpand(mzero)
with m.If(self.is_ld_i):
# set up connections to LD-split. note: not active if mask is zero
comb += self.valid_o.eq(self.sld_valid_o[0])
with m.Else():
comb += self.valid_o.eq(self.sld_valid_o.all())
+ ## debug output -- output mask2 and mzero
+ ## guess second port is invalid
# all bits valid (including when data error occurs!) decode ld1/ld2
with m.If(self.valid_o):
# note that data from LD1 will be in *cache-line* byte position
# likewise from LD2 but we *know* it is at the start of the line
- comb += self.ld_data_o.data.eq((ld1.ld_o.data >> ashift1) |
- (ld2.ld_o.data << ashift2))
+ comb += self.ld_data_o.data.eq((ld1.ld_o.data >> (ashift1*8)) |
+ (ld2.ld_o.data << (ashift2*8)))
with m.If(self.is_st_i):
+ # set busy flag -- required for unit test
for i, (ld, mask) in enumerate(((ld1, mask1),
(ld2, mask2))):
valid = Signal(name="stvalid_i%d" % i, reset_less=True)
comb += self.sld_valid_o[i].eq(ld.valid_o)
comb += self.sst_data_o[i].data.eq(ld.ld_o.data)
- comb += ld1.ld_i.eq((self.st_data_i << ashift1) & mask1)
- comb += ld2.ld_i.eq((self.st_data_i >> ashift2) & mask2)
+ comb += ld1.ld_i.eq((self.st_data_i << (ashift1*8)) & mask1)
+ comb += ld2.ld_i.eq((self.st_data_i >> (ashift2*8)) & mask2)
# sort out valid: mask2 zero we ignore 2nd LD
with m.If(mask2 == mzero):
def ports(self):
return list(self)
+
def sim(dut):
sim = Simulator(dut)
sim.add_clock(1e-6)
- data = 0b11010011
- dlen = 4 # 4 bits
- addr = 0b1100
+ data = 0x0102030405060708A1A2A3A4A5A6A7A8
+ dlen = 16 # data length in bytes
+ addr = 0b1110
ld_len = 8
- ldm = ((1<<ld_len)-1)
- dlm = ((1<<dlen)-1)
- data = data & ldm # truncate data to be tested, mask to within ld len
- print ("ldm", ldm, bin(data&ldm))
- print ("dlm", dlm, bin(addr&dlm))
+ ldm = ((1 << ld_len)-1)
+ ldme = byteExpand(ldm)
+ dlm = ((1 << dlen)-1)
+ data = data & ldme # truncate data to be tested, mask to within ld len
+ print("ldm", ldm, hex(data & ldme))
+ print("dlm", dlm, bin(addr & dlm))
+
dmask = ldm << (addr & dlm)
- print ("dmask", bin(dmask))
- dmask1 = dmask >> (1<<dlen)
- print ("dmask1", bin(dmask1))
- dmask = dmask & ((1<<(1<<dlen))-1)
- print ("dmask", bin(dmask))
-
- def send_in():
- print ("send_in")
+ print("dmask", bin(dmask))
+ dmask1 = dmask >> (1 << dlen)
+ print("dmask1", bin(dmask1))
+ dmask = dmask & ((1 << (1 << dlen))-1)
+ print("dmask", bin(dmask))
+ dmask1 = byteExpand(dmask1)
+ dmask = byteExpand(dmask)
+
+ def send_ld():
+ print("send_ld")
yield dut.is_ld_i.eq(1)
yield dut.len_i.eq(ld_len)
yield dut.addr_i.eq(addr)
yield dut.valid_i.eq(1)
- print ("waiting")
+ print("waiting")
while True:
valid_o = yield dut.valid_o
if valid_o:
break
yield
+ exc = yield dut.exc
ld_data_o = yield dut.ld_data_o.data
yield dut.is_ld_i.eq(0)
yield
- print (bin(ld_data_o), bin(data))
+ print(exc)
+ assert exc==0
+ print(hex(ld_data_o), hex(data))
assert ld_data_o == data
def lds():
- print ("lds")
+ print("lds")
while True:
valid_i = yield dut.valid_i
if valid_i:
break
yield
- shf = addr & dlm
+ shf = (addr & dlm)*8 #shift bytes not bits
+ print("shf",shf/8.0)
shfdata = (data << shf)
data1 = shfdata & dmask
- print ("ld data1", bin(data), bin(data1), shf, bin(dmask))
+ print("ld data1", hex(data), hex(data1), shf,shf/8.0, hex(dmask))
- data2 = (shfdata >> 16) & dmask1
- print ("ld data2", 1<<dlen, bin(data >> (1<<dlen)), bin(data2))
+ data2 = (shfdata >> 128) & dmask1
+ print("ld data2", 1 << dlen, hex(data >> (1 << dlen)), hex(data2))
yield dut.sld_data_i[0].data.eq(data1)
yield dut.sld_valid_i[0].eq(1)
yield
yield
sim.add_sync_process(lds)
- sim.add_sync_process(send_in)
+ sim.add_sync_process(send_ld)
prefix = "ldst_splitter"
with sim.write_vcd("%s.vcd" % prefix, traces=dut.ports()):