phy/lpddr4: fix edge case error with CommandsPipeline ignoring a command

Command was being ignored when it occurred on the last phase and
the next command would invalidate the first phase. Now it is fixed
and a regression test is included. A fix in ConstBitSlip has been added
due to wrong Verilog being generated with cycles=1, register=False.
This commit is contained in:
Jędrzej Boczar 2021-06-01 12:50:01 +02:00
parent baf9c07858
commit da769094fd
2 changed files with 25 additions and 20 deletions

View File

@ -59,7 +59,11 @@ class ConstBitSlip(Module):
self.sync += r.eq(Cat(r[dw:], self.i)) self.sync += r.eq(Cat(r[dw:], self.i))
else: else:
reg = Signal(cycles*dw, reset_less=True) reg = Signal(cycles*dw, reset_less=True)
self.sync += reg.eq(Cat(reg[dw:], self.i)) # Cat with slice of len=0 generates incorrect Verilog
if len(reg[dw:]) > 0:
self.sync += reg.eq(Cat(reg[dw:], self.i))
else:
self.sync += reg.eq(self.i)
self.comb += r.eq(Cat(reg, self.i)) self.comb += r.eq(Cat(reg, self.i))
self.comb += self.o.eq(r[slp+1:dw+slp+1]) self.comb += self.o.eq(r[slp+1:dw+slp+1])
@ -191,6 +195,7 @@ class CommandsPipeline(Module):
nphases = len(adapters) nphases = len(adapters)
self.cs = Signal(cs_ser_width) self.cs = Signal(cs_ser_width)
self.ca = [Signal(ca_ser_width) for _ in range(ca_nbits)] self.ca = [Signal(ca_ser_width) for _ in range(ca_nbits)]
assert cmd_nphases_span <= nphases
# # # # # #
@ -198,7 +203,7 @@ class CommandsPipeline(Module):
n_previous = cmd_nphases_span - 1 n_previous = cmd_nphases_span - 1
# Create a history of valid adapters used for masking overlapping ones # Create a history of valid adapters used for masking overlapping ones
valids = ConstBitSlip(dw=nphases, slp=0) valids = ConstBitSlip(dw=nphases, slp=0, cycles=1, register=False)
self.submodules += valids self.submodules += valids
self.comb += valids.i.eq(Cat(a.valid for a in adapters)) self.comb += valids.i.eq(Cat(a.valid for a in adapters))
valids_hist = valids.r valids_hist = valids.r
@ -216,23 +221,21 @@ class CommandsPipeline(Module):
allowed = ~reduce(or_, valids_hist[nphases+phase - n_previous:nphases+phase]) allowed = ~reduce(or_, valids_hist[nphases+phase - n_previous:nphases+phase])
# Use CS and CA of given adapter slipped by `phase` bits # Use CS and CA of given adapter slipped by `phase` bits
cs_bs = ConstBitSlip(dw=cs_ser_width, slp=phase) cs_bs = ConstBitSlip(dw=cs_ser_width, slp=phase, cycles=1)
self.submodules += cs_bs self.submodules += cs_bs
self.comb += cs_bs.i.eq(Cat(adapter.cs)), cs_mask = Replicate(allowed, len(cs_bs.i))
cs_mask = Replicate(allowed, len(cs_bs.o)) self.comb += cs_bs.i.eq(Cat(adapter.cs) & cs_mask),
cs = cs_bs.o & cs_mask cs_per_adapter.append(cs_bs.o)
cs_per_adapter.append(cs)
# For CA we need to do the same for each bit # For CA we need to do the same for each bit
ca_bits = [] ca_bits = []
for bit in range(ca_nbits): for bit in range(ca_nbits):
ca_bs = ConstBitSlip(dw=ca_ser_width, slp=phase) ca_bs = ConstBitSlip(dw=ca_ser_width, slp=phase, cycles=1)
self.submodules += ca_bs self.submodules += ca_bs
ca_bit_hist = [adapter.ca[i][bit] for i in range(cmd_nphases_span)] ca_bit_hist = [ca[bit] for ca in adapter.ca]
self.comb += ca_bs.i.eq(Cat(*ca_bit_hist)),
ca_mask = Replicate(allowed, len(ca_bs.o)) ca_mask = Replicate(allowed, len(ca_bs.o))
ca = ca_bs.o & ca_mask self.comb += ca_bs.i.eq(Cat(*ca_bit_hist) & ca_mask),
ca_per_adapter[bit].append(ca) ca_per_adapter[bit].append(ca_bs.o)
# OR all the masked signals # OR all the masked signals
self.comb += self.cs.eq(reduce(or_, cs_per_adapter)) self.comb += self.cs.eq(reduce(or_, cs_per_adapter))

View File

@ -149,19 +149,21 @@ class LPDDR4Tests(unittest.TestCase):
read = dict(cs_n=0, cas_n=0, ras_n=1, we_n=1) read = dict(cs_n=0, cas_n=0, ras_n=1, we_n=1)
self.run_test(LPDDR4SimPHY(sys_clk_freq=self.SYS_CLK_FREQ), self.run_test(LPDDR4SimPHY(sys_clk_freq=self.SYS_CLK_FREQ),
dfi_sequence = [ dfi_sequence = [
{0: read, 3: read}, # p4 should be ignored {0: read, 3: read}, # p3 should be ignored
{0: read, 4: read}, {0: read, 4: read},
{6: read}, {6: read},
{0: read}, # ignored {0: read}, # ignored
{7: read},
{3: read}, # not ignored
], ],
pad_checkers = {"sys8x_90": { pad_checkers = {"sys8x_90": {
'cs': latency + '10100000' + '10101010' + '00000010' + '10000000', 'cs': latency + '10100000' + '10101010' + '00000010' + '10000000' + '00000001' + '01010100',
'ca0': latency + '00000000' + '00000000' + '00000000' + '00000000', 'ca0': latency + '00000000' + '00000000' + '00000000' + '00000000' + '00000000' + '00000000',
'ca1': latency + '10100000' + '10101010' + '00000010' + '10000000', 'ca1': latency + '10100000' + '10101010' + '00000010' + '10000000' + '00000001' + '01010100',
'ca2': latency + '00000000' + '00000000' + '00000000' + '00000000', 'ca2': latency + '00000000' + '00000000' + '00000000' + '00000000' + '00000000' + '00000000',
'ca3': latency + '0x000000' + '0x000x00' + '0000000x' + '00000000', 'ca3': latency + '0x000000' + '0x000x00' + '0000000x' + '00000000' + '00000000' + 'x000x000',
'ca4': latency + '00100000' + '00100010' + '00000000' + '10000000', 'ca4': latency + '00100000' + '00100010' + '00000000' + '10000000' + '00000000' + '01000100',
'ca5': latency + '00000000' + '00000000' + '00000000' + '00000000', 'ca5': latency + '00000000' + '00000000' + '00000000' + '00000000' + '00000000' + '00000000',
}}, }},
) )