diff --git a/src/gateware/cxp_pipeline.py b/src/gateware/cxp_pipeline.py index b9aebb3..882cd80 100644 --- a/src/gateware/cxp_pipeline.py +++ b/src/gateware/cxp_pipeline.py @@ -1,296 +1,292 @@ from migen import * from misoc.interconnect.csr import * from misoc.interconnect import stream -from misoc.cores.liteeth_mini.mac.crc import LiteEthMACCRCEngine, LiteEthMACCRCChecker +char_width = 8 +char_layout = [("data", char_width), ("k", char_width//8)] -import struct - -upconn_dw = 8 -upconn_layout = [("data", upconn_dw), ("k", upconn_dw//8)] - -downconn_dw = 32 -downconn_layout = [("data", downconn_dw), ("k", downconn_dw//8)] - +word_dw = 32 +word_layout = [("data", word_dw), ("k", word_dw//8)] +buffer_depth = 128 def K(x, y): return ((y << 5) | x) KCode = { - "pak_start" : K(27, 7), - "io_ack" : K(28, 6), - "trig_indic_28_2" : K(28, 2), - "trig_indic_28_4" : K(28, 4), - "pak_end" : K(29, 7), + "pak_start" : C(K(27, 7), char_width), + "io_ack" : C(K(28, 6), char_width), + "trig_indic_28_2" : C(K(28, 2), char_width), + "trig_indic_28_4" : C(K(28, 4), char_width), + "pak_end" : C(K(29, 7), char_width), + "idle_comma" : C(K(28, 5), char_width), + "idle_alignment" : C(K(28, 1), char_width), } - -def _bytes2word(bytes, big_endian=True): - if big_endian: - return struct.unpack(">I", struct.pack(">4B", *bytes))[0] - else: - return struct.unpack("4B", *bytes))[0] - -class Code_Source(Module): - def __init__(self, layout, data, k): - - self.source = stream.Endpoint(layout) - self.stb = Signal() +class Packet_Wrapper(Module): + def __init__(self): + self.sink = stream.Endpoint(word_layout) + self.source = stream.Endpoint(word_layout) # # # - assert len(data) == len(k) > 0 - counts = len(data) - - cnt = Signal() if counts == 1 else Signal(max=counts) - clr_cnt = Signal() - inc_cnt = Signal() - - self.sync += [ - If(clr_cnt, - cnt.eq(cnt.reset), - ).Elif(inc_cnt, - cnt.eq(cnt + 1), - ) - ] self.submodules.fsm = fsm = FSM(reset_state="IDLE") - fsm.act("IDLE", - clr_cnt.eq(1), - If(self.stb, - NextState("WRITE") - ) - ) - - fsm.act("WRITE", - self.source.stb.eq(1), - self.source.data.eq(Array(data)[cnt]), - self.source.k.eq(Array(k)[cnt]), - If(cnt == counts - 1, - self.source.eop.eq(1), - If(self.source.ack, NextState("IDLE")) - ).Else( - inc_cnt.eq(self.source.ack) - ) - ) - - -class Code_Inserter(Module): - def __init__(self, layout, data, k, insert_infront=True): - self.sink = stream.Endpoint(layout) - self.source = stream.Endpoint(layout) - - self.data = Signal.like(self.sink.data) - self.k = Signal.like(self.sink.k) - - # # # - assert len(data) == len(k) > 0 - counts = len(data) - - cnt = Signal() if counts == 1 else Signal(max=counts) - clr_cnt = Signal() - inc_cnt = Signal() - - self.sync += [ - If(clr_cnt, - cnt.eq(cnt.reset), - ).Elif(inc_cnt, - cnt.eq(cnt + 1), - ) - ] - - self.submodules.fsm = fsm = FSM(reset_state="IDLE") - remove_sink_oep = 0 if insert_infront else 1 - - # add code in front: IDLE -> INSERT -> COPY - # add code at end: IDLE -> COPY -> INSERT fsm.act("IDLE", self.sink.ack.eq(1), - clr_cnt.eq(1), If(self.sink.stb, self.sink.ack.eq(0), - NextState("INSERT" if insert_infront else "COPY"), + NextState("INSERT_HEADER"), ) ) - fsm.act("INSERT", + fsm.act("INSERT_HEADER", self.sink.ack.eq(0), self.source.stb.eq(1), - self.source.data.eq(Array(data)[cnt]), - self.source.k.eq(Array(k)[cnt]), - If(cnt == counts - 1, - If(remove_sink_oep, self.source.eop.eq(1)), - If(self.source.ack, NextState("COPY" if insert_infront else "IDLE")) - ).Else( - inc_cnt.eq(self.source.ack) - ) + self.source.data.eq(Replicate(KCode["pak_start"], 4)), + self.source.k.eq(0b1111), + If(self.source.ack, NextState("COPY")), ) fsm.act("COPY", self.sink.connect(self.source), - If(remove_sink_oep, self.source.eop.eq(0)), + self.source.eop.eq(0), If(self.sink.stb & self.sink.eop & self.source.ack, - NextState("IDLE" if insert_infront else "INSERT"), - ) + NextState("INSERT_FOOTER"), + ), ) - -class Packet_Wrapper(Module): - def __init__(self, layout): - self.submodules.pak_start = pak_start = Code_Inserter(layout, [KCode["pak_start"]]*4, [1]*4) - self.submodules.pak_end = pak_end = Code_Inserter(layout, [KCode["pak_end"]]*4, [1]*4, insert_infront=False) - - self.comb += pak_start.source.connect(pak_end.sink), - self.sink = pak_start.sink - self.source = pak_end.source + fsm.act("INSERT_FOOTER", + self.sink.ack.eq(0), + self.source.stb.eq(1), + self.source.data.eq(Replicate(KCode["pak_end"], 4)), + self.source.k.eq(0b1111), + self.source.eop.eq(1), + If(self.source.ack, NextState("IDLE")), + ) -@ResetInserter() -@CEInserter() -class CXPCRC32(Module): - # Section 9.2.2.2 (CXP-001-2021) - width = 32 - polynom = 0x04C11DB7 - seed = 2**width-1 - check = 0x00000000 - def __init__(self, data_width): - self.data = Signal(data_width) - self.value = Signal(self.width) - self.error = Signal() - - # # # - - self.submodules.engine = LiteEthMACCRCEngine(data_width, self.width, self.polynom) - reg = Signal(self.width, reset=self.seed) - self.sync += reg.eq(self.engine.next) - self.comb += [ - self.engine.data.eq(self.data), - self.engine.last.eq(reg), - - self.value.eq(reg[::-1]), - self.error.eq(self.engine.next != self.check) - ] - -class CXPCRC32Checker(LiteEthMACCRCChecker): - def __init__(self, layout): - LiteEthMACCRCChecker.__init__(self, CXPCRC32, layout) - -class TX_Trigger(Module, AutoCSR): +class TX_Trigger(Module): def __init__(self): - self.trig_stb = Signal() - self.delay = Signal(upconn_dw) + self.stb = Signal() + self.delay = Signal(char_width) self.linktrig_mode = Signal(max=4) # # # + self.sink = stream.Endpoint(char_layout) + self.source = stream.Endpoint(char_layout) + # Table 15 & 16 (CXP-001-2021) # Send [K28.2, K28.4, K28.4] or [K28.4, K28.2, K28.2] and 3x delay as trigger packet - self.submodules.code_src = code_src = Code_Source(upconn_layout, [self.delay]*3, [0]*3) - self.comb += code_src.stb.eq(self.trig_stb), - - header = [Signal(8) for _ in range(3)] - self.comb += \ + trig_packet = [Signal(char_width), Signal(char_width), Signal(char_width), self.delay, self.delay, self.delay] + trig_packet_k = [1, 1, 1, 0, 0, 0] + self.comb += [ If((self.linktrig_mode == 0) | (self.linktrig_mode == 2), - header[0].eq(KCode["trig_indic_28_2"]), - header[1].eq(KCode["trig_indic_28_4"]), - header[2].eq(KCode["trig_indic_28_4"]), + trig_packet[0].eq(KCode["trig_indic_28_2"]), + trig_packet[1].eq(KCode["trig_indic_28_4"]), + trig_packet[2].eq(KCode["trig_indic_28_4"]), ).Else( - header[0].eq(KCode["trig_indic_28_4"]), - header[1].eq(KCode["trig_indic_28_2"]), - header[2].eq(KCode["trig_indic_28_2"]), - ) + trig_packet[0].eq(KCode["trig_indic_28_4"]), + trig_packet[1].eq(KCode["trig_indic_28_2"]), + trig_packet[2].eq(KCode["trig_indic_28_2"]), + ), + ] - self.submodules.inserter = inserter = Code_Inserter(upconn_layout, header, [1]*3) + self.submodules.fsm = fsm = FSM(reset_state="COPY") + + cnt = Signal(max=6) + fsm.act("COPY", + NextValue(cnt, cnt.reset), + self.sink.connect(self.source), + If(self.stb, NextState("WRITE_TRIG")) + ) - self.comb += code_src.source.connect(inserter.sink) - self.source = inserter.source + fsm.act("WRITE_TRIG", + self.sink.ack.eq(0), + self.source.stb.eq(1), + self.source.data.eq(Array(trig_packet)[cnt]), + self.source.k.eq(Array(trig_packet_k)[cnt]), + If(self.source.ack, + If(cnt == 5, + NextState("COPY"), + ).Else( + NextValue(cnt, cnt + 1), + ) + ) + ) -class Trigger_ACK(Module): +class Idle_Word_Inserter(Module): def __init__(self): - self.ack = Signal() + self.stb = Signal() + + # # # + + # Section 9.2.5 (CXP-001-2021) + # Send K28.5, K28.1, K28.1, D21.5 as idle word + self.submodules.fsm = fsm = FSM(reset_state="COPY") + + self.sink = stream.Endpoint(word_layout) + self.source = stream.Endpoint(word_layout) + fsm.act("COPY", + self.sink.connect(self.source), + If(self.stb, NextState("WRITE_IDLE")) + ) + + fsm.act("WRITE_IDLE", + self.sink.ack.eq(0), + self.source.stb.eq(1), + self.source.data.eq(Cat(KCode["idle_comma"], KCode["idle_alignment"], KCode["idle_alignment"], C(0xB5, char_width))), + self.source.k.eq(0b1110), + If(self.source.ack, NextState("COPY")), + ) + + +class Trigger_ACK_Inserter(Module): + def __init__(self): + self.stb = Signal() # # # # Section 9.3.2 (CXP-001-2021) # Send 4x K28.6 and 4x 0x01 as trigger packet ack - self.submodules.code_src = code_src = Code_Source(upconn_layout, [0x01]*4, [0]*4) - self.submodules.inserter = inserter = Code_Inserter(upconn_layout, [KCode["io_ack"]]*4, [1]*4) - self.comb += [ - code_src.stb.eq(self.ack), - code_src.source.connect(inserter.sink) - ] + self.submodules.fsm = fsm = FSM(reset_state="COPY") + + self.sink = stream.Endpoint(word_layout) + self.source = stream.Endpoint(word_layout) + fsm.act("COPY", + self.sink.connect(self.source), + If(self.stb, NextState("WRITE_ACK0")) + ) - self.source = inserter.source + fsm.act("WRITE_ACK0", + self.sink.ack.eq(0), + self.source.stb.eq(1), + self.source.data.eq(Replicate(KCode["io_ack"], 4)), + self.source.k.eq(0b1111), + If(self.source.ack, NextState("WRITE_ACK1")), + ) + fsm.act("WRITE_ACK1", + self.sink.ack.eq(0), + self.source.stb.eq(1), + self.source.data.eq(Replicate(C(0x01, char_width), 4)), + self.source.k.eq(0b0000), + If(self.source.ack, NextState("COPY")), + ) + + +@FullMemoryWE() class TX_Command_Packet(Module, AutoCSR): - # Section 12.1.2 (CXP-001-2021) - # Max control packet size is 128 bytes - def __init__(self, fifo_depth=128): - self.len = CSRStorage(log2_int(fifo_depth)) - self.data = CSR(upconn_dw) - self.writeable = CSRStatus() + def __init__(self): + self.tx_word_len = CSRStorage(bits_for(buffer_depth)) + self.tx = CSR() # # # + + self.specials.mem = mem = Memory(word_dw, buffer_depth) + self.specials.mem_port = mem_port = mem.get_port() + self.source = stream.Endpoint(word_layout) - self.submodules.fifo = fifo = stream.SyncFIFO(upconn_layout, fifo_depth) - self.submodules.pak_wrp = pak_wrp = Packet_Wrapper(upconn_layout) - self.source = pak_wrp.source - self.comb += fifo.source.connect(pak_wrp.sink) + tx_done = Signal() + addr_next = Signal(bits_for(buffer_depth)) + addr = Signal.like(addr_next) + addr_rst = Signal() + addr_inc = Signal() - cnt = Signal(log2_int(fifo_depth), reset=1) + # increment addr in the same cycle the moment addr_inc is high + # as memory takes one cycle to shift to the correct addr self.sync += [ - self.writeable.status.eq(fifo.sink.ack), - If(fifo.sink.ack, fifo.sink.stb.eq(0)), - If(self.data.re, - fifo.sink.stb.eq(1), - fifo.sink.data.eq(self.data.r), - - fifo.sink.k.eq(0), - If(cnt == self.len.storage, - fifo.sink.eop.eq(1), - cnt.eq(cnt.reset), - ).Else( - fifo.sink.eop.eq(0), - cnt.eq(cnt + 1), - ), - ) + addr.eq(addr_next), + If(self.tx.re, self.tx.w.eq(1)), + If(tx_done, self.tx.w.eq(0)), ] + self.comb += [ + addr_next.eq(addr), + If(addr_rst, + addr_next.eq(addr_next.reset), + ).Elif(addr_inc, + addr_next.eq(addr + 1), + ), + mem_port.adr.eq(addr_next), + self.source.data.eq(mem_port.dat_r) + ] + + self.submodules.fsm = fsm = FSM(reset_state="IDLE") + + fsm.act("IDLE", + addr_rst.eq(1), + If(self.tx.re, NextState("TRANSMIT")) + ) + fsm.act("TRANSMIT", + self.source.stb.eq(1), + If(self.source.ack, + addr_inc.eq(1), + ), + If(addr_next == self.tx_word_len.storage, + self.source.eop.eq(1), + tx_done.eq(1), + NextState("IDLE") + ) + ) + class TX_Test_Packet(Module, AutoCSR): def __init__(self): - - self.stb = CSR() - self.busy = CSRStatus() + self.tx = CSR() # # # - - self.submodules.test_pattern_src = test_pattern_src = Code_Source(upconn_layout, [*range(0x100)]*16, [0]*0x100*16) - self.submodules.pak_type_inserter = pak_type_inserter = Code_Inserter(upconn_layout, [0x04]*4, [0]*4) - self.submodules.pak_wrp = pak_wrp = Packet_Wrapper(upconn_layout) - self.comb += [ - test_pattern_src.source.connect(pak_type_inserter.sink), - pak_type_inserter.source.connect(pak_wrp.sink), - ] - - self.source = pak_wrp.source + + tx_done = Signal() self.sync += [ - test_pattern_src.stb.eq(self.stb.re), - If(self.stb.re, - self.busy.status.eq(1), - ).Elif(self.source.eop & self.source.ack, - self.busy.status.eq(0) - ) + If(self.tx.re, self.tx.w.eq(1)), + If(tx_done, self.tx.w.eq(0)), ] + self.source = stream.Endpoint(word_layout) + self.submodules.fsm = fsm = FSM(reset_state="IDLE") + + cnt = Signal(0xFFF) + fsm.act("IDLE", + NextValue(cnt, cnt.reset), + If(self.tx.re, + NextState("WRITE_PACKET_TYPE") + ) + ) + + fsm.act("WRITE_PACKET_TYPE", + self.source.stb.eq(1), + self.source.data.eq(Replicate(C(0x04, char_width), 4)), + self.source.k.eq(0b0000), + If(self.source.ack,NextState("WRITE_TEST_COUNTER")) + ) + + fsm.act("WRITE_TEST_COUNTER", + self.source.stb.eq(1), + self.source.data.eq(Cat(cnt[:8], cnt[:8]+1, cnt[:8]+2, cnt[:8]+3)), + self.source.k.eq(0b0000), + If(self.source.ack, + If(cnt == 0xFFF-3, + tx_done.eq(1), + self.source.eop.eq(1), + NextState("IDLE") + ).Else( + NextValue(cnt, cnt + 4), + ) + + ) + ) + + + class RX_Debug_Buffer(Module,AutoCSR): def __init__(self): - self.submodules.buf_out = buf_out = stream.SyncFIFO(downconn_layout, 128) + self.submodules.buf_out = buf_out = stream.SyncFIFO(word_layout, 128) self.sink = buf_out.sink self.inc = CSR() - self.dout_pak = CSRStatus(downconn_dw) - self.kout_pak = CSRStatus(downconn_dw//8) + self.dout_pak = CSRStatus(word_dw) + self.kout_pak = CSRStatus(word_dw//8) self.dout_valid = CSRStatus() self.sync += [ @@ -301,79 +297,27 @@ class RX_Debug_Buffer(Module,AutoCSR): self.dout_valid.status.eq(buf_out.source.stb), ] -class Receiver_Path(Module, AutoCSR): - def __init__(self): - self.trig_ack = Signal() - self.trig_clr = Signal() - - self.packet_type = Signal(8) - self.decoder_err = Signal() - self.decoder_err_clr = Signal() - - self.test_err = Signal() - self.test_err_clr = Signal() - - # # # - - - self.submodules.trig_ack_checker = trig_ack_checker = CXP_Trig_Ack_Checker() - self.submodules.packet_decoder = packet_decoder = CXP_Data_Packet_Decode() - - # Error are latched - self.sync += [ - If(trig_ack_checker.ack, - self.trig_ack.eq(1), - ).Elif(self.trig_clr, - self.trig_ack.eq(0), - ), - - If(packet_decoder.decode_err, - self.decoder_err.eq(1), - ).Elif(self.decoder_err_clr, - self.decoder_err.eq(0), - ), - - If(packet_decoder.test_err, - self.test_err.eq(1), - ).Elif(self.test_err_clr, - self.test_err.eq(0), - ) - ] - self.comb += [ - self.packet_type.eq(packet_decoder.packet_type), - - ] - - pipeline = [ trig_ack_checker, packet_decoder ] - - for s, d in zip(pipeline, pipeline[1:]): - self.comb += s.source.connect(d.sink) - - self.sink = pipeline[0].sink - self.source = pipeline[-1].source - - - +@FullMemoryWE() class CXP_Data_Packet_Decode(Module): def __init__(self): - self.sink = stream.Endpoint(downconn_layout) + self.sink = stream.Endpoint(word_layout) # This is where data stream comes out - self.source = stream.Endpoint(downconn_layout) + self.source = stream.Endpoint(word_layout) - self.packet_type = Signal(8) - self.decode_err = Signal() + self.packet_type_rx = Signal(8) + self.decode_err_rx = Signal() - self.buffer = Signal(40*downconn_dw) - self.test_err = Signal() + self.test_err_rx = Signal() # # # - # decoder -> priorities mux(normal packet vs trigger ack) -> data packet mux (control ack, data stream, heartbeat, testmode, (optional Genlcam event)) + # TODO: data&event -> memory + # TODO: heartbeat type = { "data_stream": 0x01, "control_ack_no_tag": 0x03, "test_packet": 0x04, "control_ack_with_tag": 0x06, - "event_ack": 0x08, + "event": 0x07, "heartbeat": 0x09, "debug" : 0x02, @@ -384,7 +328,7 @@ class CXP_Data_Packet_Decode(Module): fsm.act("IDLE", self.sink.ack.eq(1), # TODO: add error correction? - If((self.sink.stb & (self.sink.data == _bytes2word([KCode["pak_start"]]*4)) & (self.sink.k == 0b1111)), + If((self.sink.stb & (self.sink.data == Replicate(KCode["pak_start"], 4)) & (self.sink.k == 0b1111)), NextState("DECODE"), ) ) @@ -396,17 +340,21 @@ class CXP_Data_Packet_Decode(Module): fsm.act("DECODE", self.sink.ack.eq(1), If(self.sink.stb, - NextValue(self.packet_type, self.sink.data[:8]), + NextValue(self.packet_type_rx, self.sink.data[:8]), Case(self.sink.data[:8],{ type["data_stream"]: NextState("STREAMING"), - type["debug"]: NextState("STREAMING"), + type["control_ack_no_tag"]: NextState("LOAD_BUFFER"), type["test_packet"]: [ - NextValue(cnt, 0), + NextValue(cnt, cnt.reset), NextState("VERIFY_TEST_PATTERN"), ], + type["control_ack_with_tag"]: NextState("LOAD_BUFFER"), + type["event"]: NextState("LOAD_BUFFER"), + + type["debug"]: NextState("LOAD_BUFFER"), "default": [ - self.decode_err.eq(1), + self.decode_err_rx.eq(1), # wait till next valid packet NextState("IDLE"), ], @@ -420,11 +368,11 @@ class CXP_Data_Packet_Decode(Module): fsm.act("VERIFY_TEST_PATTERN", self.sink.ack.eq(1), If(self.sink.stb, - If(((self.sink.data == _bytes2word([KCode["pak_end"]]*4)) & (self.sink.k == 0b1111)), + If(((self.sink.data == Replicate(KCode["pak_end"], 4)) & (self.sink.k == 0b1111)), NextState("IDLE"), ).Else( If(((self.sink.data != Cat(cnt, cnt+1, cnt+2, cnt+3))), - self.test_err.eq(1), + self.test_err_rx.eq(1), ), If(cnt == 0xFC, NextValue(cnt, cnt.reset), @@ -436,8 +384,9 @@ class CXP_Data_Packet_Decode(Module): ) + # For stream data packet fsm.act("STREAMING", - If((self.sink.stb & (self.sink.data == _bytes2word([KCode["pak_end"]]*4)) & (self.sink.k == 0b1111)), + If((self.sink.stb & (self.sink.data == Replicate(KCode["pak_end"], 4)) & (self.sink.k == 0b1111)), # discard K29,7 self.sink.ack.eq(1), NextState("IDLE") @@ -445,49 +394,50 @@ class CXP_Data_Packet_Decode(Module): self.sink.connect(self.source), ) ) - # # input pipeline stage - determine packet length based on type - # self.sync += [ - # packet_start.eq((self.sink.data[0] == K(27, 7)) & (self.sink.k[0] == 1)), - # packet_end.eq((self.sink.data[0] == K(29, 7)) & (self.sink.k[0] == 1)), - # If((self.sink.data[0] == K(27, 7)) & (self.sink.k[0] == 1), - # packet_buffer_load.eq(1), - # ), + # TODO: add overflow error + # TODO: reclock this to cxp_gtx_rx + self.specials.mem = mem = Memory(word_dw, buffer_depth) + self.specials.mem_port = mem_port = mem.get_port(write_capable=True, clock_domain="sys") + # write pointer represents where the gateware is + write_ptr_rx = Signal(bits_for(buffer_depth)) + # read pointer represents where CPU is + # write reaching read is an error, read reaching write is buffer clear + self.read_ptr_rx = Signal.like(write_ptr_rx) + self.new_packet_rx = Signal() - # trig_ack.eq((self.sink.data[0] == K(28, 6)) & (self.sink.k[0] == 1)), - # If(trig_ack, - # self.trig_ack.eq(self.sink.data[0]), - # trig_ack.eq(0), - # ).Elif(packet_buffer_load, - # # TODO: add test packet counting - # Case(buffer_count, - # {i: buffer[i*downconn_dw:(i+1)*downconn_dw].eq(self.sink.data) - # for i in range(40)}), - # buffer_count.eq(buffer_count + 1), + self.comb += mem_port.adr.eq(write_ptr_rx), + self.sync += self.new_packet_rx.eq(self.read_ptr_rx != write_ptr_rx) + # For control ack, event packet + fsm.act("LOAD_BUFFER", + mem_port.we.eq(0), + self.sink.ack.eq(1), + If(self.sink.stb, + If(((self.sink.data == Replicate(KCode["pak_end"], 4)) & (self.sink.k == 0b1111)), + NextState("IDLE"), + ).Else( + mem_port.we.eq(1), + mem_port.dat_w.eq(self.sink.data), + NextValue(write_ptr_rx, write_ptr_rx + 1), + ) + ) + ) class CXP_Trig_Ack_Checker(Module, AutoCSR): def __init__(self): - self.sink = stream.Endpoint(downconn_layout) - self.source = stream.Endpoint(downconn_layout) + self.sink = stream.Endpoint(word_layout) + self.source = stream.Endpoint(word_layout) self.ack = Signal() # # # - self.submodules.fsm = fsm = FSM(reset_state="IDLE") - - fsm.act("IDLE", - self.sink.ack.eq(1), - If(self.sink.stb, - self.sink.ack.eq(0), - NextState("COPY"), - ) - ) + self.submodules.fsm = fsm = FSM(reset_state="COPY") fsm.act("COPY", - If((self.sink.stb & (self.sink.data == _bytes2word([KCode["io_ack"]]*4)) & (self.sink.k == 0b1111)), + If((self.sink.stb & (self.sink.data == Replicate(KCode["io_ack"], 4)) & (self.sink.k == 0b1111)), # discard K28,6 self.sink.ack.eq(1), NextState("CHECK_ACK") @@ -498,10 +448,10 @@ class CXP_Trig_Ack_Checker(Module, AutoCSR): fsm.act("CHECK_ACK", If(self.sink.stb, - NextState("IDLE"), + NextState("COPY"), # discard the word after K28,6 self.sink.ack.eq(1), - If(self.sink.data == _bytes2word([0x01]*4), + If(self.sink.data == Replicate(C(0x01, char_width), 4), self.ack.eq(1), ) )