diff --git a/sim_generator.py b/sim_generator.py new file mode 100644 index 0000000..ebf4016 --- /dev/null +++ b/sim_generator.py @@ -0,0 +1,120 @@ +from migen import * +from misoc.interconnect.csr import * +from misoc.interconnect import stream + +from sim_pipeline import CXPCRC32 +from src.gateware.cxp_pipeline import * + +class CXPCRC32Inserter(Module): + def __init__(self): + self.sink = stream.Endpoint(word_layout) + self.source = stream.Endpoint(word_layout) + + # # # + + self.submodules.crc = crc = CXPCRC32(word_dw) + self.submodules.fsm = fsm = FSM(reset_state="IDLE") + + fsm.act( + "IDLE", + crc.reset.eq(1), + self.sink.ack.eq(1), + If( + self.sink.stb, + self.sink.ack.eq(0), + NextState("COPY"), + ), + ) + fsm.act( + "COPY", + crc.ce.eq(self.sink.stb & self.source.ack), + crc.data.eq(self.sink.data), + self.sink.connect(self.source), + self.source.eop.eq(0), + If( + self.sink.stb & self.sink.eop & self.source.ack, + NextState("INSERT"), + ), + ) + fsm.act( + "INSERT", + self.source.stb.eq(1), + self.source.eop.eq(1), + self.source.data.eq(crc.value), + If(self.source.ack, NextState("IDLE")), + ) + + +class StreamPacket_Wrapper(Module): + def __init__(self): + self.sink = stream.Endpoint(word_layout) + self.source = stream.Endpoint(word_layout) + + # # # + + 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("INSERT_HEADER_0"), + ), + ) + + fsm.act( + "INSERT_HEADER_0", + self.sink.ack.eq(0), + self.source.stb.eq(1), + self.source.data.eq(Replicate(KCode["pak_start"], 4)), + self.source.k.eq(Replicate(1, 4)), + If(self.source.ack, NextState("INSERT_HEADER_1")), + ) + + fsm.act( + "INSERT_HEADER_1", + self.sink.ack.eq(0), + self.source.stb.eq(1), + self.source.data.eq(Replicate(C(0x01, char_width), 4)), + self.source.k.eq(Replicate(0, 4)), + If(self.source.ack, NextState("COPY")), + ) + + fsm.act( + "COPY", + self.sink.connect(self.source), + self.source.eop.eq(0), + If( + self.sink.stb & self.sink.eop & self.source.ack, + NextState("INSERT_FOOTER"), + ), + ) + + 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(Replicate(1, 4)), + # Simulate RX don't have eop tagged + # self.source.eop.eq(1), + If(self.source.ack, NextState("IDLE")), + ) + + +# With KCode & 0x01*4 +class StreamData_Generator(Module): + def __init__(self): + # should be big enough for all test + self.submodules.buffer = buffer = stream.SyncFIFO(word_layout, 32) + self.submodules.crc_inserter = crc_inserter = CXPCRC32Inserter() + self.submodules.wrapper = wrapper = StreamPacket_Wrapper() + + # # # + pipeline = [buffer, crc_inserter, wrapper] + 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 diff --git a/sim_pipeline.py b/sim_pipeline.py index bfff912..513fa49 100644 --- a/sim_pipeline.py +++ b/sim_pipeline.py @@ -24,110 +24,6 @@ class EOP_Marker(Module): self.sink.ack.eq(~self.source.stb | self.source.ack), self.source.eop.eq(~self.sink.stb & last_stb), ] - -class Stream_MetaData_Extractor(Module): - def __init__(self): - self.sink = stream.Endpoint(word_layout_dchar) - self.source = stream.Endpoint(word_layout_dchar) - - # # # - - # GOAL: - # 0) accept four sinks?? - # 1) decode SPH, SPT - # 2) decode Image header, line break - # 3) verify the crc before phrasing image data downstream - - # HOW?? - # combine streams? - # phrase linedata to sys CD - # check stream data tag - # only need to support mono16 for now - - self.stream_id = Signal(char_width) - self.pak_tag = Signal(char_width) - self.stream_pak_size = Signal(char_width * 2) - - self.submodules.fsm = fsm = FSM(reset_state="WAIT_HEADER") - - fsm.act( - "WAIT_HEADER", - NextValue(self.stream_id, self.stream_id.reset), - NextValue(self.pak_tag, self.pak_tag.reset), - NextValue(self.stream_pak_size, self.stream_pak_size.reset), - self.sink.ack.eq(1), - If( - self.sink.stb, - NextValue(self.stream_id, self.sink.dchar), - NextState("GET_PAK_TAG"), - ), - ) - - fsm.act( - "GET_PAK_TAG", - If( - self.sink.stb, - self.sink.ack.eq(1), - NextValue(self.pak_tag, self.sink.dchar), - NextState("GET_PAK_SIZE_0"), - ), - ) - - fsm.act( - "GET_PAK_SIZE_0", - self.sink.ack.eq(1), - If( - self.sink.stb, - NextValue(self.stream_pak_size[8:], self.sink.dchar), - NextState("GET_PAK_SIZE_1"), - ), - ) - - fsm.act( - "GET_PAK_SIZE_1", - self.sink.ack.eq(1), - If( - self.sink.stb, - NextValue(self.stream_pak_size[:8], self.sink.dchar), - NextState("STORE_BUFFER"), - ), - ) - - fsm.act( - "STORE_BUFFER", - self.sink.connect(self.source), - # both serve the same function but using the pak size I can remove eop injecter and save 1 cycle - If(self.sink.stb, - NextValue(self.stream_pak_size, self.stream_pak_size - 1), - If(self.stream_pak_size == 1, - NextState("WAIT_HEADER"), - ) - ), - # If((self.sink.stb & self.sink.eop), - # NextState("WAIT_HEADER"), - # ) - ) - -class Frame_Decoder(Module): - def __init__(self): - self.sink = stream.Endpoint(word_layout_dchar) - self.source = stream.Endpoint(word_layout_dchar) - - # # # - - # TODO: decode Image header, line break - -class Pixel_Decoder(Module): - def __init__(self, pixel_format="mono16"): - assert pixel_format == "mono16" - - self.sink = stream.Endpoint(word_layout_dchar) - self.source = stream.Endpoint(word_layout_dchar) - - # # # - - # TODO: support mono16 for now? - class Streams_Crossbar(Module): def __init__(self, downconns, streams_buffer): n_downconn = len(downconns) @@ -205,113 +101,10 @@ class CXPCRC32(Module): self.error.eq(reg != self.check), ] -class CXPCRC32Inserter(Module): - def __init__(self): - self.sink = stream.Endpoint(word_layout) - self.source = stream.Endpoint(word_layout) - - # # # - - self.submodules.crc = crc = CXPCRC32(word_dw) - self.submodules.fsm = fsm = FSM(reset_state="IDLE") - - fsm.act("IDLE", - crc.reset.eq(1), - self.sink.ack.eq(1), - If(self.sink.stb, - self.sink.ack.eq(0), - NextState("COPY"), - ) - ) - fsm.act("COPY", - crc.ce.eq(self.sink.stb & self.source.ack), - crc.data.eq(self.sink.data), - self.sink.connect(self.source), - self.source.eop.eq(0), - If(self.sink.stb & self.sink.eop & self.source.ack, - NextState("INSERT"), - ) - ) - fsm.act("INSERT", - self.source.stb.eq(1), - self.source.eop.eq(1), - self.source.data.eq(crc.value), - If(self.source.ack, NextState("IDLE")) - ) - -class StreamPacket_Wrapper(Module): - def __init__(self): - self.sink = stream.Endpoint(word_layout) - self.source = stream.Endpoint(word_layout) - - # # # - - 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("INSERT_HEADER_0"), - ) - ) - - fsm.act("INSERT_HEADER_0", - self.sink.ack.eq(0), - self.source.stb.eq(1), - self.source.data.eq(Replicate(KCode["pak_start"], 4)), - self.source.k.eq(Replicate(1, 4)), - If(self.source.ack, NextState("INSERT_HEADER_1")), - ) - - fsm.act("INSERT_HEADER_1", - self.sink.ack.eq(0), - self.source.stb.eq(1), - self.source.data.eq(Replicate(C(0x01, char_width), 4)), - self.source.k.eq(Replicate(0, 4)), - If(self.source.ack, NextState("COPY")), - ) - - fsm.act("COPY", - self.sink.connect(self.source), - self.source.eop.eq(0), - If(self.sink.stb & self.sink.eop & self.source.ack, - NextState("INSERT_FOOTER"), - ), - ) - - 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(Replicate(1, 4)), - # Simulate RX don't have eop tagged - # self.source.eop.eq(1), - If(self.source.ack, NextState("IDLE")), - ) - -# With KCode & 0x01*4 -class StreamData_Generator(Module): - def __init__(self): - # should be big enough for all test - self.submodules.buffer = buffer = stream.SyncFIFO(word_layout, 32) - self.submodules.crc_inserter = crc_inserter = CXPCRC32Inserter() - self.submodules.wrapper = wrapper = StreamPacket_Wrapper() - - # # # - pipeline = [buffer, crc_inserter, wrapper] - 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 - # For verifying crc in stream data packet class Double_Stream_Buffer(Module): # default size is 2 kBtyes - Section 9.5.2 (CXP-001-2021) def __init__(self, size=16000): - # detect and tag end of packet for crc - # self.submodules.eop_marker = eop_marker = EOP_Marker() - # self.sink = eop_marker.sink self.sink = stream.Endpoint(word_layout_dchar) self.submodules.crc = crc = CXPCRC32(word_dw) @@ -393,3 +186,93 @@ class Double_Stream_Buffer(Module): # last_eop = Signal() # self.comb += self.source.eop.eq(~last_eop & self.sink.eop) + + +class Stream_Parser(Module): + def __init__(self): + self.sink = stream.Endpoint(word_layout_dchar) + self.source = stream.Endpoint(word_layout_dchar) + + # # # + + self.stream_id = Signal(char_width) + self.pak_tag = Signal(char_width) + self.stream_pak_size = Signal(char_width * 2) + + self.submodules.fsm = fsm = FSM(reset_state="WAIT_HEADER") + + fsm.act( + "WAIT_HEADER", + NextValue(self.stream_id, self.stream_id.reset), + NextValue(self.pak_tag, self.pak_tag.reset), + NextValue(self.stream_pak_size, self.stream_pak_size.reset), + self.sink.ack.eq(1), + If( + self.sink.stb, + NextValue(self.stream_id, self.sink.dchar), + NextState("GET_PAK_TAG"), + ), + ) + + fsm.act( + "GET_PAK_TAG", + If( + self.sink.stb, + self.sink.ack.eq(1), + NextValue(self.pak_tag, self.sink.dchar), + NextState("GET_PAK_SIZE_0"), + ), + ) + + fsm.act( + "GET_PAK_SIZE_0", + self.sink.ack.eq(1), + If( + self.sink.stb, + NextValue(self.stream_pak_size[8:], self.sink.dchar), + NextState("GET_PAK_SIZE_1"), + ), + ) + + fsm.act( + "GET_PAK_SIZE_1", + self.sink.ack.eq(1), + If( + self.sink.stb, + NextValue(self.stream_pak_size[:8], self.sink.dchar), + NextState("STORE_BUFFER"), + ), + ) + + fsm.act( + "STORE_BUFFER", + self.sink.connect(self.source), + # both serve the same function but using the pak size I can remove eop injecter and save 1 cycle + If(self.sink.stb, + NextValue(self.stream_pak_size, self.stream_pak_size - 1), + If(self.stream_pak_size == 1, + NextState("WAIT_HEADER"), + ) + ), + ) + +class Frame_Decoder(Module): + def __init__(self): + self.sink = stream.Endpoint(word_layout_dchar) + self.source = stream.Endpoint(word_layout_dchar) + + # # # + + # TODO: decode Image header, line break + +class Pixel_Decoder(Module): + def __init__(self, pixel_format="mono16"): + assert pixel_format == "mono16" + + self.sink = stream.Endpoint(word_layout_dchar) + self.source = stream.Endpoint(word_layout_dchar) + + # # # + + # TODO: support mono16 for now? + diff --git a/sim_stream.py b/sim_stream.py index 8b11508..3360320 100644 --- a/sim_stream.py +++ b/sim_stream.py @@ -1,6 +1,8 @@ from migen import * from misoc.interconnect import stream + from sim_pipeline import * +from sim_generator import StreamData_Generator from src.gateware.cxp_pipeline import *