LibreSatCam/FPGA_Firmware/Source/src/output_reformatter.v

186 lines
5.8 KiB
Verilog

`timescale 1ns/1ns
/*
MIPI CSI RX to Parallel Bridge (c) by Gaurav Singh www.CircuitValley.com
MIPI CSI RX to Parallel Bridge is licensed under a
Creative Commons Attribution 3.0 Unported License.
You should have received a copy of the license along with this
work. If not, see <http://creativecommons.org/licenses/by/3.0/>.
*/
/*
Takes 32bit 2pixe to 128bit 8pixel yuv input from rgb2yuv module @ mipi byte clock outputs 32bit 2pixel yuv output @output_clk_i ,
output_clk_i can be totoally independnt phease and frequency of mipi_byte_clock, but frequnecy be fast enough to have full line transmitted before next line comes.
This implementation of Output reformatter outputs data which which meant to send out of the system to a 32bit receiver
depending on requirement this will be need to be adapted as per the receiver
*/
module output_reformatter #(parameter PIXEL_PER_CLK=8 )(
clk_i, //data changes on negedge
output_clk_i, //output clock
data_i,
data_in_valid_i, //expected active high
line_sync_i, //expected active high
frame_sync_i, //expected active low
output_o,
output_valid_o //active high
);
input line_sync_i;
input frame_sync_i;
input clk_i;
input data_in_valid_i;
input [((PIXEL_PER_CLK * 8 * 2) - 1 ):0]data_i;
output reg output_valid_o;
output [31:0]output_o;
input output_clk_i;
reg [10:0] write_address;
reg [11:0] read_address;
wire [31:0]ram_even_o;
wire [31:0]ram_odd_o;
reg [10:0] input_pixel_count_clk_i; //under clk_i domain
reg [10:0] input_pixel_count_meta1;
reg [10:0] input_pixel_count_meta2;
reg [10:0] input_pixel_count_meta3;
reg [10:0] input_pixel_count_out_clk;
reg line_even_nodd_clk_i; //select between two different RAM
reg line_even_nodd_meta1;
reg line_even_nodd_meta2;
reg line_even_nodd_meta3;
reg line_even_nodd_out_clk;
reg last_line_sync; //helps to determine edge of line sync for write address reset
reg last_line_even_nodd; //helps to determine edge of line sync for read address reset
//ebr ram_dp write address and data is latched on same rising edge of write clock
//read address is latached on rising edge of read clock and data outputed on same rising edge but after tCO_EBR so should be sampled on comming fallsing or next rising edge
out_line_ram_dp line_odd( .wr_clk_i(!clk_i),
.rd_clk_i(output_clk_i),
.rst_i(frame_sync_i),
.wr_clk_en_i(data_in_valid_i),
.rd_en_i(line_even_nodd_clk_i),
.rd_clk_en_i(1'b1),
.wr_en_i(!line_even_nodd_clk_i),
.wr_data_i(data_i),
.wr_addr_i(write_address),
.rd_addr_i(read_address),
.rd_data_o(ram_odd_o));
out_line_ram_dp line_even( .wr_clk_i(!clk_i),
.rd_clk_i(output_clk_i),
.rst_i(frame_sync_i),
.wr_clk_en_i(data_in_valid_i),
.rd_en_i(!line_even_nodd_clk_i),
.rd_clk_en_i(1'b1),
.wr_en_i(line_even_nodd_clk_i),
.wr_data_i(data_i),
.wr_addr_i(write_address),
.rd_addr_i(read_address),
.rd_data_o(ram_even_o));
/*
out_line_ram_ldp line_odd( .clk_i((line_even_nodd)?!clk_i:output_clk_i),
.dps_i(1'b1),
.rst_i(!frame_sync_i),
.wr_clk_en_i(data_in_valid_i),
.rd_clk_en_i(!line_even_nodd),
.wr_en_i(line_even_nodd),
.wr_data_i(data_i),
.wr_addr_i(write_address),
.rd_addr_i(read_address),
.rd_data_o(ram_even_o),
.lramready_o(),
.rd_datavalid_o());
out_line_ram_ldp line_even( .clk_i((!line_even_nodd)?!clk_i:output_clk_i),
.dps_i(1'b1),
.rst_i(!frame_sync_i),
.wr_clk_en_i(data_in_valid_i),
.rd_clk_en_i(line_even_nodd),
.wr_en_i(!line_even_nodd),
.wr_data_i(data_i),
.wr_addr_i(write_address),
.rd_addr_i(read_address),
.rd_data_o(ram_odd_o),
.lramready_o(),
.rd_datavalid_o()) ;
*/
//assign output_o = line_even_nodd? ram_odd_o[((read_address[0])?6'd32:6'd0) +:32]: ram_even_o[((read_address[0])?6'd32:6'd0) +:32]; //depeding on line select even or odd ram , also select correct 32bit word from 64 bit ramoutput
assign output_o = line_even_nodd_clk_i? ram_odd_o:ram_even_o; //depeding on line select even or odd ram
always @(posedge clk_i )
begin
if (frame_sync_i)
begin
line_even_nodd_clk_i <= 0;
last_line_sync <= 0;
input_pixel_count_clk_i <= 0;
write_address <= 0;
end
else
begin
last_line_sync <= line_sync_i;
if (!last_line_sync && line_sync_i)
begin
write_address <= 9'b0;
input_pixel_count_clk_i <= write_address << (PIXEL_PER_CLK >> 2) ; //x4 or x2 or also x1 write_address as each write_address has 128 bit or 64 bit or 32 bit while output width is 32bit
line_even_nodd_clk_i <= !line_even_nodd_clk_i;
end
else
begin
write_address <= write_address + data_in_valid_i;
end
end
end
always @(negedge output_clk_i)
begin
line_even_nodd_meta1 <= line_even_nodd_clk_i;
line_even_nodd_meta2 <= line_even_nodd_meta1;
line_even_nodd_meta3 <= line_even_nodd_meta2;
line_even_nodd_out_clk <= line_even_nodd_meta3;
input_pixel_count_meta1 <= input_pixel_count_clk_i;
input_pixel_count_meta2 <= input_pixel_count_meta1;
input_pixel_count_meta3 <= input_pixel_count_meta2;
input_pixel_count_out_clk <= input_pixel_count_meta3;
last_line_even_nodd <= line_even_nodd_out_clk;
if (last_line_even_nodd != line_even_nodd_out_clk) //reset read address for each new line
begin
read_address <= 12'b0;
output_valid_o <= 1'b0;
end
else
begin
if (read_address < input_pixel_count_out_clk)
begin
read_address <= read_address + 1'b1;
output_valid_o <= 1'b1;
end
else
begin
output_valid_o <= 1'b0;
end
end
end
endmodule