Skip to content
Diogo Valadares Reis dos Santos edited this page Aug 26, 2025 · 3 revisions

[Português]

[← Previous Page | Next Page →]

The Screen

The Screen is a component that allows graphics to be rendered by the processor. It operates in a simplified manner compared to real screens, where each pixel is mapped to an address in memory. This design allows you to change the color of any pixel using a single store instruction.

The screen has a square aspect ratio, with a resolution that can be configured to any power-of-two value below 256. For practical reasons, the default resolution is set to 64, using 14 bits to address every pixel (6-bit word addresses for each axis).

Since each pixel requires at least 24 bits to represent its color, each one is mapped to a full 32-bit word. Therefore, to move from one pixel to the next, you must increment or decrement the address by 4.

Although the screen is available in Logisim, due to the limited performance of the simulation, it is recommended to use the SystemVerilog simulation for more complex rendering tasks.

image

In the SystemVerilog interface, there are two important configuration options. The first is the resolution, which can be adjusted as needed. The second is the Screen Refresh Delay, which controls how frequently the program reads the file—lower values result in faster refresh rates.

image

SystemVerilog Code

The code for the screen contains a register matrix that stores the image being displayed. This matrix is copied to a file from time to time if there has been any modifications to it. The screen size is parametrized, allowing its size to be changed

`timescale 1s/1s
module video_controller #(
    parameter SCREEN_WIDTH_BIT_WIDTH = 8,
    parameter SCREEN_HEIGHT_BIT_WIDTH = 8,
    parameter SCREEN_WIDTH = 1 << SCREEN_WIDTH_BIT_WIDTH,
    parameter SCREEN_HEIGHT = 1 << SCREEN_HEIGHT_BIT_WIDTH,
    parameter SCREEN_FILE = "screen.mem",
    parameter WRITE_INTERVAL = 100  // Clock cycles between write attempts
)(
    input clock,
    input reset,
    input write,
    input [SCREEN_WIDTH_BIT_WIDTH + SCREEN_HEIGHT_BIT_WIDTH - 1 : 0] address,
    input [31:0] data
);

logic [23:0] screenBuffer [0 : SCREEN_WIDTH * SCREEN_HEIGHT - 1];
logic [31:0] write_counter;
logic buffer_modified;  // Modification flag
integer file_handle;

// Initialize memory
initial begin
    foreach (screenBuffer[i]) screenBuffer[i] = 24'b0;
    write_counter = 0;
    buffer_modified = 0;
end

// Main buffer and file control
always @(posedge clock) begin
    if (reset) begin
        // Reset memory and flags
        foreach (screenBuffer[i]) screenBuffer[i] = 24'b0;
        write_counter <= 0;
        buffer_modified <= 0;
    end
    else begin
        // Handle screen writes and track modifications
        if (write) begin
            screenBuffer[address] <= data[23:0];
            buffer_modified <= 1'b1;  // Set modification flag
        end

        // File writing logic (only when modified)
        write_counter <= write_counter + 1;
        if (write_counter >= WRITE_INTERVAL && buffer_modified) begin
            write_counter <= 0;
            file_handle = $fopen(SCREEN_FILE, "w");
            if (file_handle) begin
                foreach (screenBuffer[i]) begin
                    $fdisplay(file_handle, "%h", screenBuffer[i]);
                end
                $fclose(file_handle);
                buffer_modified <= 1'b0;  // Clear flag after successful write
            end
        end
    end
end

endmodule

Clone this wiki locally