// Takes data in from JPEG, sends out over USB
// Two clock domains: 
//      JPEG (image pixel clock)
//      USB (PHYCLK = 60MHz)

// Interfaces with Gowin USB Device controller
// Implemented as a single FIFO with clock crossing

// JPEG data is written to FIFO whenever it's ready
// When JPEG image is done (JPEG_DONE goes high), the number
// of bytes left to be sent is captured and sent to the 
// USB side. This allows USB to send a packet with less
// than the maximum number of bytes. And allows the USB
// sender to know the correct packet size to set before
// the packet is sent!

// All other times, the USB sender will only send packets
// that are equal to the maximum size.

module isoc_video_buffer #(
    parameter MAX_PKT_SZ = 1024,
    parameter COUNT_BITS = 18, // how big a frame can be = 2^COUNT_BITS-1 (18 -> 262143)
    parameter FIFO_SIZE = 13 // almost same as above, max fifo count = 2^(FIFO_SIZE-1) (13 -> 4096)
) 
(
    input           ARESET,

    // JPEG compressor interface
    input           JPEG_CLK, // writing side clock
    input           JPEG_DE,  // data enable = write enable
    input           JPEG_DONE, // done = last byte of image
    input [7:0]     JPEG_DATA,
    input           STREAM_ENABLE, // set to 1 when camera stream is requested by PC

    // USB Device controller interface
    input           USB_CLK, // reading side clock
    input           TXACT, // transmission active, holds high for the duration of a packet
    input           TXPOP, // tells us to prepare the next byte
    input           USB_SOF, // flag when start-of-frame token received
    // input           PKTFIN, // end of this tx packet (not well documented, so unused)
    output [7:0]    TXDAT, // data to write over USB
    output          TXCORK, // for isochronous must never NAK. Instead reply with zero length packet
    // output [3:0]    TXISOPID, // when in high speed, high bandwidth mode make sure to select correct PID
    output [11:0]   TXDAT_LEN // how many bytes are we writing?
);

// tx <--> rx interface
wire frame_done; // trigger from rx to tx submodules
wire frame_done_ack; // reply from tx to rx
wire [COUNT_BITS-1:0] frame_count; // number of bytes in the frame (total)

// fifo write interface
wire fifo_wren;
wire fifo_full;
wire [7:0] fifo_wr_data;

// fifo read interface
wire fifo_rden;
wire fifo_empty;
wire [FIFO_SIZE-1:0] fifo_rd_count;
wire [7:0] fifo_rd_data;

isoc_video_buffer_rx #(
    .COUNT_BITS(COUNT_BITS)
)
u_vid_buf_rx
(
    .ARESET(ARESET),
    .PXL_CLK(JPEG_CLK),
    .PXL_DATA(JPEG_DATA),
    .PXL_DE(JPEG_DE),
    .PXL_DONE(JPEG_DONE),
    .STREAM_ENABLE(STREAM_ENABLE),
    .FIFO_DATA(fifo_wr_data),
    .FIFO_WREN(fifo_wren),
    .FIFO_FULL(fifo_full),
    .FRAME_DONE(frame_done),
    .FRAME_DONE_ACK(frame_done_ack),
    .FRAME_COUNT(frame_count)
);

isoc_video_buffer_tx #(
    .COUNT_BITS(COUNT_BITS),
    .FIFO_NUM_BITS(FIFO_SIZE),
    .MAX_PAYLOAD_SIZE(MAX_PKT_SZ),
    .MAX_PACKET_SIZE(MAX_PKT_SZ)
)
u_vid_buf_tx
(
    .ARESET(ARESET || (~STREAM_ENABLE)),
    .USB_CLK(USB_CLK),
    .USB_TXACT(TXACT),
    .USB_TXPOP(TXPOP),
    .USB_SOF(USB_SOF),
    .USB_TXDAT(TXDAT),
    .USB_TXDAT_LEN(TXDAT_LEN),
    .FIFO_RDEN(fifo_rden),
    .FIFO_DATA(fifo_rd_data),
    .FIFO_RNUM(fifo_rd_count),
    .FIFO_EMPTY(fifo_empty),
    .FRAME_DONE(frame_done),
    .FRAME_DONE_ACK(frame_done_ack),
    .FRAME_COUNT(frame_count)
);

vid_buf_fifo u_fifo(
    .WrReset(ARESET || (~STREAM_ENABLE)), //input WrReset
    .WrClk(JPEG_CLK), //input WrClk
    .WrEn(fifo_wren), //input WrEn
    .Data(fifo_wr_data), //input [7:0] Data
    .Full(fifo_full), //output Full

    .RdReset(ARESET || (~STREAM_ENABLE)), //input RdReset
    .RdClk(USB_CLK), //input RdClk
    .RdEn(fifo_rden), //input RdEn
    .Q(fifo_rd_data), //output [7:0] Q
    .Rnum(fifo_rd_count), //output [12:0] Rnum
    .Empty(fifo_empty) //output Empty
);

assign TXCORK = 1'b0;   // As this is an isochronous endpoint, we cannot NAK.
                        // Only provide zero length packets when we have no data.

endmodule
