Files
retroSoC/rtl/ip/ribp/multimedia/dvp.sv
T
maksyuki 3cf9e4c6a6 feat: add DVP (Digital Video Processor) support and related formal verification
- Modified dma_core to accommodate a wider data width for FIFO operations.
- Updated filelists to include new DVP source files and formal verification files.
- Introduced formal verification modules for DVP functionality.
- Enhanced clock and reset domain configurations for DVP integration.
- Added DVP interrupt handling in the IRQ topology.
- Implemented a testbench for DVP to validate register access and frame processing.
- Updated software build scripts to include DVP-related source files.
- Adjusted the system topology to reflect the new DVP interrupt and IRQ mapping.
2026-08-13 08:36:38 +08:00

300 lines
9.6 KiB
Systemverilog

// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
`include "dvp_define.svh"
/* verilator lint_off DECLFILENAME */
interface dvp_if ();
logic pclk_i;
logic href_i;
logic vsync_i;
logic [7:0] dat_i;
modport dut(input pclk_i, input href_i, input vsync_i, input dat_i);
endinterface
/* verilator lint_on DECLFILENAME */
module ribp_dvp (
// verilog_format: off
input logic clk_i,
input logic rst_n_i,
ribp_if.slave ribp,
axi4_stream_if.source rx_axis,
dvp_if.dut dvp,
output logic irq_o
// verilog_format: on
);
localparam int DVP_PAYLOAD_WIDTH = 42;
logic [ 127:0] s_config_sys;
logic s_cfg_v_sys;
logic s_cfg_rdy_sys;
logic [ 127:0] s_cfg_pclk_q;
logic s_cfg_v_pclk;
logic s_cfg_rdy_pclk;
logic [ 1:0] s_cmd_sys;
logic [ 1:0] s_cmd_pclk;
logic s_cmd_v_pclk;
logic s_cmd_rdy_pclk;
logic s_cmd_rdy_sys;
logic s_cmd_v_sys;
logic [ 1:0] s_cmd_core;
logic s_cmd_abort_sys;
logic s_cmd_flush_sys;
logic s_pclk_inv;
logic s_pclk_buf;
logic s_pclk_rst_n;
logic s_pclk_sel;
logic s_pclk_falling;
logic s_active;
logic s_stream_en;
logic s_fifo_src_ready;
logic s_fifo_dst_valid;
logic [DVP_PAYLOAD_WIDTH-1:0] s_fifo_dst_data;
logic s_fifo_dst_ready;
logic s_fifo_src_clear;
logic s_fifo_src_clear_busy;
logic s_fifo_dst_clear_busy;
logic [ 31:0] s_fifo_rx_data;
logic s_rx_pop;
logic s_fifo_full_sys;
logic s_fifo_empty_sys;
logic s_frm_start_tgl;
logic s_line_done_tgl;
logic s_frm_done_tgl;
logic s_err_tgl;
logic s_frame_start_event;
logic s_line_done_event;
logic s_frame_done_event;
logic s_err_evt;
logic [ 5:0] s_err_flags_pclk;
logic [ 5:0] s_err_flags_sys;
logic [ 127:0] s_frm_stats_pclk;
logic s_frm_stats_v_pclk;
logic s_frm_stats_rdy_pclk;
logic [ 127:0] s_frm_stats_sys;
logic s_frm_stats_v_sys;
assign s_cmd_sys = {s_cmd_flush_sys, s_cmd_abort_sys};
// Commands are consumed in the pixel domain as soon as they cross the CDC.
assign s_cmd_rdy_pclk = !s_fifo_src_clear_busy;
assign s_pclk_falling = s_config_sys[106];
assign s_fifo_src_clear = s_cmd_pclk[`DVP_COMMAND_FLUSH] || s_cmd_pclk[`DVP_COMMAND_ABORT];
assign s_fifo_dst_ready = !s_fifo_dst_clear_busy && (s_stream_en ? rx_axis.tready : s_rx_pop);
assign s_fifo_rx_data = s_fifo_dst_data[31:0];
assign s_fifo_empty_sys = !s_fifo_dst_valid;
tc_clk_buf u_dvp_pclk_clk_buf (
.clk_i(dvp.pclk_i),
.clk_o(s_pclk_buf)
);
tc_clk_inv u_dvp_pclk_inv (
.clk_i(s_pclk_buf),
.clk_o(s_pclk_inv)
);
tc_clk_mux2 u_dvp_pclk_mux (
.clk0_i (s_pclk_buf),
.clk1_i (s_pclk_inv),
.clk_sel_i(s_pclk_falling),
.clk_o (s_pclk_sel)
);
rst_sync #(
.STAGE(5)
) u_dvp_pclk_rst_sync (
.clk_i (s_pclk_sel),
.rst_n_i(rst_n_i),
.rst_n_o(s_pclk_rst_n)
);
dvp_reg u_dvp_reg (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.ribp (ribp),
.active_i (s_active),
.fifo_empty_i (s_fifo_empty_sys),
.fifo_full_i (s_fifo_full_sys),
.rx_data_i (s_fifo_rx_data),
.frame_start_i (s_frame_start_event),
.line_done_i (s_line_done_event),
.frame_done_i (s_frame_done_event),
.error_event_i (s_err_evt),
.error_flags_i (s_err_flags_sys),
.frame_stats_i (s_frm_stats_sys),
.frame_stats_valid_i(s_frm_stats_v_sys),
.config_o (s_config_sys),
.config_valid_o (s_cfg_v_sys),
.config_ready_i (s_cfg_rdy_sys),
.command_abort_o (s_cmd_abort_sys),
.command_flush_o (s_cmd_flush_sys),
.command_valid_o (s_cmd_v_sys),
.command_ready_i (s_cmd_rdy_sys),
.rx_pop_o (s_rx_pop),
.stream_enable_o (s_stream_en),
.irq_o (irq_o)
);
cdc_2phase #(
.DATA_WIDTH(128)
) u_dvp_config_cdc (
.src_clk_i (clk_i),
.src_rst_n_i(rst_n_i),
.src_data_i (s_config_sys),
.src_valid_i(s_cfg_v_sys),
.src_ready_o(s_cfg_rdy_sys),
.dst_clk_i (s_pclk_sel),
.dst_rst_n_i(s_pclk_rst_n),
.dst_data_o (s_cfg_pclk_q),
.dst_valid_o(s_cfg_v_pclk),
.dst_ready_i(s_cfg_rdy_pclk)
);
cdc_2phase #(
.DATA_WIDTH(2)
) u_dvp_command_cdc (
.src_clk_i (clk_i),
.src_rst_n_i(rst_n_i),
.src_data_i (s_cmd_sys),
.src_valid_i(s_cmd_v_sys),
.src_ready_o(s_cmd_rdy_sys),
.dst_clk_i (s_pclk_sel),
.dst_rst_n_i(s_pclk_rst_n),
.dst_data_o (s_cmd_pclk),
.dst_valid_o(s_cmd_v_pclk),
.dst_ready_i(s_cmd_rdy_pclk)
);
cdc_fifo_warm_flush #(
.DATA_WIDTH (DVP_PAYLOAD_WIDTH),
.BUFFER_DEPTH(128)
) u_dvp_payload_fifo (
.src_clk_i (s_pclk_sel),
.src_rst_n_i (s_pclk_rst_n),
.src_clear_i (s_fifo_src_clear),
.src_clear_busy_o(s_fifo_src_clear_busy),
.src_data_i (s_core_push_data),
.src_valid_i (s_core_push_valid),
.src_ready_o (s_fifo_src_ready),
.dst_clk_i (clk_i),
.dst_rst_n_i (rst_n_i),
.dst_clear_busy_o(s_fifo_dst_clear_busy),
.dst_data_o (s_fifo_dst_data),
.dst_valid_o (s_fifo_dst_valid),
.dst_ready_i (s_fifo_dst_ready)
);
logic [DVP_PAYLOAD_WIDTH-1:0] s_core_push_data;
logic s_core_push_valid;
assign s_cmd_core = s_cmd_v_pclk ? s_cmd_pclk : 2'b00;
cdc_sync #(
.STAGE (2),
.DATA_WIDTH(1)
) u_fifo_full_sync (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (!s_fifo_src_ready),
.dat_o (s_fifo_full_sys)
);
cdc_sync #(
.STAGE (2),
.DATA_WIDTH(6)
) u_error_flags_sync (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_err_flags_pclk),
.dat_o (s_err_flags_sys)
);
/* verilator lint_off PINCONNECTEMPTY */
edge_det #(
.STAGE(2)
) u_frame_start_event (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_frm_start_tgl),
.dat_o (),
.re_o (s_frame_start_event),
.fe_o ()
);
edge_det #(
.STAGE(2)
) u_line_done_event (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_line_done_tgl),
.dat_o (),
.re_o (s_line_done_event),
.fe_o ()
);
edge_det #(
.STAGE(2)
) u_frame_done_event (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_frm_done_tgl),
.dat_o (),
.re_o (s_frame_done_event),
.fe_o ()
);
edge_det #(
.STAGE(2)
) u_error_event (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_err_tgl),
.dat_o (),
.re_o (s_err_evt),
.fe_o ()
);
/* verilator lint_on PINCONNECTEMPTY */
cdc_2phase #(
.DATA_WIDTH(128)
) u_dvp_stats_cdc (
.src_clk_i (s_pclk_sel),
.src_rst_n_i(s_pclk_rst_n),
.src_data_i (s_frm_stats_pclk),
.src_valid_i(s_frm_stats_v_pclk),
.src_ready_o(s_frm_stats_rdy_pclk),
.dst_clk_i (clk_i),
.dst_rst_n_i(rst_n_i),
.dst_data_o (s_frm_stats_sys),
.dst_valid_o(s_frm_stats_v_sys),
.dst_ready_i(1'b1)
);
assign rx_axis.tdata = s_fifo_dst_data[31:0];
assign rx_axis.tkeep = s_fifo_dst_data[39:36];
assign rx_axis.tstrb = s_fifo_dst_data[35:32];
assign rx_axis.tlast = s_fifo_dst_data[40];
assign rx_axis.tid = '0;
assign rx_axis.tdest = '0;
assign rx_axis.tuser = s_fifo_dst_data[41];
assign rx_axis.tvalid = s_stream_en && s_fifo_dst_valid;
dvp_core u_dvp_core (
.clk_i (s_pclk_sel),
.rst_n_i (s_pclk_rst_n),
.config_i (s_cfg_pclk_q),
.config_valid_i (s_cfg_v_pclk),
.command_i (s_cmd_core),
.config_ready_o (s_cfg_rdy_pclk),
.push_ready_i (s_fifo_src_ready),
.push_valid_o (s_core_push_valid),
.push_data_o (s_core_push_data),
.active_o (s_active),
.frame_start_toggle_o(s_frm_start_tgl),
.line_done_toggle_o (s_line_done_tgl),
.frame_done_toggle_o (s_frm_done_tgl),
.error_toggle_o (s_err_tgl),
.error_flags_o (s_err_flags_pclk),
.frame_stats_o (s_frm_stats_pclk),
.frame_stats_valid_o (s_frm_stats_v_pclk),
.frame_stats_ready_i (s_frm_stats_rdy_pclk),
.href_i (dvp.href_i),
.vsync_i (dvp.vsync_i),
.dat_i (dvp.dat_i)
);
endmodule