// (C) 2001-2025 Altera Corporation. All rights reserved.
// Your use of Altera Corporation's design tools, logic functions and other 
// software and tools, and its AMPP partner logic functions, and any output 
// files from any of the foregoing (including device programming or simulation 
// files), and any associated documentation or information are expressly subject 
// to the terms and conditions of the Altera Program License Subscription 
// Agreement, Altera IP License Agreement, or other applicable 
// license agreement, including, without limitation, that your use is for the 
// sole purpose of programming logic devices manufactured by Altera and sold by 
// Altera or its authorized distributors.  Please refer to the applicable 
// agreement for further details.


module intel_vvp_fr2cv_core
//---------------------------------------------------------------------------
// Description
// This module allow conversion from a VVP FR bus to a Intel CV bus by
// remapping the embedded timing markers on the AXI-FR TDATA bus to
// explicit individual timing signal connections on the CV interface
//---------------------------------------------------------------------------
#(
    parameter NUMBER_OF_COLOR_PLANES    = 3,
    parameter PIXELS_IN_PARALLEL        = 1,
    parameter BPS                       = 10,

    parameter CV_STYLE                  = "Lite",
    parameter CV_HV_MODE                = "sync",
    parameter CV_USE_VALID              = 0,
    parameter CV_USE_READY              = 0,

    // Legacy CV
    parameter RUNTIME_CONTROL           = 1,
    parameter SEPARATE_SLAVE_CLOCK      = 1,
    parameter STD_WIDTH                 = 1,
    parameter CVO_BUS_HAS_CV_CLK        = 1,

    parameter DEVICE_FAMILY             = "Agilex 7"
)
(
    // CPU clock/reset interface
    cpu_clk,
    cpu_rst,

    // CPU interface
    av_mm_cpu_agent_address,
    av_mm_cpu_agent_read,
    av_mm_cpu_agent_readdata,
    av_mm_cpu_agent_readdatavalid,
    av_mm_cpu_agent_waitrequest,
    av_mm_cpu_agent_write,
    av_mm_cpu_agent_writedata,
    av_mm_cpu_agent_byteenable,

    // Legacy CVI "output style" interface: C_CV_ENABLE_VIP_CVI_INTF
    cvi_vid_clk,
    cvi_vid_data,
    cvi_vid_de,
    cvi_vid_datavalid,
    cvi_vid_locked,
    cvi_vid_f,
    cvi_vid_v_sync,
    cvi_vid_h_sync,
    cvi_vid_hd_sdn,
    cvi_vid_std,
    cvi_vid_color_encoding,
    cvi_vid_bit_width,
    cvi_vid_total_sample_count,
    cvi_vid_total_line_count,
    cvi_sof,
    cvi_sof_locked,
    cvi_refclk_div,
    cvi_clipping,
    cvi_padding,
    cvi_overflow,
    cvi_vid_hdmi_duplication,

    // Legacy CVO "output style" interface: C_CV_ENABLE_VIP_CVO_INTF
    cvo_vid_clk,
    cvo_vid_data,
    cvo_underflow,
    cvo_vid_mode_change,
    cvo_vid_vcoclk_div,
    cvo_vid_sof_locked,
    cvo_vid_sof,
    cvo_vid_std,
    cvo_vid_datavalid,
    cvo_vid_v_sync,
    cvo_vid_h_sync,
    cvo_vid_f,
    cvo_vid_h,
    cvo_vid_v,

    // cv clock output
    cv_clk,
    
    // FR and CV Lite clock/reset interface
    vid_clk,
    vid_rst,
    
    // CV Lite interface
    cv_vid_out_data,
    cv_vid_out_active,
    cv_vid_out_f,
    cv_vid_out_h,
    cv_vid_out_v,
    cv_vid_out_h_sync,
    cv_vid_out_v_sync,
    cv_vid_out_valid,
    cv_vid_out_ready,
    
    // FR interface
    axi4s_fr_vid_in_tdata,
    axi4s_fr_vid_in_tuser,
    axi4s_fr_vid_in_tvalid,
    axi4s_fr_vid_in_tready,
    axi4s_fr_vid_in_tlast
);

//---------------------------------------------------------------------------
// Calculate localparams needed for the interface.
//---------------------------------------------------------------------------
localparam C_CV_ENABLE_VIP_CVI_INTF = (CV_STYLE == "CVI") ? 1 : 0;
localparam C_CV_ENABLE_VIP_CVO_INTF = (CV_STYLE == "CVO") ? 1 : 0;

localparam C_PADDED_BPS       = (BPS < 8) ? 8 : BPS;
localparam C_AXIS_PIXEL_BYTES = ((NUMBER_OF_COLOR_PLANES+1)*C_PADDED_BPS+7)/8;
localparam C_AXIS_WIDTH       = C_AXIS_PIXEL_BYTES*PIXELS_IN_PARALLEL*8;
localparam C_TUSER_WIDTH      = C_AXIS_PIXEL_BYTES*PIXELS_IN_PARALLEL;
localparam C_CV_WIDTH         = PIXELS_IN_PARALLEL * NUMBER_OF_COLOR_PLANES * BPS;

localparam C_CPU_ADDR_WIDTH = 6;
localparam C_CPU_ADDR_OUT_OF_RANGE_VALUE = 32'h1234ABCD;

// CPU clock/reset interface
input  logic                                    cpu_clk;
input  logic                                    cpu_rst;

// CPU interface
input  logic [C_CPU_ADDR_WIDTH-1:0]             av_mm_cpu_agent_address;
input  logic                                    av_mm_cpu_agent_read;
output logic [31:0]                             av_mm_cpu_agent_readdata;
output logic                                    av_mm_cpu_agent_readdatavalid;
output logic                                    av_mm_cpu_agent_waitrequest;
input  logic                                    av_mm_cpu_agent_write;
input  logic [31:0]                             av_mm_cpu_agent_writedata;
input  logic [ 3:0]                             av_mm_cpu_agent_byteenable;

// Legacy CVI "output style" interface: C_CV_ENABLE_VIP_CVI_INTF
output logic                                    cvi_vid_clk;
output logic [C_CV_WIDTH-1:0]                   cvi_vid_data;
output logic [PIXELS_IN_PARALLEL-1:0]           cvi_vid_de;
output logic                                    cvi_vid_datavalid;
output logic                                    cvi_vid_locked;
output logic [PIXELS_IN_PARALLEL-1:0]           cvi_vid_f;
output logic [PIXELS_IN_PARALLEL-1:0]           cvi_vid_v_sync;
output logic [PIXELS_IN_PARALLEL-1:0]           cvi_vid_h_sync;
output logic                                    cvi_vid_hd_sdn;
output logic [STD_WIDTH-1:0]                    cvi_vid_std;
output logic [7:0]                              cvi_vid_color_encoding;
output logic [7:0]                              cvi_vid_bit_width;
output logic [15:0]                             cvi_vid_total_sample_count;
output logic [15:0]                             cvi_vid_total_line_count;
input  logic                                    cvi_sof;
input  logic                                    cvi_sof_locked;
input  logic                                    cvi_refclk_div;
output logic [3:0]                              cvi_vid_hdmi_duplication;
input  logic                                    cvi_clipping;
input  logic                                    cvi_padding;
input  logic                                    cvi_overflow;

// Legacy CVO "output style" interface: C_CV_ENABLE_VIP_CVO_INTF
input                                           cvo_vid_clk;
output logic [C_CV_WIDTH-1:0]                   cvo_vid_data;
output logic                                    cvo_underflow;
output logic                                    cvo_vid_mode_change;
output logic                                    cvo_vid_vcoclk_div;
output logic                                    cvo_vid_sof_locked;
output logic                                    cvo_vid_sof;
output logic [PIXELS_IN_PARALLEL*STD_WIDTH-1:0] cvo_vid_std;
output logic [PIXELS_IN_PARALLEL - 1 : 0]       cvo_vid_datavalid;
output logic [PIXELS_IN_PARALLEL - 1 : 0]       cvo_vid_v_sync;
output logic [PIXELS_IN_PARALLEL - 1 : 0]       cvo_vid_h_sync;
output logic [PIXELS_IN_PARALLEL - 1 : 0]       cvo_vid_f;
output logic [PIXELS_IN_PARALLEL - 1 : 0]       cvo_vid_h;
output logic [PIXELS_IN_PARALLEL - 1 : 0]       cvo_vid_v;

// CV output clock
output logic                                    cv_clk;
// FR and CV Lite clock/reset interface
input  logic                                    vid_clk;
input  logic                                    vid_rst;

// CV Lite interface
output logic [C_CV_WIDTH - 1      : 0]          cv_vid_out_data;
output logic [PIXELS_IN_PARALLEL - 1 : 0]       cv_vid_out_active;
output logic [PIXELS_IN_PARALLEL - 1 : 0]       cv_vid_out_f;
output logic [PIXELS_IN_PARALLEL - 1 : 0]       cv_vid_out_h;
output logic [PIXELS_IN_PARALLEL - 1 : 0]       cv_vid_out_v;
output logic [PIXELS_IN_PARALLEL - 1 : 0]       cv_vid_out_h_sync;
output logic [PIXELS_IN_PARALLEL - 1 : 0]       cv_vid_out_v_sync;
output logic                                    cv_vid_out_valid;
input  logic                                    cv_vid_out_ready;

// FR interface
input  logic [C_AXIS_WIDTH - 1    : 0]          axi4s_fr_vid_in_tdata;
input  logic [C_TUSER_WIDTH - 1   : 0]          axi4s_fr_vid_in_tuser;
input  logic                                    axi4s_fr_vid_in_tvalid;
output logic                                    axi4s_fr_vid_in_tready;
input  logic                                    axi4s_fr_vid_in_tlast;

//---------------------------------------------------------------------------
// useful localparams
//---------------------------------------------------------------------------
localparam C_CV_PIXEL_BITS      = NUMBER_OF_COLOR_PLANES * BPS;
localparam C_PADDED_PIXEL_BITS  = NUMBER_OF_COLOR_PLANES * C_PADDED_BPS;
localparam C_AXIS_BITS          = (NUMBER_OF_COLOR_PLANES + 1) * C_PADDED_BPS;

localparam C_BIT_FIELD          = C_AXIS_BITS - 1;
localparam C_BIT_V              = C_AXIS_BITS - 2;
localparam C_BIT_H              = C_AXIS_BITS - 3;
localparam C_BIT_DE             = C_AXIS_BITS - 4;
localparam C_BIT_SYNC_MODE      = C_AXIS_BITS - 5;
// SOF and EOL bits ignored

// cpu reg addresses
localparam C_REG_CVI_LEGACY_0 = 6'd16;
localparam C_REG_CVI_LEGACY_1 = 6'd17;
localparam C_REG_CVI_LEGACY_2 = 6'd18;

localparam C_REG_CVO_LEGACY_0 = 6'd19;

logic                               cpu_reg_cvi_sof;
logic                               cpu_reg_cvi_sof_locked;
logic                               cpu_reg_cvi_overflow;
logic                               cpu_reg_cvi_clipping;
logic                               cpu_reg_cvi_padding;
logic                               cpu_reg_cvi_refclk_div;
logic                               cpu_reg_cvi_vid_locked;
logic                               cpu_reg_cvi_vid_hd_sdn;
logic [STD_WIDTH-1:0]               cpu_reg_cvi_vid_std;
logic [7:0]                         cpu_reg_cvi_vid_color_encoding;
logic [7:0]                         cpu_reg_cvi_vid_bit_width;
logic [3:0]                         cpu_reg_cvi_vid_hdmi_duplication;
logic [15:0]                        cpu_reg_cvi_vid_total_sample_count;
logic [15:0]                        cpu_reg_cvi_vid_total_line_count;
logic                               cpu_reg_cvo_vid_sof;
logic                               cpu_reg_cvo_vid_sof_locked;
logic                               cpu_reg_cvo_underflow;
logic                               cpu_reg_cvo_vid_vcoclk_div;
logic                               cpu_reg_cvo_vid_mode_change;
logic [STD_WIDTH-1:0]               cpu_reg_cvo_vid_std;

logic                               video_clk;
logic [C_CV_WIDTH      - 1 : 0]     vid_out_data;
logic [PIXELS_IN_PARALLEL - 1 : 0]  vid_out_active;
logic [PIXELS_IN_PARALLEL - 1 : 0]  vid_out_f;
logic [PIXELS_IN_PARALLEL - 1 : 0]  vid_out_h;
logic [PIXELS_IN_PARALLEL - 1 : 0]  vid_out_v;
logic [PIXELS_IN_PARALLEL - 1 : 0]  vid_out_h_sync;
logic [PIXELS_IN_PARALLEL - 1 : 0]  vid_out_v_sync;
logic                               vid_out_valid;
logic                               vid_out_ready;

logic [C_AXIS_WIDTH - 1: 0]         shim_axis_tdata;
logic                               shim_axis_tvalid;
logic                               shim_axis_tready;

logic [31:0]                        cpu_reg_cvi_legacy_0;
logic [31:0]                        cpu_reg_cvi_legacy_1;
logic [31:0]                        cpu_reg_cvi_legacy_2;
logic [31:0]                        cpu_reg_cvo_legacy_0;

///////////////////////////////////////////////////////////////////////////////
//
// Connecting Legacy CVI/CVO or CV Lite interface
//
assign cv_clk                       = video_clk; // whatever clock is used internally, route it out so the wider system can use it...

generate
    if (C_CV_ENABLE_VIP_CVI_INTF == 1) begin
        assign video_clk                    = vid_clk;
        // CV Lite
        assign cv_vid_out_data              = {C_CV_WIDTH{1'b0}};
        assign cv_vid_out_active            = {PIXELS_IN_PARALLEL{1'b0}};
        assign cv_vid_out_f                 = {PIXELS_IN_PARALLEL{1'b0}};
        assign cv_vid_out_h                 = {PIXELS_IN_PARALLEL{1'b0}};
        assign cv_vid_out_v                 = {PIXELS_IN_PARALLEL{1'b0}};
        assign cv_vid_out_h_sync            = {PIXELS_IN_PARALLEL{1'b0}};
        assign cv_vid_out_v_sync            = {PIXELS_IN_PARALLEL{1'b0}};
        assign cv_vid_out_valid             = 1'b0;
        assign vid_out_ready                = 1'b1;
    
        // Legacy CVI
        assign cvi_vid_clk                  = vid_clk;
        assign cvi_vid_data                 = vid_out_data;
        assign cvi_vid_datavalid            = vid_out_valid;
        assign cvi_vid_de                   = vid_out_active;
        assign cvi_vid_f                    = vid_out_f;
        assign cvi_vid_v_sync               = vid_out_v_sync;
        assign cvi_vid_h_sync               = vid_out_h_sync;
    
        // Legacy CVO
        assign cvo_vid_data                 = {C_CV_WIDTH{1'b0}};
        assign cvo_vid_datavalid            = {PIXELS_IN_PARALLEL{1'b0}};
        assign cvo_vid_v_sync               = {PIXELS_IN_PARALLEL{1'b0}};
        assign cvo_vid_h_sync               = {PIXELS_IN_PARALLEL{1'b0}};
        assign cvo_vid_f                    = {PIXELS_IN_PARALLEL{1'b0}};
        assign cvo_vid_h                    = {PIXELS_IN_PARALLEL{1'b0}};
        assign cvo_vid_v                    = {PIXELS_IN_PARALLEL{1'b0}};
    end
    else if (C_CV_ENABLE_VIP_CVO_INTF == 1) begin
        assign video_clk                    = CVO_BUS_HAS_CV_CLK==1 ? cvo_vid_clk : vid_clk;
        // CV Lite
        assign cv_vid_out_data              = {C_CV_WIDTH{1'b0}};
        assign cv_vid_out_active            = {PIXELS_IN_PARALLEL{1'b0}};
        assign cv_vid_out_f                 = {PIXELS_IN_PARALLEL{1'b0}};
        assign cv_vid_out_h                 = {PIXELS_IN_PARALLEL{1'b0}};
        assign cv_vid_out_v                 = {PIXELS_IN_PARALLEL{1'b0}};
        assign cv_vid_out_h_sync            = {PIXELS_IN_PARALLEL{1'b0}};
        assign cv_vid_out_v_sync            = {PIXELS_IN_PARALLEL{1'b0}};
        assign cv_vid_out_valid             = 1'b0;
        assign vid_out_ready                = 1'b1;
    
        // Legacy CVI
        assign cvi_vid_clk                  = 1'b0;
        assign cvi_vid_data                 = {C_CV_WIDTH{1'b0}};
        assign cvi_vid_datavalid            = 1'b0;
        assign cvi_vid_de                   = {PIXELS_IN_PARALLEL{1'b0}};
        assign cvi_vid_f                    = {PIXELS_IN_PARALLEL{1'b0}};
        assign cvi_vid_v_sync               = {PIXELS_IN_PARALLEL{1'b0}};
        assign cvi_vid_h_sync               = {PIXELS_IN_PARALLEL{1'b0}};
    
        // Legacy CVO
        assign cvo_vid_data                 = vid_out_data;
        assign cvo_vid_datavalid            = vid_out_active;
        assign cvo_vid_v_sync               = vid_out_v_sync;
        assign cvo_vid_h_sync               = vid_out_h_sync;
        assign cvo_vid_f                    = vid_out_f;
        assign cvo_vid_h                    = vid_out_h;
        assign cvo_vid_v                    = vid_out_v;
    end
    else begin
        assign video_clk                    = vid_clk;
        // CV Lite
        assign cv_vid_out_data              = vid_out_data;
        assign cv_vid_out_active            = vid_out_active;
        assign cv_vid_out_f                 = vid_out_f;
        assign cv_vid_out_h                 = vid_out_h;
        assign cv_vid_out_v                 = vid_out_v;
        assign cv_vid_out_h_sync            = vid_out_h_sync;
        assign cv_vid_out_v_sync            = vid_out_v_sync;
        assign cv_vid_out_valid             = vid_out_valid;
        assign vid_out_ready                = (CV_USE_READY == 1) ? cv_vid_out_ready : 1'b1;
    
        // Legacy CVI
        assign cvi_vid_clk                  = 1'b0;
        assign cvi_vid_data                 = {C_CV_WIDTH{1'b0}};
        assign cvi_vid_datavalid            = 1'b0;
        assign cvi_vid_de                   = {PIXELS_IN_PARALLEL{1'b0}};
        assign cvi_vid_f                    = {PIXELS_IN_PARALLEL{1'b0}};
        assign cvi_vid_v_sync               = {PIXELS_IN_PARALLEL{1'b0}};
        assign cvi_vid_h_sync               = {PIXELS_IN_PARALLEL{1'b0}};
    
        // Legacy CVO
        assign cvo_vid_data                 = {C_CV_WIDTH{1'b0}};
        assign cvo_vid_datavalid            = {PIXELS_IN_PARALLEL{1'b0}};
        assign cvo_vid_v_sync               = {PIXELS_IN_PARALLEL{1'b0}};
        assign cvo_vid_h_sync               = {PIXELS_IN_PARALLEL{1'b0}};
        assign cvo_vid_f                    = {PIXELS_IN_PARALLEL{1'b0}};
        assign cvo_vid_h                    = {PIXELS_IN_PARALLEL{1'b0}};
        assign cvo_vid_v                    = {PIXELS_IN_PARALLEL{1'b0}};
    end
endgenerate

//--------------------------------------------------------------------------------
// Instantiate axis-shim module to decouple the inputs
//--------------------------------------------------------------------------------
intel_vvp_axi_pipeline_stage # (
    .DATA_WIDTH             (C_AXIS_WIDTH),
    .IS_TOKEN_INTERFACE     (1)
)
i_inputshim (
    .clk                    (video_clk),
    .rst                    (vid_rst),

    .axi_st_din_tvalid      (axi4s_fr_vid_in_tvalid),
    .axi_st_din_tdata       (axi4s_fr_vid_in_tdata),
    .axi_st_din_tuser       (1'b0),
    .axi_st_din_tlast       (1'b0),
    .axi_st_din_tready      (shim_axis_tready),
    
    .axi_st_dout_tvalid     (shim_axis_tvalid),
    .axi_st_dout_tdata      (shim_axis_tdata),
    .axi_st_dout_tuser      (),
    .axi_st_dout_tlast      (),
    .axi_st_dout_tready     (vid_out_ready)
);

always_ff @(posedge video_clk) begin
    if (vid_rst) begin
        vid_out_valid <= 1'b0;
    end
    else begin
        if (vid_out_ready) begin
            vid_out_valid <= shim_axis_tvalid;
        end
    end
end

assign axi4s_fr_vid_in_tready = (CV_USE_READY == 1) ? shim_axis_tready : 1'b1;

//---------------------------------------------------------------------------
// Remapping VVP FR bus to a Intel CV
//---------------------------------------------------------------------------
always_ff @(posedge video_clk) begin:a_FR_Stripper
    if (vid_out_ready) begin
        for (int i=0; i<PIXELS_IN_PARALLEL; i++) begin
            vid_out_active[i]    <= shim_axis_tdata[C_AXIS_PIXEL_BYTES*8*i + C_BIT_DE];

            vid_out_f[i]         <= shim_axis_tdata[C_AXIS_PIXEL_BYTES*8*i + C_BIT_FIELD];
            vid_out_v_sync[i]    <= shim_axis_tdata[C_AXIS_PIXEL_BYTES*8*i + C_BIT_V] && ~shim_axis_tdata[C_AXIS_PIXEL_BYTES*8*i + C_BIT_SYNC_MODE];
            vid_out_v[i]         <= shim_axis_tdata[C_AXIS_PIXEL_BYTES*8*i + C_BIT_V] &&  shim_axis_tdata[C_AXIS_PIXEL_BYTES*8*i + C_BIT_SYNC_MODE];
            vid_out_h_sync[i]    <= shim_axis_tdata[C_AXIS_PIXEL_BYTES*8*i + C_BIT_H] && ~shim_axis_tdata[C_AXIS_PIXEL_BYTES*8*i + C_BIT_SYNC_MODE];
            vid_out_h[i]         <= shim_axis_tdata[C_AXIS_PIXEL_BYTES*8*i + C_BIT_H] &&  shim_axis_tdata[C_AXIS_PIXEL_BYTES*8*i + C_BIT_SYNC_MODE];

            for (int j=0; j<NUMBER_OF_COLOR_PLANES; j++) begin
                vid_out_data[C_CV_PIXEL_BITS*i + BPS*j +: BPS] <= shim_axis_tdata[C_AXIS_PIXEL_BYTES*8*i + C_PADDED_BPS*(j+1)-1 -: BPS];
            end
        end
    end
end

generate
    if (RUNTIME_CONTROL == 1) begin
        ///////////////////////////////////////////////////////////////////////////////
        //
        // Decode the cpu bus and provide some registers
        //

        // Get values from registers separately to facilitate byteenable code
        always_comb begin
            cpu_reg_cvi_vid_locked                            = cpu_reg_cvi_legacy_0[8];
            cpu_reg_cvi_vid_color_encoding                    = cpu_reg_cvi_legacy_0[23:16];
            cpu_reg_cvi_vid_bit_width                         = cpu_reg_cvi_legacy_0[31:24];
    
            cpu_reg_cvi_vid_std                               = cpu_reg_cvi_legacy_1[STD_WIDTH-1:0]; // up to 16 bits
            cpu_reg_cvi_vid_hdmi_duplication                  = cpu_reg_cvi_legacy_1[19:16];
            cpu_reg_cvi_vid_hd_sdn                            = cpu_reg_cvi_legacy_1[24];
    
            cpu_reg_cvi_vid_total_sample_count                = cpu_reg_cvi_legacy_2[15: 0];
            cpu_reg_cvi_vid_total_line_count                  = cpu_reg_cvi_legacy_2[31:16];
    
            cpu_reg_cvo_vid_sof                               = cpu_reg_cvo_legacy_0[0];
            cpu_reg_cvo_vid_sof_locked                        = cpu_reg_cvo_legacy_0[1];
            cpu_reg_cvo_underflow                             = cpu_reg_cvo_legacy_0[2];
            cpu_reg_cvo_vid_vcoclk_div                        = cpu_reg_cvo_legacy_0[3];
            cpu_reg_cvo_vid_mode_change                       = cpu_reg_cvo_legacy_0[4];
            cpu_reg_cvo_vid_std                               = cpu_reg_cvo_legacy_0[16+:STD_WIDTH]; // up to 12 bits
        end

        always_ff @(posedge cpu_clk) begin : a_cpu
            if (cpu_rst) begin
                cpu_reg_cvi_legacy_0 <= 32'b0;
                cpu_reg_cvi_legacy_1 <= 32'b0;
                cpu_reg_cvi_legacy_2 <= 32'b0;
                cpu_reg_cvo_legacy_0 <= 32'b0;
        
                av_mm_cpu_agent_waitrequest   <= 1'b1;
                av_mm_cpu_agent_readdatavalid <= 1'b0;
                av_mm_cpu_agent_readdata      <= 32'b0;
            end
            else begin
                av_mm_cpu_agent_waitrequest   <= 1'b0;
                av_mm_cpu_agent_readdatavalid <= av_mm_cpu_agent_read;
                av_mm_cpu_agent_readdata      <= 32'b0;

                if (av_mm_cpu_agent_read) begin
                    // Legacy CVI registers
                    if (C_CV_ENABLE_VIP_CVI_INTF && av_mm_cpu_agent_address == C_REG_CVI_LEGACY_0) begin
                        av_mm_cpu_agent_readdata[0]             <= cpu_reg_cvi_sof;         // RO
                        av_mm_cpu_agent_readdata[1]             <= cpu_reg_cvi_sof_locked;  // RO
                        av_mm_cpu_agent_readdata[2]             <= cpu_reg_cvi_overflow;    // RO
                        av_mm_cpu_agent_readdata[3]             <= cpu_reg_cvi_clipping;    // RO
                        av_mm_cpu_agent_readdata[4]             <= cpu_reg_cvi_padding;     // RO
                        av_mm_cpu_agent_readdata[5]             <= cpu_reg_cvi_refclk_div;  // RO

                        av_mm_cpu_agent_readdata[8]             <= cpu_reg_cvi_vid_locked;

                        av_mm_cpu_agent_readdata[23:16]         <= cpu_reg_cvi_vid_color_encoding;
                        av_mm_cpu_agent_readdata[31:24]         <= cpu_reg_cvi_vid_bit_width;
                    end
                    else if (C_CV_ENABLE_VIP_CVI_INTF && av_mm_cpu_agent_address == C_REG_CVI_LEGACY_1) begin // optional registers
                        av_mm_cpu_agent_readdata[STD_WIDTH-1:0] <= cpu_reg_cvi_vid_std; // up to 16 bits
                        av_mm_cpu_agent_readdata[19:16]         <= cpu_reg_cvi_vid_hdmi_duplication;
                        av_mm_cpu_agent_readdata[24]            <= cpu_reg_cvi_vid_hd_sdn;
                    end
                    else if (C_CV_ENABLE_VIP_CVI_INTF && av_mm_cpu_agent_address == C_REG_CVI_LEGACY_2) begin // optional registers
                        av_mm_cpu_agent_readdata[ 15:0]         <= cpu_reg_cvi_vid_total_sample_count;
                        av_mm_cpu_agent_readdata[31:16]         <= cpu_reg_cvi_vid_total_line_count;
                    end
                    // Legacy CVO registers
                    else if (C_CV_ENABLE_VIP_CVO_INTF && av_mm_cpu_agent_address == C_REG_CVO_LEGACY_0) begin
                        av_mm_cpu_agent_readdata[0]             <= cpu_reg_cvo_vid_sof;
                        av_mm_cpu_agent_readdata[1]             <= cpu_reg_cvo_vid_sof_locked;
                        av_mm_cpu_agent_readdata[2]             <= cpu_reg_cvo_underflow;
                        av_mm_cpu_agent_readdata[3]             <= cpu_reg_cvo_vid_vcoclk_div;
                        av_mm_cpu_agent_readdata[4]             <= cpu_reg_cvo_vid_mode_change;
                        av_mm_cpu_agent_readdata[16+:STD_WIDTH] <= cpu_reg_cvo_vid_std; // up to 16 bits
                    end
                    // Out of range
                    else begin
                        av_mm_cpu_agent_readdata                <= C_CPU_ADDR_OUT_OF_RANGE_VALUE;
                    end
                end

                if (av_mm_cpu_agent_write) begin
                    for (int i=0; i<4; i++) begin
                        if (av_mm_cpu_agent_byteenable[i]) begin
                            // Legacy CVI registers
                            if (C_CV_ENABLE_VIP_CVI_INTF && av_mm_cpu_agent_address == C_REG_CVI_LEGACY_0) begin
                                cpu_reg_cvi_legacy_0[8*i +: 8] <= av_mm_cpu_agent_writedata[8*i +: 8];
                            end
                            else if (C_CV_ENABLE_VIP_CVI_INTF && av_mm_cpu_agent_address == C_REG_CVI_LEGACY_1) begin
                                cpu_reg_cvi_legacy_1[8*i +: 8] <= av_mm_cpu_agent_writedata[8*i +: 8];
                            end
                            else if (C_CV_ENABLE_VIP_CVI_INTF && av_mm_cpu_agent_address == C_REG_CVI_LEGACY_2) begin
                                cpu_reg_cvi_legacy_2[8*i +: 8] <= av_mm_cpu_agent_writedata[8*i +: 8];
                            end
                            // Legacy CVO registers
                            else if (C_CV_ENABLE_VIP_CVO_INTF && av_mm_cpu_agent_address == C_REG_CVO_LEGACY_0) begin
                                cpu_reg_cvo_legacy_0[8*i +: 8] <= av_mm_cpu_agent_writedata[8*i +: 8];
                            end
                        end
                    end
                end
            end
        end

        ///////////////////////////////////////////////////////////////////////////////
        //
        // Video <-> CPU clock domain crossings
        //
        if (SEPARATE_SLAVE_CLOCK == 1) begin

            // C_REG_CVI_LEGACY_CVI_0, RW
            intel_vvp_clock_crosser #(
                .DATA_WIDTH (6),
                .NUM_CC_REG (3),
                .INPUT_REG  (1)
            )
            u_cdc_reg_0 (
                .in_clk     (video_clk),
                .in_data    ({
                    cvi_sof,
                    cvi_sof_locked,
                    cvi_overflow,
                    cvi_clipping,
                    cvi_padding,
                    cvi_refclk_div
                    }),
                .out_clk    (cpu_clk),
                .out_data   ({
                    cpu_reg_cvi_sof,
                    cpu_reg_cvi_sof_locked,
                    cpu_reg_cvi_overflow,
                    cpu_reg_cvi_clipping,
                    cpu_reg_cvi_padding,
                    cpu_reg_cvi_refclk_div
                    })
            );

            // C_REG_CVI_LEGACY_0, RO
            intel_vvp_clock_crosser #(
                .DATA_WIDTH (17),
                .NUM_CC_REG (3),
                .INPUT_REG  (1)
            )
            u_cdc_reg_1 (
                .in_clk     (cpu_clk),
                .in_data    ({
                    cpu_reg_cvi_vid_locked,
                    cpu_reg_cvi_vid_color_encoding,
                    cpu_reg_cvi_vid_bit_width
                    }),
                .out_clk    (video_clk),
                .out_data   ({
                    cvi_vid_locked,
                    cvi_vid_color_encoding,
                    cvi_vid_bit_width
                })
            );

            // C_REG_CVI_LEGACY_1, RO
            intel_vvp_clock_crosser #(
                .DATA_WIDTH (STD_WIDTH+5),
                .NUM_CC_REG (3),
                .INPUT_REG  (1)
            )
            u_cdc_reg_2 (
                .in_clk     (cpu_clk),
                .in_data    ({
                    cpu_reg_cvi_vid_std,
                    cpu_reg_cvi_vid_hdmi_duplication,
                    cpu_reg_cvi_vid_hd_sdn
                    }),
                .out_clk    (video_clk),
                .out_data   ({
                    cvi_vid_std,
                    cvi_vid_hdmi_duplication,
                    cvi_vid_hd_sdn
                    })
            );

            // C_REG_CVI_LEGACY_2, RO
            intel_vvp_clock_crosser #(
                .DATA_WIDTH (32),
                .NUM_CC_REG (3),
                .INPUT_REG  (1)
            )
            u_cdc_reg_3 (
                .in_clk     (cpu_clk),
                .in_data    ({
                    cpu_reg_cvi_vid_total_sample_count,
                    cpu_reg_cvi_vid_total_line_count
                }),
                .out_clk    (video_clk),
                .out_data   ({
                    cvi_vid_total_sample_count,
                    cvi_vid_total_line_count
                })
            );

            // C_REG_CVO_LEGACY_0, RO
            intel_vvp_clock_crosser #(
                .DATA_WIDTH (5+PIXELS_IN_PARALLEL*STD_WIDTH),
                .NUM_CC_REG (3),
                .INPUT_REG  (1)
            )
            u_cdc_reg_4 (
                .in_clk     (cpu_clk),
                .in_data    ({
                    cpu_reg_cvo_vid_sof,
                    cpu_reg_cvo_vid_sof_locked,
                    cpu_reg_cvo_underflow,
                    cpu_reg_cvo_vid_vcoclk_div,
                    cpu_reg_cvo_vid_mode_change,
                    {PIXELS_IN_PARALLEL{cpu_reg_cvo_vid_std}}
                    }),
                .out_clk    (video_clk),
                .out_data   ({
                    cvo_vid_sof,
                    cvo_vid_sof_locked,
                    cvo_underflow,
                    cvo_vid_vcoclk_div,
                    cvo_vid_mode_change,
                    cvo_vid_std
                })
            );

        end
        else begin
            always_ff @(posedge video_clk) begin
                cpu_reg_cvi_sof             <= cvi_sof;
                cpu_reg_cvi_sof_locked      <= cvi_sof_locked;
                cpu_reg_cvi_overflow        <= cvi_overflow;
                cpu_reg_cvi_clipping        <= cvi_clipping;
                cpu_reg_cvi_padding         <= cvi_padding;
                cpu_reg_cvi_refclk_div      <= cvi_refclk_div;

                cvi_vid_locked              <= cpu_reg_cvi_vid_locked;
                cvi_vid_color_encoding      <= cpu_reg_cvi_vid_color_encoding;
                cvi_vid_bit_width           <= cpu_reg_cvi_vid_bit_width;

                cvi_vid_std                 <= cpu_reg_cvi_vid_std;
                cvi_vid_hdmi_duplication    <= cpu_reg_cvi_vid_hdmi_duplication;
                cvi_vid_hd_sdn              <= cpu_reg_cvi_vid_hd_sdn;

                cvi_vid_total_sample_count  <= cpu_reg_cvi_vid_total_sample_count;
                cvi_vid_total_line_count    <= cpu_reg_cvi_vid_total_line_count;

                cvo_vid_sof                 <= cpu_reg_cvo_vid_sof;
                cvo_vid_sof_locked          <= cpu_reg_cvo_vid_sof_locked;
                cvo_underflow               <= cpu_reg_cvo_underflow;
                cvo_vid_vcoclk_div          <= cpu_reg_cvo_vid_vcoclk_div;
                cvo_vid_mode_change         <= cpu_reg_cvo_vid_mode_change;
                cvo_vid_std                 <= {PIXELS_IN_PARALLEL{cpu_reg_cvo_vid_std}};
            end
        end
    end
    else begin
        always_comb begin
            av_mm_cpu_agent_readdata        = 32'b0;
            av_mm_cpu_agent_readdatavalid   = 1'b0;
            av_mm_cpu_agent_waitrequest     = 1'b0;
        
            cvi_vid_locked                  = 1'b0;
            cvi_vid_color_encoding          = 8'b0;
            cvi_vid_bit_width               = 8'b0;
        
            cvi_vid_std                     = {STD_WIDTH{1'b0}};
            cvi_vid_hdmi_duplication        = 4'b0;
            cvi_vid_hd_sdn                  = 1'b0;
        
            cvi_vid_total_sample_count      = 16'b0;
            cvi_vid_total_line_count        = 16'b0;
        
            cvo_vid_sof                     = 1'b0;
            cvo_vid_sof_locked              = 1'b0;
            cvo_underflow                   = 1'b0;
            cvo_vid_vcoclk_div              = 1'b0;
            cvo_vid_mode_change             = 1'b0;
            cvo_vid_std                     = {PIXELS_IN_PARALLEL*STD_WIDTH{1'b0}};
        end
    end
    
endgenerate

endmodule

`ifdef QUESTA_INTEL_OEM
`pragma questa_oem_00 "6vv+NLMwKGCERPrXQet892N4C1uCcErmxLgPyMYhdyaOVp6v3RudhNcA/7XKciBkOPUl2PgJ7/ZUbVxqHQKKzrSdlNXKta3IsnCAq/J9MkOatE4scrQhqz7jz78naosjfxAIOYUnLEA1oR4TKsq17eekHtg6YxLDUNA4tyS3nu/F6+GYYnJsFdi8wNo4AExJNjRD7CqV+JQu8Wz0b9258XsQQ2oy9clPj5jgEPEBfOzlYOJMpiQUiu+uBEWYdb4GPqO2s2x9MIJTeBRbAVwmkpcfxxAtJxXgF5V1qI1g74zmE+GarFt4yFA0HZHlma1k0E1CjutQqIKECNVGuqGwpHOFPNdrsu0bP/PJQVgF6M1Br3KTE5S+QjwnmwpgPAWVwEFFnwNvS3dydu+tWI66j2T4/QmKMlS0wFZ43eq+5RFp1+UNGk7A42nt0GhKEk7DilSyg3qvn8iyym1RsQR9UTlCobBnS9j57n21/NxXc8vkbv0wDHMgoQi1G/5x+zHlsHu2fnEXrMIKcf5+0QBVZ5QDTaxXK71Pz3qbMH47umOv1l2h/CwQ+gHKSu/xjjphM0IesAt0DITVgjgLo8i4hwK8vPvxy9r6UhEhMvoEf3aLsxM+LtpiREAh+JzVkKeZZFc0DZozOp6XeAwWCJ0rFRalfCW0HZiqHAE4W2RpwldM9JUqBOgbx8vzYtT+gNP7caQCfAFH2+V11AQe4Fd/QLL433OmeX9m5qMatPUgjTd4MOTP0izLeJk78C+h1QaTlLhJjznNekXF98tKF+HAlpnMaYA4eeOaTs/zqIWTzXN+8GpzUJ4sY4Su5dZ8pFEz5Lnc0crI0AGg1u6sPMkuId/gzzggoq90Flno+MjHyC0HB9E3UbLfVk5Qlr6PTANTWLtEg6izq266N/GqxjcscAVT9Ox0k0j0rNRrgnbIHqeKgo7TWcuCE31IPMtRrijziylEf050Hf26QKa8zk/xmJeK9nnIPTkb8BgP+ywyMjSyyl+AW7k1AVVUayhcdeLF"
`endif