From f5f490ef24b3c05ac6e23ea95dceace74b842649 Mon Sep 17 00:00:00 2001 From: JayR-360 <149827065+JayR-360@users.noreply.github.com> Date: Fri, 14 Nov 2025 18:10:31 -0500 Subject: [PATCH 01/10] Add initial content to vga_timing.sv --- rtl/video/vga_timing.sv | 1 + 1 file changed, 1 insertion(+) diff --git a/rtl/video/vga_timing.sv b/rtl/video/vga_timing.sv index e69de29..77356c3 100644 --- a/rtl/video/vga_timing.sv +++ b/rtl/video/vga_timing.sv @@ -0,0 +1 @@ +test From ed480525b37d17d113f60f20aa21357ded434190 Mon Sep 17 00:00:00 2001 From: JayR-360 <149827065+JayR-360@users.noreply.github.com> Date: Fri, 14 Nov 2025 19:24:56 -0500 Subject: [PATCH 02/10] Add VGA_timing module for video synchronization Implement VGA timing module with pixel clock generation and coordinate tracking. --- rtl/video/vga_timing.sv | 58 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/rtl/video/vga_timing.sv b/rtl/video/vga_timing.sv index 77356c3..2320dc7 100644 --- a/rtl/video/vga_timing.sv +++ b/rtl/video/vga_timing.sv @@ -1 +1,57 @@ -test +`timescale 1ns / 1ps + +module VGA_timing( + input clk, + input reset, + output hsync, + output vsync, + output reg [9:0] x, + output reg [9:0] y, + output reg active_video +); + +localparam H_RES = 640, + V_RES = 480, + H_FP = 16, + H_SYNC = 98, + H_BP = 48, + V_FP = 10, + V_SYNC = 2, + V_BP = 2; + + +reg [2:0] counter; +reg pixel_clk; +initial begin + counter = 0; +end + +always@ (posedge clk) begin + if (counter == 2'd2) begin + pixel_clk <= ~pixel_clk; + counter <= 0; + end + else begin + counter <= counter + 1; + end +end + + + + always@ (posedge pixel_clk) begin + if (reset) begin + x <= 0; + y <= 0; + active_video <= 0; + end + + if (active_video == 1'b1) begin + //video logic + x <= x + 1; + y <= y + 1; + end + end + + + +endmodule From dbb83f5ebcf47981bac0ac1dd434cb26c0619947 Mon Sep 17 00:00:00 2001 From: GameBoyAdvSP <90002537+Meowcaroni@users.noreply.github.com> Date: Mon, 17 Nov 2025 10:27:09 -0500 Subject: [PATCH 03/10] Erase 'timescale' from VGA_timing module Deleted 'timescale' line to ensure file was compatible with all simulators --- rtl/video/vga_timing.sv | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/rtl/video/vga_timing.sv b/rtl/video/vga_timing.sv index 2320dc7..1d36e1e 100644 --- a/rtl/video/vga_timing.sv +++ b/rtl/video/vga_timing.sv @@ -1,5 +1,3 @@ -`timescale 1ns / 1ps - module VGA_timing( input clk, input reset, @@ -55,3 +53,4 @@ end endmodule + From ffff12ec63e8c2b2fc56e2792229405d67df172e Mon Sep 17 00:00:00 2001 From: JayR-360 <149827065+JayR-360@users.noreply.github.com> Date: Sun, 23 Nov 2025 18:41:05 -0500 Subject: [PATCH 04/10] Update VGA_timing module with new input and logic Refactor VGA timing module to add position tracking and improve reset handling. Also handled changes listed in comments --- rtl/video/vga_timing.sv | 65 ++++++++++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 21 deletions(-) diff --git a/rtl/video/vga_timing.sv b/rtl/video/vga_timing.sv index 1d36e1e..7ccc17c 100644 --- a/rtl/video/vga_timing.sv +++ b/rtl/video/vga_timing.sv @@ -1,13 +1,21 @@ module VGA_timing( - input clk, - input reset, - output hsync, - output vsync, - output reg [9:0] x, - output reg [9:0] y, - output reg active_video + input clk_i, //clock to control porject + input rst_ni, //active low reset + output hsync, //horizotal sync + output vsync, //vertical sync + + /****/ + //not in ond pager added after fact + output reg [9:0] pos_in_row, //current position in row + output reg [9:0] pos_in_col, //current position in col + /****/ + + output reg [9:0] x, //x coordinate to display pixel data + output reg [9:0] y, //y coordinate to display pixel data + output reg active_video //determines whether we have active video or not ); +//parameters for VGA window localparam H_RES = 640, V_RES = 480, H_FP = 16, @@ -15,16 +23,21 @@ localparam H_RES = 640, H_BP = 48, V_FP = 10, V_SYNC = 2, - V_BP = 2; - - + V_BP = 2, + H_ACTIVE_START = H_SYNC + H_BP, //this parameter list the start of the valid horizontal output + H_ACTIVE_END = H_ACTIVE_START + H_RES, //this parameter contains when to stop output data + V_ACTIVE_START = V_SYNC + V_BP, + V_ACTIVE_END = V_SYNC + 480; + + +/* STUFF TO CONTROL and MAKE VGA CLOCK */ reg [2:0] counter; reg pixel_clk; initial begin counter = 0; end -always@ (posedge clk) begin +always@ (posedge clk_i) begin if (counter == 2'd2) begin pixel_clk <= ~pixel_clk; counter <= 0; @@ -33,24 +46,34 @@ always@ (posedge clk) begin counter <= counter + 1; end end + +/* clock end */ + + + +/* STUFF TO CONTROL VGA DISPLAY */ + assign hsync = (x < H_SYNC) ? 1'b0 : 1'b1; //while this is less than the HSYNC value (98) it is going to not write valid data (black) + assign vsync = (y < V_SYNC) ? 1'b0 : 1'b1; //while this is less than the VSYNC value (2) it is going to not write valid data (black) - always@ (posedge pixel_clk) begin - if (reset) begin + if (rst_ni) begin x <= 0; y <= 0; active_video <= 0; end if (active_video == 1'b1) begin - //video logic - x <= x + 1; - y <= y + 1; - end + if ((pos_in_row >= H_ACTIVE_START) && (pos_in_row < H_ACTIVE_END) && + (pos_in_col >= V_ACTIVE_START) && (pos_in_col < V_ACTIVE_END)) begin + x <= pos_in_row - H_ACTIVE_START; + y <= pos_in_col - V_ACTIVE_START; + end + end + else begin //not within valid data window + x <= 0; + y <= 0; + end end - - - + /* VGA STUFF */ endmodule - From 7b8cad6ce5163798afd6c4f05c0ab69f4f968d06 Mon Sep 17 00:00:00 2001 From: JayR-360 <149827065+JayR-360@users.noreply.github.com> Date: Sun, 23 Nov 2025 18:44:55 -0500 Subject: [PATCH 05/10] Document VGA timing module functionality Added documentation for VGA timing module including parameters, interfaces, behavior, and dependencies. --- rtl/video/VGA_timing_op.md | 60 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 rtl/video/VGA_timing_op.md diff --git a/rtl/video/VGA_timing_op.md b/rtl/video/VGA_timing_op.md new file mode 100644 index 0000000..b169438 --- /dev/null +++ b/rtl/video/VGA_timing_op.md @@ -0,0 +1,60 @@ +The purpose of the VGA timing module is to generate the horizontal and vertical synchronization pulses and pixel coordinate signals required for standard VGA resolutions (e.g., 640×480 @ 60 Hz). It defines when each pixel should be drawn, when blanking intervals occur, and when sync pulses are active essentially acting as the heartbeat of the display pipeline. Other video blocks, such as the framebuffer controller or DAC driver, use these timing signals to know when to fetch and output video data. + +Parameters + +| Name | Default | Description | +| ----------| ------- | --------------------------------------------| +| H_RES | 640 | Active horizontal pixels per line | +| V_RES | 480 | Active vertical pixels per frame | +| H_FP | 16 | Horizontal front porch (pixels) | +| H_SYNC | 96 | Horizontal sync pulse width (pixels) | +| H_BP | 48 | Horizontal back porch (pixels) | +| V_FP | 10 | Vertical front porch (lines) | +| V_SYNC | 2 | Vertical sync pulse width (lines) | +| V_BP | 2 | Vertical back porch (lines) | +| PIXEL_CLK | 25*10^6 | Pixel clock frequency for 640 by 480 @ 60Hz | + +Interfaces (Ports) + +| Signal | Dir | Width | Description | +| ---- | ---- | ---- |-------------------------------------------------------------------------------------------------------------| +| clk | Input | 1 | Main pixel clock. Ensures timing logic and display pipeline stay synchronized | +| reset | Input | 1 | Active-low synchronous reset | +| hsync | Output | 1 | Horizontal sync pulse. Signals the end of a frame (start of new refresh) | +| vsync | Output | 1 | Vertical sync pulse. Signals the end of a frame (start of new fresh) | +| x | Output | 10 | Horizontal pixel counter (0-639 during active display) | +| y | Output | 10 | Vertical pixel counter (0-479 during active display) | +| active_video | Output | 1 | High during visible display time; low during blanking intervals (used to gate pixel output or blank screen) | + +Reset/Initialization + +- On reset (reset = 0), all internal counters (x,y) reset to zero and both sync outputs (hsync, vsync) are deserted +- The module begins normal operation as soon as reset is released and a valid clk is present +- No external configuration sequence is required timing parameters are static or parametrized at synthesis + +Behavior and Timing + +- The module implements two nested counters: + - The horizontal counter (x) increments every clock cycle + - When x reaches the total pixels per line, it resets to zero and increments the vertical counter (y) +- hsync is asserted low for H_SYNC cycles after the active + front porch interval +- vsync is asserted low for V_SYNC lines after the active + front porch period +- The signal active_video is high only when both x and y are within the active display area +- The structure guarantees a 60 Hz refresh at 640 \* 480 with a 25 MHz pixel clock + +Errors / IRQs + +- This module does not generate interrupts or error signals +- It operates continuously as long as a valid clock is provided +- Any display synchronization or VSYNC interrupt is usually handled by the framebuffer controller + +Dependencies + +- Clock: Requires a stable pixel clock (typically 25 MHz). +- Reset: Synchronous, active-low (reset). +- Upstream IP: Clock generation block (PLL or divider). +- Downstream IP: Framebuffer controller or video DAC/encoder that consumes timing signals. + +Summary + +- The VGA timing generator defines the temporal structure of a video frame by driving sync pulses, counters, and valid video windows. It forms the foundation for raster-scan display logic and provides synchronization for all downstream video pipeline modules From 24933b9e3c591376f70ee55947d6b0ae201dd8da Mon Sep 17 00:00:00 2001 From: JayR-360 <149827065+JayR-360@users.noreply.github.com> Date: Fri, 13 Feb 2026 13:55:10 -0500 Subject: [PATCH 06/10] Add framebuffer controller module for video output still not complete but basic framework - need to meet with other teams to ensure proper functionality - might need write path? - needs axi and ddr funcionality --- rtl/video/fb_ctrl.sv | 204 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 204 insertions(+) diff --git a/rtl/video/fb_ctrl.sv b/rtl/video/fb_ctrl.sv index e69de29..9a616e5 100644 --- a/rtl/video/fb_ctrl.sv +++ b/rtl/video/fb_ctrl.sv @@ -0,0 +1,204 @@ +module fb_ctrl_basic #( + parameter int unsigned H_RES = 640, + parameter int unsigned V_RES = 480, + + // Source framebuffer format (GamingCPU uses 320x200 8bpp; start here even if VGA is 640x480) + parameter int unsigned FB_W = 320, + parameter int unsigned FB_H = 200, + parameter int unsigned INDEX_W = 8, // 8bpp index + parameter int unsigned RGB_W = 24, // 8:8:8 output for now + + // Addressing + parameter int unsigned ADDR_W = 32, + parameter int unsigned STRIDE_W = 16 // stride in BYTES +) ( + input logic clk_i, + input logic rst_ni, + input logic enable_i, + + // "Registers" (programming model) + input logic [ADDR_W-1:0] fb_base_i, // base address (byte address, even for BRAM emulation) + input logic [STRIDE_W-1:0] fb_stride_i, // bytes per row (>= FB_W) + + // From timing generator + input logic [$clog2(H_RES)-1:0] pixel_x_i, + input logic [$clog2(V_RES)-1:0] pixel_y_i, + input logic active_video_i, + input logic vsync_i, + + //for double buffering + input logic swap_req_i, //signal from CPU to request buffer swap (can be a simple pulse) + output logic swap_done_o, //signal to CPU to indicate swap is done (can be a pulse on the next vsync after swap) + + // frame sync intrrupt (to CPU / interrupt controller) + output logic vsync_irq_o, + + // Output pixel stream + output logic [INDEX_W-1:0] pixel_index_o, + output logic [RGB_W-1:0] pixel_rgb_o, + output logic pixel_valid_o + +); + +//enable +logic enable_q; +logic enable_rise; + +always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + enable_q <= 1'b0; + end else begin + enable_q <= enable_i; + end +end + +assign enable_rise = enable_i && !enable_q; //detect rising edge of enable to reset state if needed + // -------------------------------------------------------------------------- + //Coordinate mapping (OUTPUT space -> SOURCE framebuffer space) + // -------------------------------------------------------------------------- + + logic [$clog2(FB_W)-1:0] src_x; + logic [$clog2(FB_H)-1:0] src_y; + logic src_in_range; + + always_comb begin + + src_x = pixel_x_i[$clog2(H_RES)-1:1]; //scale the x down by 2 640 -> 320 + src_y = (pixel_y_i * FB_H) / V_RES; //scale the y down 480 -> 200 + src_in_range = (src_x < FB_W) && (src_y < FB_H); // a simple bounds check + + end + + + + +// -------------------------------------------------------------------------- +// Memory backend (BRAM emulation for now) +// We'll model framebuffer as a simple array indexed by "byte offset from base" +// -------------------------------------------------------------------------- +localparam int unsigned FB_BYTES = FB_W * FB_H; // 1 byte per pixel +localparam int unsigned FB_TOTAL_BYTES = 2 * FB_BYTES; //total size for double buffering + +logic [$clog2(FB_TOTAL_BYTES)-1:0] bram_addr; +logic [INDEX_W-1:0] bram_rdata_q; + +//replace this line with actual BRAM instantiation in the future +logic [INDEX_W-1:0] framebuffer [0:FB_TOTAL_BYTES-1]; + +//page offsets +localparam int unsigned FB_PAGE_BYTES = FB_BYTES; +logic [$clog2(FB_TOTAL_BYTES)-1:0] front_page_off_q, back_page_off_q; + + +//read address uses front page +always_comb begin + bram_addr = front_page_off_q + (src_y * FB_W) + src_x; +end + +//1 cycle registered read +always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + bram_rdata_q <= '0; + end else begin + bram_rdata_q <= framebuffer[bram_addr]; + end +end + +// -------------------------------------------------------------------------- +//Valid alignment (because memory read has latency) +// -------------------------------------------------------------------------- + +logic valid_q; + +always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + valid_q <= 1'b0; + end else begin + valid_q <= enable_i && src_in_range && active_video_i; + end +end + +always_comb begin + pixel_index_o = bram_rdata_q; + pixel_valid_o = valid_q; +end + +// -------------------------------------------------------------------------- +//Palette lookup +// -------------------------------------------------------------------------- + +logic [RGB_W-1:0] palette [0:(1< Date: Fri, 13 Feb 2026 13:56:35 -0500 Subject: [PATCH 07/10] Add files via upload frame buffer controller one page; might update later once module is fully realized --- rtl/video/# fb_ctrl - Module Brief (v0.1).md | 102 +++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 rtl/video/# fb_ctrl - Module Brief (v0.1).md diff --git a/rtl/video/# fb_ctrl - Module Brief (v0.1).md b/rtl/video/# fb_ctrl - Module Brief (v0.1).md new file mode 100644 index 0000000..e7572bc --- /dev/null +++ b/rtl/video/# fb_ctrl - Module Brief (v0.1).md @@ -0,0 +1,102 @@ +# fb_ctrl - Module Brief (v0.1) + +**Owner:** Jay Merveilleux +**RTL:** `rtl/video/fb_ctrl.sv` + +The `fb_ctrl` module implements the display scanout engine for the video subsystem by autonomously reading pixel data from a framebuffer stored in system memory and delivering it to the video output pipeline in precise synchronization with VGA timing. A framebuffer is a memory-resident image buffer in which each location represents the color of a screen pixel; `fb_ctrl` continuously scans this memory in raster order-left to right, top to bottom-using DMA-style AXI reads driven by the active display timing. The module supports configurable base address and stride, enabling flexible memory layout and efficient, cache-aligned access to frame data. To prevent visual artifacts such as tearing, `fb_ctrl` employs double buffering, displaying one framebuffer while another is updated and performing buffer swaps only at vertical sync boundaries. In addition, the controller expands indexed pixel formats via palette or colormap lookup and raises a VSYNC interrupt to coordinate safe rendering and buffer management with software. + +--- + +## Parameters + +- **H_RES** (default: 640) + Defines the horizontal resolution of the active display area and the number of pixels scanned per line. + +- **V_RES** (default: 480) + Defines the vertical resolution of the active display area and the total number of visible lines per frame. + +- **Pixel format / data width** + Number of bits per pixel fetched from framebuffer memory. The default configuration uses 8-bit indexed color expanded to RGB via palette/COLORMAP logic. + +- **Address width** + Width of framebuffer base address and internal address counters, defining the maximum addressable framebuffer size in system memory. + +- **Stride support** + Programmable line stride allowing each framebuffer row to begin at a configurable byte offset, supporting padded or cache-line-aligned layouts. + +- **AXI burst length / beat size** + Controls AXI read burst sizing during scanout to maximize sustained memory bandwidth and minimize bus overhead. + +- **Double-buffer enable** + Enables front/back framebuffer operation with swaps applied only at VSYNC boundaries. + +- **Scaling mode** + Optional pixel replication used for resolution upscaling (e.g., 320*200 source scaled to 640*480 output). + +--- + +## Interfaces (Ports) + +| Signal | Dir | Width | Description | +|------------------|-----|--------|---------------------------------------------------------------------------| +| `clk_i` | in | 1 | System clock driving framebuffer control logic and DMA request generation | +| `rst_ni` | in | 1 | Active-low reset; clears internal state and disables scanout | +| `enable_i` | in | 1 | Enables framebuffer scanout | +| `fb_base_i` | in | ADDR_W | Base address of active framebuffer in DDR | +| `fb_stride_i` | in | STR_W | Byte stride between successive framebuffer rows | +| `fb_swap_i` | in | 1 | Requests front/back framebuffer swap (applied at VSYNC) | +| `pixel_x_i` | in | X_W | Horizontal pixel coordinate from VGA timing | +| `pixel_y_i` | in | Y_W | Vertical pixel coordinate from VGA timing | +| `active_video_i` | in | 1 | High during visible display region | +| `pixel_index_o` | out | PIX_W | Indexed pixel fetched from framebuffer | +| `pixel_rgb_o` | out | RGB_W | Expanded RGB pixel output | +| `axi_ar_*` | out | - | AXI read address channel | +| `axi_r_*` | in | - | AXI read data channel | +| `vsync_irq_o` | out | 1 | VSYNC interrupt signaling frame boundary | + +--- + +## Reset / Initialization + +The `fb_ctrl` module uses an active-low reset (`rst_ni`) to return all internal state to a known idle condition. When reset is asserted, scanout is disabled, internal registers are cleared, and no AXI memory transactions are issued. Pixel output and VSYNC interrupt generation are suppressed during reset. After reset is deasserted, software programs framebuffer base address, stride, and buffer configuration before enabling scanout. Normal operation begins once enabled, with any buffer swap requests applied on the next VSYNC boundary. + +--- + +## Behavior & Timing + +The `fb_ctrl` module operates synchronously on the system clock (`clk_i`) as a continuously running scanout engine. When enabled, it autonomously issues AXI read transactions to fetch pixel data from the active framebuffer in raster order, synchronized to VGA timing. Framebuffer addresses advance horizontally across each line and jump by the programmed stride at line boundaries. Memory fetches are gated during blanking intervals using `active_video_i`. Double-buffer swaps are latched during operation and applied atomically at VSYNC, where an optional interrupt signals frame completion. + +--- + +## Programming Model + +The `fb_ctrl` module is configured through memory-mapped control registers defined in `specs/registers/video.yaml`. Software programs framebuffer base address, stride, pixel format, palette configuration, and optional front/back buffers before enabling scanout. Once enabled, hardware autonomously performs pixel fetch, format expansion, and display synchronization. A VSYNC interrupt allows software to safely update frame data or request buffer swaps, which are applied only at VSYNC. + +--- + +## Errors / IRQs + +The `fb_ctrl` module does not implement internal error detection for invalid configuration parameters or memory access failures. It assumes valid framebuffer addresses and reliable AXI read responses. No explicit error flags are generated for out-of-bounds access or underruns. An optional VSYNC interrupt is generated at the end of each frame and cleared via control/status registers as defined in `specs/registers/video.yaml`. + +--- + +## Performance Targets + +- Sustains continuous scanout at one pixel per pixel clock +- Operates at standard video pixel clocks (e.g., 25-40+ MHz for VGA modes) +- AXI bandwidth provisioned for worst-case resolution and pixel format +- Bounded, deterministic pixel latency through fixed pipeline depth +- Tear-free full-frame updates via double buffering +- No jitter introduced into active display timing + +--- + +## Dependencies + +Depends on system clock (`clk_i`), reset (`rst_ni`), AXI memory fabric, and backing DDR. Requires VGA timing signals from `vga_timing.sv`. Software must program valid framebuffer parameters via `specs/registers/video.yaml`. The AXI interconnect arbitrates memory access against other masters and must provide sufficient bandwidth for worst-case scanout. + +--- + +## Verification Links + +Verified using directed simulation testbenches validating raster-order scanout, stride handling, blanking behavior, and VSYNC-synchronized buffer swaps. System-level video simulations and test applications validate sustained operation under memory contention. AXI memory models observe read access patterns and burst alignment. Known limitations include reliance on software for bounds checking and the absence of formal verification under extreme contention. From dfda340d1a4518b56d25806e14daaba5d8670b6c Mon Sep 17 00:00:00 2001 From: JayR-360 <149827065+JayR-360@users.noreply.github.com> Date: Fri, 13 Feb 2026 18:15:44 -0500 Subject: [PATCH 08/10] Implement VGA DAC module for video output ready for verification --- rtl/video/pmod_vga_dac.sv | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/rtl/video/pmod_vga_dac.sv b/rtl/video/pmod_vga_dac.sv index e69de29..4b5c051 100644 --- a/rtl/video/pmod_vga_dac.sv +++ b/rtl/video/pmod_vga_dac.sv @@ -0,0 +1,34 @@ +module pmod__DAC( + input logic clk_i, + input logic rst_ni, + input logic active_video_i, + input logic [3:0] R_i, + input logic [3:0] G_i, + input logic [3:0] B_i, + input logic hsync_i, vsync_i, + output logic [3:0] vga_r_o, + output logic [3:0] vga_g_o, + output logic [3:0] vga_b, + output logic hsync_o, + output logic vsync_o +); + +assign vsync_o = vsync_i; +assign hsync_o = hsync_i; + +always @(posedge clk_i) begin + if (~rst_ni) begin + vga_r_o <= 0; + vga_g_o <= 0; + vga_b_o <= 0; + end + + + if (active_video_i == 1'b1) begin //active video enable nothing will happen if it is at zero + // if (active_video_i) begin + vga_r_o <= R_i; + vga_g_o <= G_i; + vga_b_o <= B_i; + end +end +endmodule From 76c7e8f0f2d2d5a48da699a2f1eed5029d12029f Mon Sep 17 00:00:00 2001 From: JayR-360 <149827065+JayR-360@users.noreply.github.com> Date: Sat, 14 Feb 2026 01:47:05 -0500 Subject: [PATCH 09/10] Add files via upload audio one pagers --- rtl/video/audio_dma_one_pager.md | 94 ++++++++++++++++++++++++++++++++ rtl/video/i2s_tx_one_pager.md | 89 ++++++++++++++++++++++++++++++ rtl/video/pwm_audio_one_pager.md | 87 +++++++++++++++++++++++++++++ 3 files changed, 270 insertions(+) create mode 100644 rtl/video/audio_dma_one_pager.md create mode 100644 rtl/video/i2s_tx_one_pager.md create mode 100644 rtl/video/pwm_audio_one_pager.md diff --git a/rtl/video/audio_dma_one_pager.md b/rtl/video/audio_dma_one_pager.md new file mode 100644 index 0000000..f3763e2 --- /dev/null +++ b/rtl/video/audio_dma_one_pager.md @@ -0,0 +1,94 @@ +# audio_dma — Module Brief (v0.1) + +**Owner:** Jay Merveilleux +**RTL:** `rtl/audio/audio_dma.sv` + +The `audio_dma` module implements the streaming direct memory access (DMA) engine for the GamingCPU audio subsystem. It autonomously transfers audio sample data from system memory into a local buffering interface that feeds downstream audio output blocks such as `i2s_tx` or `pwm_audio`. Designed around a ring-buffer model, `audio_dma` allows software to continuously produce audio samples into memory while hardware consumes them at a deterministic rate, decoupling real-time audio playback from CPU scheduling and instruction execution. By issuing burst-based AXI read transactions, the module sustains audio throughput with minimal bus overhead and predictable latency. + +--- + +## Parameters + +- **Address width** + Width of the AXI address bus and internal address counters, defining the maximum addressable audio buffer size in system memory. + +- **Data width** + Width of AXI read data beats, typically aligned to the system memory and interconnect configuration. + +- **Ring buffer size** + Defines the total size of the circular audio buffer in bytes or samples. + +- **Burst length** + Controls the maximum AXI read burst size used when fetching audio data, balancing latency and bus efficiency. + +- **FIFO depth** + Depth of internal buffering between AXI read responses and the downstream audio sink. + +--- + +## Interfaces (Ports) + +| Signal | Dir | Width | Description | +|-------------------|-----|-------|----------------------------------------------------------------------| +| `clk_i` | in | 1 | System clock driving DMA control logic | +| `rst_ni` | in | 1 | Active-low reset; clears internal state and halts DMA operation | +| `enable_i` | in | 1 | Enables audio DMA operation | +| `buf_base_i` | in | ADDR | Base address of audio ring buffer in system memory | +| `buf_size_i` | in | SIZE | Total size of ring buffer | +| `rd_ptr_i` | in | ADDR | Read pointer supplied by software or internal state | +| `axi_ar_*` | out | — | AXI read address channel | +| `axi_r_*` | in | — | AXI read data channel | +| `sample_*` | out | — | Audio sample stream output to downstream audio blocks | +| `sample_valid_o` | out | 1 | Indicates valid audio sample data | +| `sample_ready_i` | in | 1 | Backpressure from downstream consumer | +| `underrun_o` | out | 1 | Indicates ring buffer underrun condition | +| `irq_o` | out | 1 | Optional interrupt signaling underrun or threshold events | + +--- + +## Reset / Initialization + +The `audio_dma` module uses an active-low reset (`rst_ni`) to return all internal state to a known idle condition. When reset is asserted, all AXI transactions are halted, internal FIFOs are flushed, address counters are cleared, and no audio samples are emitted. Underrun status is cleared, and interrupt outputs are deasserted. After reset deassertion, software programs the ring buffer base address, buffer size, and initial read/write pointers before enabling DMA operation. + +--- + +## Behavior & Timing + +The `audio_dma` module operates synchronously on the system clock (`clk_i`) as a continuously running streaming DMA engine. When enabled, it issues AXI read transactions to fetch audio data from the configured ring buffer in memory. Address generation advances sequentially through the buffer and wraps automatically at the end of the configured buffer region, implementing circular addressing semantics. + +Read data returned over the AXI interface is queued into an internal FIFO, decoupling memory access timing from the fixed consumption rate of the downstream audio output block. Data is presented to the consumer using a valid/ready handshake. AXI read bursts are sized to maximize sustained bandwidth while minimizing arbitration overhead on the shared interconnect. + +--- + +## Programming Model + +The `audio_dma` module is configured through memory-mapped control registers defined in the audio/DMA register specification. Software initializes the audio ring buffer in memory and programs buffer base address, buffer size, and control flags before enabling DMA operation. During playback, software advances the producer write pointer independently, while `audio_dma` advances the consumer read pointer autonomously. Status registers allow software to monitor buffer occupancy and detect underrun conditions. + +--- + +## Errors / IRQs + +The primary error condition detected by `audio_dma` is a buffer underrun, which occurs when the DMA engine attempts to fetch audio data beyond the available produced samples. In this condition, the module asserts an underrun status flag and may generate an interrupt to notify software. Depending on configuration, the DMA engine may stall, continue issuing reads that return invalid data, or output zero-valued samples downstream until the buffer is refilled. Recovery is software-driven and involves replenishing the ring buffer and clearing the underrun status. + +--- + +## Performance Targets + +- Sustains continuous audio streaming at the configured sample rate +- Supports burst-based AXI reads aligned to cache-line boundaries +- Maintains deterministic sample delivery to downstream audio blocks +- Tolerates short-term memory latency via internal buffering +- No audible glitches during steady-state operation +- Graceful handling of underrun conditions + +--- + +## Dependencies + +Depends on the system clock (`clk_i`), reset (`rst_ni`), AXI memory fabric, and backing system memory. Requires a downstream audio consumer such as `i2s_tx` or `pwm_audio`. Software must configure valid ring buffer parameters via the audio/DMA register specification. The AXI interconnect must provide sufficient bandwidth to sustain real-time audio fetches under worst-case contention. + +--- + +## Verification Links + +Verified using directed simulation testbenches validating ring buffer wraparound behavior, AXI burst alignment, and backpressure handling. System-level audio simulations confirm sustained playback under memory contention and proper underrun detection. AXI memory models observe read access patterns and FIFO behavior. Known limitations include reliance on software for correct buffer sizing and the absence of formal verification for extreme arbitration scenarios. diff --git a/rtl/video/i2s_tx_one_pager.md b/rtl/video/i2s_tx_one_pager.md new file mode 100644 index 0000000..b082ae0 --- /dev/null +++ b/rtl/video/i2s_tx_one_pager.md @@ -0,0 +1,89 @@ +# i2s_tx — Module Brief (v0.1) + +**Owner:** Jay Merveilleux +**RTL:** `rtl/audio/i2s_tx.sv` + +The `i2s_tx` module implements the digital audio transmit engine for the GamingCPU audio subsystem by converting parallel PCM audio samples into a serial I2S-compliant data stream for an external digital-to-analog converter (DAC). Acting as the timing master for the audio output path, `i2s_tx` generates the I2S bit clock (BCLK) and left/right word select (LRCLK) signals and shifts out audio sample data in strict alignment with these clocks. Audio samples are provided by an upstream buffering mechanism, typically fed by the audio DMA engine, allowing continuous real-time playback without CPU involvement on a per-sample basis. The module is designed for deterministic operation, ensuring stable audio timing and glitch-free output under sustained load. + +--- + +## Parameters + +- **Sample width** (default: 16 bits) + Defines the bit width of each PCM audio sample per channel. + +- **Channel count** (default: 2) + Number of audio channels supported. The default configuration operates in stereo (left and right). + +- **Clock divider configuration** + Controls derivation of the I2S bit clock and word select clock from the system clock, determining the effective audio sample rate. + +- **Internal buffering depth** + Defines the amount of elastic buffering between the audio producer (DMA or FIFO) and the I2S shifter to absorb short-term timing variation. + +- **Frame format** + Specifies I2S framing behavior, including MSB-first transmission and left-channel-first ordering. + +--- + +## Interfaces (Ports) + +| Signal | Dir | Width | Description | +|-----------------|-----|-------|----------------------------------------------------------------| +| `clk_i` | in | 1 | System clock driving I2S timing generation and shift logic | +| `rst_ni` | in | 1 | Active-low reset; clears internal state and disables output | +| `sample_*` | in | — | Audio sample input interface from DMA or buffering logic | +| `sample_valid` | in | 1 | Indicates availability of a new stereo audio frame | +| `sample_ready` | out | 1 | Backpressure signal to upstream producer | +| `i2s_sdata_o` | out | 1 | I2S serial data output | +| `i2s_bclk_o` | out | 1 | I2S bit clock | +| `i2s_lrclk_o` | out | 1 | I2S left/right word select clock | +| `underrun_o` | out | 1 | Indicates audio underrun condition | +| `irq_o` | out | 1 | Optional interrupt signaling underrun event | + +--- + +## Reset / Initialization + +The `i2s_tx` module uses an active-low reset (`rst_ni`) to return all internal state to a known idle condition. When reset is asserted, I2S clock generation is halted, internal counters and shift registers are cleared, and the serial data output is driven to a benign state. No audio data is transmitted during reset, and underrun status is cleared. After reset deassertion, software configures the audio clocking parameters and enables the upstream audio pipeline before initiating audio transmission. + +--- + +## Behavior & Timing + +The `i2s_tx` module operates synchronously on the system clock (`clk_i`) and functions as a continuously running audio serializer once enabled. Audio samples are transmitted using standard I2S framing, with the left channel transmitted first, followed by the right channel, and data shifted out MSB-first. The module derives the I2S bit clock and word select clock internally, ensuring a fixed relationship between data transitions and clock edges. Sample words are loaded into internal shift registers at channel boundaries and transmitted serially at the programmed bit rate. Internal buffering allows limited decoupling between the audio producer and the strict timing requirements of the I2S interface. + +--- + +## Programming Model + +The `i2s_tx` module is configured through memory-mapped control registers defined in the audio/I2S register specification. Software programs the desired audio sample rate, enables the audio output path, and maintains the upstream audio ring buffer through the audio DMA engine. Once enabled, the module operates autonomously, continuously transmitting audio samples as long as valid data is supplied. Status registers allow software to monitor underrun conditions and overall audio health. + +--- + +## Errors / IRQs + +The primary error condition detected by `i2s_tx` is an audio underrun, which occurs when a new sample frame is required but no valid data is available from the upstream buffer. In this condition, the module outputs zero-valued samples to maintain valid I2S signaling and asserts an underrun status flag. An optional interrupt may be generated to notify software of the condition. Recovery is software-driven and involves refilling the audio buffer and clearing the underrun status. + +--- + +## Performance Targets + +- Sustains continuous real-time audio output at the configured sample rate +- Supports 16-bit stereo PCM audio as the default operating mode +- Maintains stable, jitter-free I2S clock generation +- Tolerates short-term producer latency via internal buffering +- Zero audible artifacts during steady-state operation +- Graceful degradation to silence on underrun conditions + +--- + +## Dependencies + +Depends on the system clock (`clk_i`), reset (`rst_ni`), and upstream audio buffering logic, typically provided by `audio_dma.sv`. Requires software configuration via the audio/I2S register set and relies on the platform interrupt controller for underrun notification. Proper operation assumes that the audio DMA and memory subsystem can sustain the required sample throughput. + +--- + +## Verification Links + +Verified using directed simulation testbenches that validate correct I2S framing, clock generation, and data ordering under normal operation. System-level audio simulations exercise continuous playback and underrun recovery behavior. Audio sink models observe serialized output for timing correctness and frame alignment. Known limitations include reliance on software for buffer sizing and the absence of formal timing verification across all possible clock divider configurations. diff --git a/rtl/video/pwm_audio_one_pager.md b/rtl/video/pwm_audio_one_pager.md new file mode 100644 index 0000000..f0b10cf --- /dev/null +++ b/rtl/video/pwm_audio_one_pager.md @@ -0,0 +1,87 @@ +# pwm_audio — Module Brief (v0.1) + +**Owner:** Jay Merveilleux +**RTL:** `rtl/audio/pwm_audio.sv` + +The `pwm_audio` module implements a simple pulse-width modulation (PWM) based audio output for the GamingCPU SoC. It provides a low-complexity, hardware-minimal audio path by converting digital audio sample amplitudes into a single-bit PWM waveform suitable for direct output to a GPIO pin or simple external low-pass filter. This module serves as a fallback or development-friendly audio solution when a full I2S DAC is unavailable, enabling basic sound output without additional external hardware. Once configured and enabled, `pwm_audio` operates autonomously, continuously converting incoming audio samples into a time-averaged analog signal via PWM duty-cycle modulation. + +--- + +## Parameters + +- **Sample width** (default: 8–16 bits) + Defines the resolution of the input audio sample used to compute the PWM duty cycle. + +- **PWM counter width** + Determines the resolution of the PWM waveform and the effective audio dynamic range. + +- **PWM carrier frequency** + Sets the PWM switching frequency relative to the system clock, trading off audio fidelity against output pin bandwidth and filtering requirements. + +- **Sample update rate** + Defines how often a new audio sample is latched and applied to the PWM duty cycle. + +--- + +## Interfaces (Ports) + +| Signal | Dir | Width | Description | +|-----------------|-----|-------|----------------------------------------------------------------| +| `clk_i` | in | 1 | System clock driving PWM generation and sample update logic | +| `rst_ni` | in | 1 | Active-low reset; clears PWM state and disables output | +| `enable_i` | in | 1 | Enables PWM audio output | +| `sample_i` | in | N | Digital audio sample input | +| `sample_valid` | in | 1 | Indicates availability of a new audio sample | +| `sample_ready` | out | 1 | Backpressure to upstream sample producer | +| `pwm_o` | out | 1 | PWM audio output signal | +| `underrun_o` | out | 1 | Indicates sample underrun condition | +| `irq_o` | out | 1 | Optional interrupt signaling underrun event | + +--- + +## Reset / Initialization + +The `pwm_audio` module uses an active-low reset (`rst_ni`) to return all internal state to a known idle condition. When reset is asserted, the PWM output is driven low, internal counters are cleared, and any latched audio sample state is discarded. No PWM waveform is generated during reset. After reset deassertion, software programs the desired PWM configuration parameters and enables audio output. Normal operation begins once valid audio samples are provided. + +--- + +## Behavior & Timing + +The `pwm_audio` module operates synchronously on the system clock (`clk_i`). Incoming audio samples are latched at the configured sample update rate and mapped to a PWM duty cycle proportional to the sample amplitude. A free-running PWM counter compares against the latched duty value to generate a single-bit output waveform. The time-averaged value of this waveform, when passed through an external low-pass filter or speaker inertia, produces an analog audio signal. + +The PWM carrier frequency is fixed relative to the system clock and is independent of the audio sample rate. Internal buffering allows limited decoupling between sample production and PWM generation, ensuring stable output timing. + +--- + +## Programming Model + +The `pwm_audio` module is configured through memory-mapped control registers defined in the audio/PWM register specification. Software selects PWM resolution, enables the output path, and supplies audio samples either directly or via a shared audio buffering mechanism. Once enabled, the module continuously generates PWM output using the most recent valid sample until updated. + +--- + +## Errors / IRQs + +The primary error condition detected by `pwm_audio` is a sample underrun, which occurs when a new audio sample is required but no valid data is available. In this condition, the module maintains the previous duty cycle or drives the output to a safe default level and asserts an underrun status flag. An optional interrupt may be generated to notify software. Recovery is software-driven and involves supplying new audio samples and clearing the underrun condition. + +--- + +## Performance Targets + +- Supports basic mono audio output for diagnostics and fallback use +- Deterministic PWM carrier frequency with stable duty-cycle generation +- Tolerates moderate sample jitter via internal latching +- Minimal hardware resource utilization +- No audible glitches during steady-state operation +- Graceful degradation during underrun conditions + +--- + +## Dependencies + +Depends on the system clock (`clk_i`) and reset (`rst_ni`) and requires an upstream audio sample source, typically shared with the main audio pipeline. Optional interrupt signaling is routed through the platform interrupt controller. External filtering or speaker characteristics are required to convert the PWM signal into an analog waveform suitable for listening. + +--- + +## Verification Links + +Verified using directed simulation testbenches validating duty-cycle generation, sample latching behavior, and reset operation. System-level tests confirm audible output on hardware platforms using external passive filtering. Known limitations include reduced audio fidelity compared to I2S-based output and reliance on external filtering for acceptable sound quality. From b4ad7a1940257973ceabd0451c63f98547179511 Mon Sep 17 00:00:00 2001 From: VuAiore <105179561+VuAiore@users.noreply.github.com> Date: Fri, 27 Feb 2026 16:03:45 -0500 Subject: [PATCH 10/10] Update pmod_vga_dac.sv slight variable issue fix --- rtl/video/pmod_vga_dac.sv | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rtl/video/pmod_vga_dac.sv b/rtl/video/pmod_vga_dac.sv index 4b5c051..0cf5fa3 100644 --- a/rtl/video/pmod_vga_dac.sv +++ b/rtl/video/pmod_vga_dac.sv @@ -8,7 +8,7 @@ module pmod__DAC( input logic hsync_i, vsync_i, output logic [3:0] vga_r_o, output logic [3:0] vga_g_o, - output logic [3:0] vga_b, + output logic [3:0] vga_b_o, output logic hsync_o, output logic vsync_o ); @@ -32,3 +32,4 @@ always @(posedge clk_i) begin end end endmodule +