forked from M-Labs/artiq-zynq
cxp upconn: add word & char boundary transmission
This commit is contained in:
parent
4eed5e99f4
commit
481162430c
|
@ -7,10 +7,12 @@ from misoc.interconnect import stream
|
||||||
from misoc.interconnect.csr import *
|
from misoc.interconnect.csr import *
|
||||||
|
|
||||||
# CXP 2.1 section 9.2.5
|
# CXP 2.1 section 9.2.5
|
||||||
IDLE_WORDS = [
|
IDLE_CHARS = [
|
||||||
#[data, k]
|
#[data, k]
|
||||||
[0b10111100, 1], #K28.5
|
[0b10111100, 1], #K28.5
|
||||||
[0b10111100, 1], #K28.5
|
[0b10111100, 1], #K28.5
|
||||||
|
[0b10111100, 1], #K28.5
|
||||||
|
[0b10111100, 1], #K28.5
|
||||||
# [0b00111100, 1], #K28.1
|
# [0b00111100, 1], #K28.1
|
||||||
# [0b00111100, 1], #K28.1
|
# [0b00111100, 1], #K28.1
|
||||||
# [0b10111100, 0], #D28.5
|
# [0b10111100, 0], #D28.5
|
||||||
|
@ -66,21 +68,30 @@ class CXP_UpConn(Module, AutoCSR):
|
||||||
o = Signal()
|
o = Signal()
|
||||||
tx_en = Signal()
|
tx_en = Signal()
|
||||||
tx_bitcount = Signal(max=10)
|
tx_bitcount = Signal(max=10)
|
||||||
|
tx_wordcount = Signal()
|
||||||
tx_reg = Signal(10)
|
tx_reg = Signal(10)
|
||||||
wordidx = Signal(max=len(IDLE_WORDS))
|
|
||||||
|
disp = Signal()
|
||||||
|
tx_wordcount = Signal(max=4)
|
||||||
|
priority = Signal(max=nfifos)
|
||||||
|
idling = Signal()
|
||||||
|
|
||||||
# startup sequence
|
# startup sequence
|
||||||
self.fsm.act("WAIT_TX_ENABLE",
|
self.fsm.act("WAIT_TX_ENABLE",
|
||||||
If(self.tx_enable.storage,
|
If(self.tx_enable.storage,
|
||||||
NextState("ENCODE_IDLE_WORD")
|
NextValue(self.encoder.d, IDLE_CHARS[0][0]),
|
||||||
|
NextValue(self.encoder.k, IDLE_CHARS[0][1]),
|
||||||
|
NextValue(self.encoder.disp_in, 0),
|
||||||
|
NextValue(tx_wordcount, 0),
|
||||||
|
NextValue(tx_bitcount, 0),
|
||||||
|
NextState("LOAD_CHAR")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
self.fsm.act("ENCODE_IDLE_WORD",
|
self.fsm.act("LOAD_CHAR",
|
||||||
NextValue(self.encoder.d, IDLE_WORDS[0][0]),
|
NextValue(idling, 1),
|
||||||
NextValue(self.encoder.k, IDLE_WORDS[0][1]),
|
NextValue(tx_reg, self.encoder.output),
|
||||||
NextValue(self.encoder.disp_in, 0),
|
NextValue(disp, self.encoder.disp_out),
|
||||||
NextValue(wordidx, 1),
|
|
||||||
NextState("START_TX")
|
NextState("START_TX")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -91,74 +102,78 @@ class CXP_UpConn(Module, AutoCSR):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# 0 lv interrupt at char boundary 10bit
|
|
||||||
# other lv interrupt at word boundary 40bit
|
|
||||||
|
|
||||||
cur_disp = Signal()
|
|
||||||
|
|
||||||
# TODO: only allow trigger packet to do character interrupt and other priority level to only interrupt word
|
|
||||||
# ISSUE: what if 2lv is transmitting 2nd char & 1lv interrupt its?
|
|
||||||
# CXP 2.1 section 9.2.4
|
# CXP 2.1 section 9.2.4
|
||||||
self.sync.cxp_upconn += [
|
self.sync.cxp_upconn += [
|
||||||
self.tx_fifos.disp_in.eq(cur_disp),
|
self.tx_fifos.disp_in.eq(disp),
|
||||||
self.encoder.disp_in.eq(cur_disp),
|
self.encoder.disp_in.eq(disp),
|
||||||
|
self.encoder.d.eq(Array(IDLE_CHARS)[tx_wordcount][0]),
|
||||||
|
self.encoder.k.eq(Array(IDLE_CHARS)[tx_wordcount][1]),
|
||||||
If(tx_en,
|
If(tx_en,
|
||||||
o.eq(tx_reg[0]),
|
o.eq(tx_reg[0]),
|
||||||
tx_reg.eq(Cat(tx_reg[1:], 0)),
|
tx_reg.eq(Cat(tx_reg[1:], 0)),
|
||||||
tx_bitcount.eq(tx_bitcount + 1),
|
tx_bitcount.eq(tx_bitcount + 1),
|
||||||
|
|
||||||
If(tx_bitcount == 8,
|
# char boundary
|
||||||
If(self.tx_fifos.pe.n,
|
If(tx_bitcount == 9,
|
||||||
self.encoder.d.eq(Array(IDLE_WORDS)[wordidx][0]),
|
|
||||||
self.encoder.k.eq(Array(IDLE_WORDS)[wordidx][1]),
|
|
||||||
If(wordidx != len(IDLE_WORDS),
|
|
||||||
wordidx.eq(wordidx + 1),
|
|
||||||
).Else(
|
|
||||||
wordidx.eq(0),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
).Elif(tx_bitcount == 9,
|
|
||||||
tx_bitcount.eq(0),
|
tx_bitcount.eq(0),
|
||||||
If(self.tx_fifos.pe.n,
|
If((~self.tx_fifos.pe.n) & (self.tx_fifos.pe.o == 0),
|
||||||
# idle word
|
# trigger packet can interrupt at char level
|
||||||
tx_reg.eq(self.encoder.output),
|
tx_reg.eq(self.tx_fifos.source_data[0]),
|
||||||
cur_disp.eq(self.encoder.disp_out),
|
self.tx_fifos.source_ack[0].eq(1),
|
||||||
|
disp.eq(self.tx_fifos.disp_out[0]),
|
||||||
).Else(
|
).Else(
|
||||||
# from fifos
|
# at word boundary
|
||||||
tx_reg.eq(self.tx_fifos.source_data[self.tx_fifos.pe.o]),
|
If(tx_wordcount == 3,
|
||||||
self.tx_fifos.source_ack[self.tx_fifos.pe.o].eq(1),
|
tx_wordcount.eq(0),
|
||||||
cur_disp.eq(self.tx_fifos.disp_out[self.tx_fifos.pe.o]),
|
# at word boundary
|
||||||
),
|
If(~self.tx_fifos.pe.n,
|
||||||
)
|
idling.eq(0),
|
||||||
|
priority.eq(self.tx_fifos.pe.o),
|
||||||
|
self.tx_fifos.source_ack[self.tx_fifos.pe.o].eq(1),
|
||||||
|
tx_reg.eq(self.tx_fifos.source_data[self.tx_fifos.pe.o]),
|
||||||
|
disp.eq(self.tx_fifos.disp_out[self.tx_fifos.pe.o]),
|
||||||
|
).Else(
|
||||||
|
idling.eq(1),
|
||||||
|
tx_reg.eq(self.encoder.output),
|
||||||
|
disp.eq(self.encoder.disp_out),
|
||||||
|
)
|
||||||
|
).Else(
|
||||||
|
# priority zero doesn't contribute to word count
|
||||||
|
tx_wordcount.eq(tx_wordcount + 1),
|
||||||
|
If(~idling,
|
||||||
|
self.tx_fifos.source_ack[priority].eq(1),
|
||||||
|
tx_reg.eq(self.tx_fifos.source_data[priority]),
|
||||||
|
disp.eq(self.tx_fifos.disp_out[priority]),
|
||||||
|
).Else(
|
||||||
|
tx_reg.eq(self.encoder.output),
|
||||||
|
disp.eq(self.encoder.disp_out),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
).Else(
|
).Else(
|
||||||
o.eq(0)
|
o.eq(0)
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
# DEBUG: remove pads
|
# DEBUG: remove pads
|
||||||
|
assert len(IDLE_CHARS) == 4 #word length must be 4 chars
|
||||||
self.encoded_data = CSRStatus(10)
|
self.encoded_data = CSRStatus(10)
|
||||||
self.sync.cxp_upconn +=[
|
self.sync.cxp_upconn +=[
|
||||||
If(tx_bitcount == 9,
|
If(tx_bitcount == 0,
|
||||||
If(self.tx_fifos.pe.n,
|
self.encoded_data.status.eq(tx_reg),
|
||||||
# idle word
|
|
||||||
self.encoded_data.status.eq(self.encoder.output),
|
|
||||||
).Else(
|
|
||||||
# from fifos
|
|
||||||
self.encoded_data.status.eq(self.tx_fifos.source_data[self.tx_fifos.pe.o]),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
ninth_bit = Signal()
|
ninth_bit = Signal()
|
||||||
eighth_bit = Signal()
|
word_bound = Signal()
|
||||||
|
|
||||||
idle_3 = Signal()
|
p1 = Signal()
|
||||||
idle_2 = Signal()
|
p2 = Signal()
|
||||||
self.comb += [
|
self.comb += [
|
||||||
eighth_bit.eq(tx_bitcount == 8),
|
|
||||||
ninth_bit.eq(tx_bitcount == 9),
|
ninth_bit.eq(tx_bitcount == 9),
|
||||||
idle_3.eq(wordidx == 3),
|
word_bound.eq(tx_wordcount == 3),
|
||||||
idle_2.eq(wordidx == 2),
|
p1.eq(priority == 1),
|
||||||
|
p2.eq(priority == 2),
|
||||||
]
|
]
|
||||||
self.specials += [
|
self.specials += [
|
||||||
# debug sma
|
# debug sma
|
||||||
|
@ -170,24 +185,29 @@ class CXP_UpConn(Module, AutoCSR):
|
||||||
Instance("OBUF", i_I=self.cd_cxp_upconn.clk, o_O=pmod[1]),
|
Instance("OBUF", i_I=self.cd_cxp_upconn.clk, o_O=pmod[1]),
|
||||||
Instance("OBUF", i_I=~self.tx_fifos.pe.n, o_O=pmod[2]),
|
Instance("OBUF", i_I=~self.tx_fifos.pe.n, o_O=pmod[2]),
|
||||||
Instance("OBUF", i_I=ninth_bit, o_O=pmod[3]),
|
Instance("OBUF", i_I=ninth_bit, o_O=pmod[3]),
|
||||||
Instance("OBUF", i_I=idle_2, o_O=pmod[4]),
|
Instance("OBUF", i_I=word_bound, o_O=pmod[4]),
|
||||||
Instance("OBUF", i_I=self.tx_fifos.source_ack[0], o_O=pmod[5]),
|
Instance("OBUF", i_I=idling, o_O=pmod[5]),
|
||||||
Instance("OBUF", i_I=idle_3, o_O=pmod[6]),
|
# Instance("OBUF", i_I=self.tx_fifos.source_ack[0], o_O=pmod[6]),
|
||||||
Instance("OBUF", i_I=tx_en, o_O=pmod[7]),
|
# Instance("OBUF", i_I=self.tx_fifos.source_ack[2], o_O=pmod[6]),
|
||||||
|
# Instance("OBUF", i_I=self.tx_fifos.source_ack[1], o_O=pmod[7]),
|
||||||
|
Instance("OBUF", i_I=p1, o_O=pmod[6]),
|
||||||
|
Instance("OBUF", i_I=p2, o_O=pmod[7]),
|
||||||
]
|
]
|
||||||
self.symbol0 = CSR(9)
|
self.symbol0 = CSR(9)
|
||||||
self.symbol1 = CSR(9)
|
self.symbol1 = CSR(9)
|
||||||
|
self.symbol2 = CSR(9)
|
||||||
|
|
||||||
self.sync += [
|
self.sync += [
|
||||||
self.tx_fifos.sink_stb[0].eq(self.symbol0.re),
|
self.tx_fifos.sink_stb[0].eq(self.symbol0.re),
|
||||||
self.tx_fifos.sink_data[0].eq(self.symbol0.r),
|
self.tx_fifos.sink_data[0].eq(self.symbol0.r),
|
||||||
self.tx_fifos.sink_stb[1].eq(self.symbol1.re),
|
self.tx_fifos.sink_stb[1].eq(self.symbol1.re),
|
||||||
self.tx_fifos.sink_data[1].eq(self.symbol1.r),
|
self.tx_fifos.sink_data[1].eq(self.symbol1.r),
|
||||||
|
self.tx_fifos.sink_stb[2].eq(self.symbol2.re),
|
||||||
|
self.tx_fifos.sink_data[2].eq(self.symbol2.r),
|
||||||
]
|
]
|
||||||
|
|
||||||
class TxFIFOs(Module, AutoCSR):
|
class TxFIFOs(Module, AutoCSR):
|
||||||
def __init__(self, nfifos, fifo_depth):
|
def __init__(self, nfifos, fifo_depth):
|
||||||
|
|
||||||
self.disp_in = Signal()
|
self.disp_in = Signal()
|
||||||
self.disp_out = Array(Signal() for _ in range(nfifos))
|
self.disp_out = Array(Signal() for _ in range(nfifos))
|
||||||
|
|
||||||
|
@ -208,23 +228,23 @@ class TxFIFOs(Module, AutoCSR):
|
||||||
encoder = ClockDomainsRenamer("cxp_upconn")(SingleEncoder(True))
|
encoder = ClockDomainsRenamer("cxp_upconn")(SingleEncoder(True))
|
||||||
setattr(self.submodules, "tx_fifo" + str(i), fifo)
|
setattr(self.submodules, "tx_fifo" + str(i), fifo)
|
||||||
setattr(self.submodules, "tx_encoder" + str(i), encoder)
|
setattr(self.submodules, "tx_encoder" + str(i), encoder)
|
||||||
self.comb += [
|
self.sync += [
|
||||||
fifo.sink.stb.eq(self.sink_stb[i]),
|
fifo.sink.stb.eq(self.sink_stb[i]),
|
||||||
self.sink_ack[i].eq(fifo.sink.ack),
|
self.sink_ack[i].eq(fifo.sink.ack),
|
||||||
fifo.sink.data.eq(self.sink_data[i]),
|
fifo.sink.data.eq(self.sink_data[i]),
|
||||||
|
]
|
||||||
self.source_stb[i].eq(fifo.source.stb),
|
self.sync.cxp_upconn += [
|
||||||
fifo.source.ack.eq(self.source_ack[i]),
|
|
||||||
|
|
||||||
encoder.d.eq(fifo.source.data[:8]),
|
encoder.d.eq(fifo.source.data[:8]),
|
||||||
encoder.k.eq(fifo.source.data[8]),
|
encoder.k.eq(fifo.source.data[8]),
|
||||||
encoder.disp_in.eq(self.disp_in),
|
encoder.disp_in.eq(self.disp_in),
|
||||||
self.disp_out[i].eq(encoder.disp_out),
|
self.disp_out[i].eq(encoder.disp_out),
|
||||||
self.source_data[i].eq(encoder.output),
|
|
||||||
]
|
|
||||||
# reset ack after asserted
|
|
||||||
self.sync.cxp_upconn += If(self.source_ack[i], self.source_ack[i].eq(0))
|
|
||||||
|
|
||||||
|
self.source_stb[i].eq(fifo.source.stb),
|
||||||
|
fifo.source.ack.eq(self.source_ack[i]),
|
||||||
|
self.source_data[i].eq(encoder.output),
|
||||||
|
# reset ack after asserted
|
||||||
|
If(self.source_ack[i], self.source_ack[i].eq(0)),
|
||||||
|
]
|
||||||
# For FIFOs transmission priority
|
# For FIFOs transmission priority
|
||||||
self.submodules.pe = PriorityEncoder(nfifos)
|
self.submodules.pe = PriorityEncoder(nfifos)
|
||||||
self.comb += self.pe.i.eq(self.source_stb)
|
self.comb += self.pe.i.eq(self.source_stb)
|
||||||
|
|
Loading…
Reference in New Issue