// 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