Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- module frame_store (
- // Video interface
- input logic comClk,
- input logic [ 19:0] video_data_in,
- input logic video_data_valid,
- // CPU configuration (all false paths)
- input logic reset,
- input logic interlaced,
- input logic top_bottom, // If this is set to 1, use top-bottom, otherwise use field interlaced
- input logic [ 21:0] top_line_interval_1, // 10:0 is the lower limit and 21:11 is the upper limit (10 bit numbers)
- input logic [ 21:0] top_line_interval_2, // Only used when top_bottom and interlaced are both true
- input logic [ 10:0] vsync_line_number, // Which line number directly follows the FRAME vsync
- input logic [ 10:0] lines_per_frame,
- // DDR interface
- input logic clk,
- input logic fifo_rd,
- output logic [ 23:0] addr,
- output logic [159:0] fifo_data_out,
- output logic [ 2:0] wr_req,
- output logic [ 7:0] wr_cnt,
- // Read agent interface
- output logic start_reading
- );
- parameter BANK_SELECT = 2'b10;
- typedef enum logic [1:0] {
- top,
- bottom,
- anc,
- unknown
- } region_t;
- // One-hot state machine indexes
- enum logic [1:0] {
- DEC_3FF_BIT,
- DEC_000_BIT,
- DEC_001_BIT,
- DEC_XYZ_BIT
- } trs_sm_index;
- // One-hot state machine states
- typedef enum logic [3:0] {
- dec_3ff = 4'b1<<DEC_3FF_BIT,
- dec_000 = 4'b1<<DEC_000_BIT,
- dec_001 = 4'b1<<DEC_001_BIT,
- dec_xyz = 4'b1<<DEC_XYZ_BIT
- } trs_sm_t;
- typedef struct packed {
- region_t region;
- logic [5:0] count;
- } fifo_data_t;
- trs_sm_t trs_sm;
- trs_sm_t trs_sm_next;
- logic vsync;
- logic hsync;
- logic field;
- logic vsync_next;
- logic hsync_next;
- logic field_next;
- logic [ 4:0][19:0] video_data_in_delay;
- logic [159:0] fifo_in;
- logic rdempty;
- logic [ 6:0] rdusedw;
- region_t video_region; // current data type from the input video
- fifo_data_t first; // first data type in the fifo
- fifo_data_t middle; // middle data type in the fifo
- fifo_data_t last; // last data type in the fifo
- fifo_data_t first_next;
- fifo_data_t middle_next;
- fifo_data_t last_next;
- logic [ 3:0][19:0] region_address;
- logic [ 3:0][19:0] region_address_next;
- logic [ 3:0][ 8:0] num_columns_left;
- logic [ 3:0][ 8:0] num_columns_left_next;
- logic fifo_wr;
- logic fifo_wr_2x; // This signal is only 1 clk_2x cycle wide
- logic two_fifo_wrs; // This signal is only 1 clk_2x cycle wide
- logic fifo_wr_cnt;
- logic synced_d1; // The data is delayed 5 times now to register the video_region
- logic synced; // goes high after the last sample of a frame is detected
- logic synced_next;
- logic [ 2:0] hsync_extend_count;
- logic active_video;
- logic [10:0] video_line_number;
- logic [10:0] video_line_number_next;
- logic start_reading_next;
- integer i;
- logic [ 6:0] rdusedw_minus_1;
- logic [ 5:0] wr_cnt_next;
- logic [ 5:0] wr_cnt_int;
- logic [ 2:0] active_in_count;
- logic [ 3:0] anc_in_count;
- logic [ 7:0][19:0] fifo_in_active;
- logic [15:0][19:0] fifo_in_anc;
- logic fifo_in_ready;
- logic write_anc_data;
- logic anc_lo_hi_n;
- logic [ 2:0] fifo_state, fifo_state_next;
- assign two_fifo_wrs = fifo_wr_2x & fifo_wr_cnt;
- assign fifo_in_ready = video_region == anc ? video_data_valid & write_anc_data : &active_in_count & video_data_valid;
- assign fifo_wr = fifo_in_ready & synced_d1; // Suppress writes until the frame position is known
- assign fifo_in = video_region == anc ? anc_lo_hi_n ? fifo_in_anc[7:0] : fifo_in_anc[15:8] : {video_data_in_delay[4], fifo_in_active[6:0]};
- assign active_video = !(hsync | |hsync_extend_count) & !vsync;
- assign addr = {BANK_SELECT, first.region, region_address[first.region]};
- assign wr_req = {3{rdusedw[5]}};
- always @* begin
- wr_cnt = 8'd0;
- case (1'b1)
- fifo_state[0]: begin
- if (num_columns_left[first.region] < 8'd31) begin
- wr_cnt = num_columns_left[first.region];
- end
- else begin
- wr_cnt = 8'd31;
- end
- end
- fifo_state[1], fifo_state[2]: begin
- if (num_columns_left[first.region] < first.count) begin
- wr_cnt = num_columns_left[first.region];
- end
- else begin
- wr_cnt = {2'b00, first.count};
- end
- end
- endcase
- end
- // write_anc_data and anc_lo_hi_n control writing 16 ANC samples to the fifo
- // at once. This will prevent any problems that arise from the memory requirement
- // to always write in bursts of 4 by ensuring there are always multiples of 4
- // waiting to be written. The active video doesn't have this problem.
- always @(posedge comClk) begin
- if (reset) begin
- write_anc_data <= 1'b0;
- anc_lo_hi_n <= 1'b0;
- end
- else begin
- if (video_data_valid) begin
- if (video_region == anc) begin
- if (&anc_in_count) begin
- write_anc_data <= 1'b1;
- anc_lo_hi_n <= 1'b1;
- end
- if (anc_lo_hi_n) begin
- anc_lo_hi_n <= 1'b0;
- end
- if (write_anc_data & !anc_lo_hi_n) begin
- write_anc_data <= 1'b0;
- end
- end
- end
- end
- end
- // Decode the input video region
- always @(posedge comClk) begin
- if (video_data_valid) begin
- if (top_bottom) begin // Indicates two line number ranges are needed to determine what region we're in
- if (active_video) begin
- if ((video_line_number >= top_line_interval_1[10:0] && video_line_number <= top_line_interval_1[21:11]) ||
- (video_line_number >= top_line_interval_2[10:0] && video_line_number <= top_line_interval_2[21:11]))
- begin
- video_region <= top;
- end
- else begin
- video_region <= bottom;
- end
- end
- else begin
- video_region <= anc;
- end
- end
- else begin // Only one line number range is used
- if (active_video) begin
- if (video_line_number >= top_line_interval_1[10:0] && video_line_number <= top_line_interval_1[21:11]) begin
- video_region <= top;
- end
- else begin
- video_region <= bottom;
- end
- end
- else begin
- video_region <= anc;
- end
- end
- end
- end
- // Realign the video to the TRS signals
- always @(posedge comClk) begin
- if (video_data_valid) begin
- video_data_in_delay[4] <= video_data_in_delay[3];
- video_data_in_delay[3] <= video_data_in_delay[2];
- video_data_in_delay[2] <= video_data_in_delay[1];
- video_data_in_delay[1] <= video_data_in_delay[0];
- video_data_in_delay[0] <= video_data_in;
- end
- end
- // Store the video and decode the TRS
- always @(posedge comClk) begin
- if (reset) begin
- synced <= 1'b0;
- synced_d1 <= 1'b0;
- anc_in_count <= 4'd0;
- active_in_count <= 3'd0;
- trs_sm <= dec_3ff;
- video_line_number <= 11'h0;
- start_reading <= 1'b0;
- hsync_extend_count <= 3'b0;
- end
- else begin
- if (video_data_valid) begin
- if (synced_d1) begin // Start preparing data to be written into the FIFO (two words at once)
- if (video_region == anc) begin
- anc_in_count <= anc_in_count + 1'b1;
- fifo_in_anc[anc_in_count] <= video_data_in_delay[4];
- end
- else begin
- active_in_count <= active_in_count + 1'b1;
- fifo_in_active[active_in_count] <= video_data_in_delay[4];
- end
- end
- if (!hsync_next & hsync) begin
- hsync_extend_count <= 3'b100;
- end
- else if (|hsync_extend_count) begin
- hsync_extend_count <= hsync_extend_count + 1'b1;
- end
- video_line_number <= video_line_number_next;
- trs_sm <= trs_sm_next;
- vsync <= vsync_next;
- hsync <= hsync_next;
- field <= field_next;
- synced <= synced_next;
- synced_d1 <= synced;
- start_reading <= start_reading_next;
- end
- end
- end
- always @* begin
- trs_sm_next = trs_sm;
- vsync_next = vsync;
- hsync_next = hsync;
- field_next = field;
- synced_next = synced;
- start_reading_next = start_reading;
- case (1'b1)
- trs_sm[DEC_3FF_BIT]: begin
- if (video_data_in[19:10] == 10'h3ff) begin
- trs_sm_next = dec_000;
- end
- end
- trs_sm[DEC_000_BIT]: begin
- if (video_data_in[19:10] == 10'h000) begin
- trs_sm_next = dec_001;
- end
- else begin
- trs_sm_next = dec_3ff;
- end
- end
- trs_sm[DEC_001_BIT]: begin
- if (video_data_in[19:10] == 10'h000) begin
- trs_sm_next = dec_xyz;
- end
- else begin
- trs_sm_next = dec_3ff;
- end
- end
- trs_sm[DEC_XYZ_BIT]: begin
- trs_sm_next = dec_3ff;
- field_next = video_data_in[18];
- vsync_next = video_data_in[17];
- hsync_next = video_data_in[16];
- end
- default: begin
- trs_sm_next = dec_3ff;
- end
- endcase
- if (vsync_next & !vsync & (interlaced & field | !interlaced)) begin
- video_line_number_next = vsync_line_number;
- end
- else if (hsync_next & !hsync) begin // New line starting
- if (video_line_number == lines_per_frame) begin
- video_line_number_next = 11'd1;
- synced_next = 1'b1;
- if (synced) begin
- start_reading_next = 1'b1;
- end
- end
- else begin
- // Don't count after a reset until the line number is determined
- video_line_number_next = video_line_number + (|video_line_number);
- end
- end
- else begin
- video_line_number_next = video_line_number;
- end
- end
- // Keep track of the addresses for the 3 memory regions by dividing the FIFO
- // into 3 sections (there will never be more than 3 different regions in the
- // FIFO at once)
- always @(posedge clk) begin
- if (reset) begin
- fifo_wr_2x <= 1'b0;
- first.region <= unknown;
- middle.region <= unknown;
- last.region <= unknown;
- first.count <= 6'd0;
- middle.count <= 6'd0;
- last.count <= 6'd0;
- fifo_state <= 3'b001;
- fifo_wr_cnt <= 1'b0;
- for (i = 0; i < 4; i++) begin
- region_address[i] <= 20'd0;
- num_columns_left[i] <= 9'd511;
- end
- end
- else begin
- fifo_wr_2x <= fifo_wr_2x ^ fifo_wr; // fifo_wr will be 2 clk cycles long, this changes it so it's only 1
- if (fifo_wr_2x) begin
- fifo_wr_cnt <= !fifo_wr_cnt;
- end
- for (i = 0; i < 4; i++) begin
- region_address[i] <= region_address_next[i];
- num_columns_left[i] <= num_columns_left_next[i];
- end
- first <= first_next;
- middle <= middle_next;
- last <= last_next;
- fifo_state <= fifo_state_next;
- end
- end
- always @* begin
- for (i = 0; i < 4; i++) begin
- region_address_next[i] = region_address[i];
- num_columns_left_next[i] = num_columns_left[i];
- end
- first_next = first;
- middle_next = middle;
- last_next = last;
- // wr_cnt_next = wr_cnt_int;
- fifo_state_next = fifo_state;
- if (fifo_state[0]) begin // In this case, the fifo should only have one data type in it
- case ({fifo_rd, two_fifo_wrs})
- 2'b01: begin
- if (first.region == video_region) begin
- first_next.count = first.count + (!(|first.count) ? 1'b1 : 2'b10);
- middle_next.count = first.count + (!(|first.count) ? 1'b1 : 2'b10);
- last_next.count = first.count + (!(|first.count) ? 1'b1 : 2'b10);
- end
- end
- 2'b10: begin
- first_next.count = first.count - 1'b1;
- middle_next.count = first.count - 1'b1;
- last_next.count = first.count - 1'b1;
- end
- 2'b11: begin
- if (first.region != video_region) begin
- first_next.count = first.count - 1'b1;
- end
- else begin
- first_next.count = first.count + 1'b1;
- middle_next.count = first.count + 1'b1;
- last_next.count = first.count + 1'b1;
- end
- end
- // All other combinations result in the count staying the same
- endcase
- if (fifo_rd) begin
- region_address_next[first.region] = region_address[first.region] + 1'b1;
- num_columns_left_next[first.region] = num_columns_left[first.region] - 1'b1;
- end
- end
- else begin
- if (fifo_rd) begin
- first_next.count = first.count - 1'b1;
- region_address_next[first.region] = region_address[first.region] + 1'b1;
- num_columns_left_next[first.region] = num_columns_left[first.region] - 1'b1;
- end
- if (two_fifo_wrs) begin
- if (middle.region == video_region) begin
- middle_next.count = last.count + (!(|last.count) ? 1'b1 : 2'b10);
- end
- last_next.count = last.count + (!(|last.count) ? 1'b1 : 2'b10);
- end
- end
- // The state of the FIFO can be 4 possible things:
- // rdempty is 1, the FIFO is empty (first == middle == last)
- // One memory region in the FIFO, rdempty is 0 (first == middle == last)
- // Two memory regions in the FIFO (first will be one, middle and last will be the other)
- // Three memory regions in the FIFO (first, middle and last won't be equal)
- case (1'b1)
- fifo_state[0]: begin
- if (fifo_wr_2x) begin
- if (first.region != video_region) begin
- if (rdempty || (fifo_rd & first.count == 6'h0)) begin
- first_next.region = video_region;
- middle_next.region = video_region;
- last_next.region = video_region;
- first_next.count = 6'd0;
- middle_next.count = 6'd0;
- last_next.count = 6'd0;
- end
- else begin
- fifo_state_next = 3'b010;
- middle_next.region = video_region;
- last_next.region = video_region;
- middle_next.count = 8'd0;
- last_next.count = 8'd0;
- end
- end
- end
- end
- fifo_state[1]: begin
- if (fifo_wr_2x) begin
- if (last.region != video_region) begin
- fifo_state_next = 3'b100;
- last_next.region = video_region;
- last_next.count = 8'd0;
- end
- end
- if (fifo_rd && first.count == 6'h0) begin
- if (last.region == last_next.region) begin
- fifo_state_next = 3'b001;
- end
- first_next = middle_next;
- middle_next = last_next; // last could be changing this cycle
- end
- end
- fifo_state[2]: begin
- if (fifo_rd && first.count == 6'h0) begin
- fifo_state_next = 3'b010;
- first_next = middle_next;
- middle_next = last_next;
- end
- end
- endcase
- end
- fifo_64x160_async m_fifo_64x160_async (
- .aclr (reset),
- .data (fifo_in),
- .rdclk (clk),
- .rdreq (fifo_rd),
- .wrclk (comClk),
- .wrreq (fifo_wr),
- .q (fifo_data_out),
- .rdempty (rdempty),
- .rdusedw (rdusedw)
- );
- endmodule
Add Comment
Please, Sign In to add comment