// retroDE_ps2 — platform_video_stub
//
// Smallest retroDE-facing video adapter needed for Milestone A. Accepts a
// flat pixel source (bg_{r,g,b}) from gs_stub and generates a free-running
// VGA-style raster with configurable timing. Wave 1 produces a flood-fill
// frame at the current BGCOLOR — enough to prove the platform video path
// end-to-end without waiting for real GS/PCRTC behavior.
//
// Contract refs:
//   docs/stub_module_plan.md    (Wave 1, item 5)
//   docs/contracts/platform.md
//
// Default timing is VGA 640x480 @ 25.175 MHz pixel clock. Testbenches
// typically override to tiny values (e.g. 16x8 with minimal porches) to
// keep simulation turnaround short.
//
// Replacement path: this module remains as the platform adaptation layer
// while the upstream pixel source evolves from gs_stub to fuller GS/PCRTC
// output.
//
// Trace payload schema:
//   PLAT MODE   arg0=frame_number arg1=pixels_per_frame arg2=- arg3=-
//     emitted once per frame on vsync rising edge, so testbenches can count
//     frames without sampling raw video signals.

`timescale 1ns/1ps

module platform_video_stub
    import trace_pkg::*;
#(
    // Horizontal timing (in pixel clocks)
    parameter int H_ACTIVE = 640,
    parameter int H_FRONT  = 16,
    parameter int H_SYNC   = 96,
    parameter int H_BACK   = 48,
    // Vertical timing (in line counts)
    parameter int V_ACTIVE = 480,
    parameter int V_FRONT  = 10,
    parameter int V_SYNC   = 2,
    parameter int V_BACK   = 33,
    // Sync polarity. VGA 640x480 is active-low on both.
    parameter bit HSYNC_ACTIVE_LOW = 1'b1,
    parameter bit VSYNC_ACTIVE_LOW = 1'b1
) (
    input  logic          clk,        // pixel clock
    input  logic          rst_n,

    // Pixel source from gs_stub
    input  logic [7:0]    bg_r,
    input  logic [7:0]    bg_g,
    input  logic [7:0]    bg_b,

    // Platform-facing video
    output logic          hsync,
    output logic          vsync,
    output logic          de,
    output logic [7:0]    r,
    output logic [7:0]    g,
    output logic [7:0]    b,

    // Trace
    output logic          ev_valid,
    output subsys_e       ev_subsys,
    output event_e        ev_event,
    output logic [63:0]   ev_arg0,
    output logic [63:0]   ev_arg1,
    output logic [63:0]   ev_arg2,
    output logic [63:0]   ev_arg3,
    output logic [31:0]   ev_flags
);

    localparam int H_TOTAL = H_ACTIVE + H_FRONT + H_SYNC + H_BACK;
    localparam int V_TOTAL = V_ACTIVE + V_FRONT + V_SYNC + V_BACK;

    localparam int H_SYNC_START = H_ACTIVE + H_FRONT;
    localparam int H_SYNC_END   = H_SYNC_START + H_SYNC;
    localparam int V_SYNC_START = V_ACTIVE + V_FRONT;
    localparam int V_SYNC_END   = V_SYNC_START + V_SYNC;

    localparam int HCNT_W = $clog2(H_TOTAL);
    localparam int VCNT_W = $clog2(V_TOTAL);

    logic [HCNT_W-1:0] hcnt;
    logic [VCNT_W-1:0] vcnt;

    // ------------------------------------------------------------------
    // Raster counters
    // ------------------------------------------------------------------

    logic end_of_line;
    logic end_of_frame;

    assign end_of_line  = (hcnt == HCNT_W'(H_TOTAL - 1));
    assign end_of_frame = end_of_line && (vcnt == VCNT_W'(V_TOTAL - 1));

    always_ff @(posedge clk) begin
        if (!rst_n) begin
            hcnt <= '0;
            vcnt <= '0;
        end else if (end_of_line) begin
            hcnt <= '0;
            vcnt <= end_of_frame ? '0 : (vcnt + VCNT_W'(1));
        end else begin
            hcnt <= hcnt + HCNT_W'(1);
        end
    end

    // ------------------------------------------------------------------
    // Sync + data-enable + pixel colour
    // ------------------------------------------------------------------

    logic active_h;
    logic active_v;
    logic in_hsync;
    logic in_vsync;

    assign active_h = (hcnt < HCNT_W'(H_ACTIVE));
    assign active_v = (vcnt < VCNT_W'(V_ACTIVE));
    assign in_hsync = (hcnt >= HCNT_W'(H_SYNC_START)) && (hcnt < HCNT_W'(H_SYNC_END));
    assign in_vsync = (vcnt >= VCNT_W'(V_SYNC_START)) && (vcnt < VCNT_W'(V_SYNC_END));

    assign hsync = HSYNC_ACTIVE_LOW ? ~in_hsync : in_hsync;
    assign vsync = VSYNC_ACTIVE_LOW ? ~in_vsync : in_vsync;
    assign de    = active_h && active_v;
    assign r     = de ? bg_r : 8'd0;
    assign g     = de ? bg_g : 8'd0;
    assign b     = de ? bg_b : 8'd0;

    // ------------------------------------------------------------------
    // Trace: one EV_MODE pulse per completed frame.
    // ------------------------------------------------------------------

    logic [31:0] frame_count;

    always_ff @(posedge clk) begin
        if (!rst_n) begin
            frame_count <= 32'd0;

            ev_valid    <= 1'b0;
            ev_subsys   <= SUBSYS_PLAT;
            ev_event    <= EV_MODE;
            ev_arg0     <= 64'd0;
            ev_arg1     <= 64'd0;
            ev_arg2     <= 64'd0;
            ev_arg3     <= 64'd0;
            ev_flags    <= 32'd0;
        end else if (end_of_frame) begin
            frame_count <= frame_count + 32'd1;

            ev_valid    <= 1'b1;
            ev_subsys   <= SUBSYS_PLAT;
            ev_event    <= EV_MODE;
            ev_arg0     <= {32'd0, frame_count};
            ev_arg1     <= {{(64-32){1'b0}}, 32'(H_ACTIVE * V_ACTIVE)};
            ev_arg2     <= 64'd0;
            ev_arg3     <= 64'd0;
            ev_flags    <= 32'd0;
        end else begin
            ev_valid <= 1'b0;
        end
    end

endmodule : platform_video_stub
