Graphics
Author: Konrad Armbrecht 2025, Martin Erichsen 2025, Beaurel Ingride Ngaleu 2025
Overview
The graphics peripheral c_soft_graphics enables the PicoNut processor to output any graphical content. It enables the PicoNut to run applications that depend on an image output.
Interface Definition
Overview
The Graphics module serves as the display output for the Piconut, an open-source RISC-V processor. This module provides a set of registers that facilitate the control and management of graphics rendering within the system. The Graphics adapter contains several registers, which are described below.
While the implementation of hardware or software graphics does not necessarily require the use of every feature of each register, it is essential that all registers are defined. This ensures that developers have a clear understanding of the available components and their functionalities, providing security and flexibility when developing graphics applications for the Piconut system.
Register offsets
The memory map for the Graphics control registers is shown in the table below. The Graphics memory map has been designed to require only 32-bit memory accesses.
Offset |
Name |
Description |
|---|---|---|
0x000 |
CONTROL |
Can be used to control the graphic interface. |
0x004 |
STATUS |
General status register. |
0x008 |
RESOLUTION_MODE |
Set value to choose respective resolution mode in pixel. |
0x00C |
RESOLUTION_MODE_SUPPORT |
Read only. Stores supported resolution modes as a bitmask. Each bit represents a supported mode (1 = supported, 0 = unsupported). |
0x010 |
COLOR_MODE |
Read only. Set registers bits to choose respective color mode in bits per pixel. |
0x014 |
COLOR_MODE_SUPPORT |
Read only. Stores supported color modes as a bitmask. Each bit represents a supported mode (1 = supported, 0 = unsupported). |
0x018 |
FRAMEBUFFER |
Pointer to framebuffer memory in the piconut system. |
0x01C |
SCANLINE |
Register to identify the current position of image buildup. |
0x100 |
COLOR_MAP |
Range: 0x100 - 0x4ff. 256 registers for color values. |
Detailed register description
Note:
Attr. RW = Read and write
Attr. R = Read only
CONTROL Register
Register offset: 0x000
Can be used to control the graphic interface.
Bit |
Field name |
Attr. |
Description |
|---|---|---|---|
0 |
Interrupt |
RW |
Enable/disable Interrupt |
1 |
Output |
RW |
Enable/disable image output. |
STATUS Register
Register offset: 0x004
General status register for the graphic interface.
Bit |
Field name |
Attr. |
Description |
|---|---|---|---|
0 |
Ready |
R |
Indicates if the graphic interface is ready (0: not ready, 1: ready). |
1 |
Error |
R |
Indicates if there is an error (0: no error, 1: error occurred). |
2 |
Busy |
R |
Indicates if the graphic interface is busy (0: idle, 1: busy). |
RESOLUTION_MODE Register
Register offset: 0x008
Set register bit to choose respective resolution mode in pixel.
Bit |
Field name |
Attr. |
Description |
|---|---|---|---|
0 |
640x480 |
RW |
Resolution mode 640x480 pixel |
1 |
800x600 |
RW |
Resolution mode 800x600 pixel |
2 |
1024x768 |
RW |
Resolution mode 1024x768 pixel |
3 |
1280x720 |
RW |
Resolution mode 1280x720 pixel |
4 |
1920x1080 |
RW |
Resolution mode 1920x1080 pixel |
5 |
3x2 |
RW |
Resolution mode 3x2 pixel |
6 |
80x60 |
RW |
Resolution mode 80x60 pixel |
7 |
320x240 |
RW |
Resolution mode 320x240 pixel |
RESOLUTION_MODE_SUPPORT Register
Register offset: 0x00C
Read only. Stores supported resolution modes as a bitmask. Each bit represents a supported mode (1 = supported, 0 = unsupported).
Before requesting to set a certain resolution mode, check, if it is supported. E.g. if mode 0x10 is requested while only modes 0x0 (640x480) and 0x1 (800x600) are supported, an error will occur.
COLOR_MODE Register
Register offset: 0x010
Set register bit to choose respective color mode. For undefined color modes, it is the implementation’s responsibility to select appropriate entries from the COLOR_MAP.
COLOR_MAP: Address range 0x100 - 0x4FF contains 256 colors, with 4 bytes per entry.
Bit |
Field name |
Attr. |
Description |
|---|---|---|---|
0 |
1 Bit Monochrome |
RW |
Black and White only |
1 |
2-Bit Mapped |
RW |
4 colors from the COLOR_MAP |
2 |
2-Bit Grayscale |
RW |
4 levels of gray from the COLOR_MAP |
3 |
3-Bit Mapped |
RW |
8 colors from the COLOR_MAP |
4 |
3-Bit RGB |
RW |
1 bit per RGB channel: black, red, green, blue, cyan, magenta, yellow and white |
5 |
3-Bit Grayscale |
RW |
8 levels of gray from the COLOR_MAP |
6 |
4-Bit Mapped |
RW |
16 colors from the COLOR_MAP |
7 |
4-Bit RGBI |
RW |
4-bit RGBI is similar to the 3-bit RGB but adds one bit for dark/bright intensity, see CGA-standard |
8 |
4-Bit Grayscale |
RW |
16 levels of gray from the COLOR_MAP |
9 |
8-Bit Mapped |
RW |
All 256 colors from COLOR_MAP |
10 |
8-Bit RGB332 |
RW |
3 bits red, 3 bits green, 2 bits blue |
11 |
8-Bit Grayscale |
RW |
256 levels of gray: RGB(0, 0, 0) to RGB (255, 255 , 255) |
12 |
16-Bit RGB565 |
RW |
RGB565 Color mode with 16 bits per pixel: 5 bits red, 6 bits green, 5 bits blue. |
13 |
32-Bit RGB888 |
RW |
Color mode with 32 bits per pixel, uses 24-bit truecolor (RGB888) packed into a 32-bit format for memory alignment. The upper 8 bits (typically alpha in RGBA) are not being used, as transparency is not relevant in the context of direct image display. |
2-Bit Mapped: https://lospec.com/palette-list/galactic-pizza
Name |
Dark Magenta |
Magenta-rosa |
Yellow |
White |
|---|---|---|---|---|
Binary |
00 |
01 |
10 |
11 |
RGB |
#3A0041 |
#C477A2 |
#F2F18B |
#FFFFFF |
2-Bit Grayscale: https://lospec.com/palette-list/2-bit-grayscale
Name |
Black |
Dark Gray |
Light Gray |
White |
|---|---|---|---|---|
Binary |
00 |
01 |
10 |
11 |
RGB |
#000000 |
#676767 |
#B6B6B6 |
#FFFFFF |
4-Bit Mapped: https://lospec.com/palette-list/go-line
Name |
Dark Purple |
Dark Pink |
Bright Red |
Orange |
Yellow |
Light Green |
Dark Green |
Dark Blue |
Black |
Blue |
Light Blue |
Cyan |
Light Pink |
Grey |
Brown |
Dark Brown |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Binary |
0000 |
0001 |
0010 |
0011 |
0100 |
0101 |
0110 |
0111 |
1000 |
1001 |
1010 |
1011 |
1100 |
1101 |
1110 |
1111 |
RGB |
#430067 |
#94216A |
#FF004D |
#FF8426 |
#FFDD34 |
#50E112 |
#3FA66F |
#365987 |
#000000 |
#0033FF |
#29ADFF |
#00FFCC |
#FFF1E8 |
#C2C3C7 |
#AB5236 |
#5F574F |
COLOR_MODE_SUPPORT Register
Register offset: 0x014
Read only. Stores supported color modes as a bitmask. Each bit represents a supported mode (1 = supported, 0 = unsupported).
Before requesting to set a certain color mode, check, if it is supported. E.g. when trying to set resolution mode 0x10, but only 0x0 (640x480) and 0x1(800x600) is defined, an error will occur.
FRAMEBUFFER Register
Register offset: 0x018
Pointer to framebuffer memory in the piconut system.
SCANLINE Register
Register offset: 0x01C
Read only. Provides the current scanline index being rendered.
COLOR_MAP Register
Register offset: 0x100
Read only. The COLOR_MAP register range (0x100 - 0x4FF) consists of 256 registers for color values. Each entry is a 32-bit value representing a color, with the bits allocated for the RGB color channels. The layout is as follows:
0xUURRGGBB |
Description |
|---|---|
UU |
Unused |
RR |
Red |
GG |
Green |
BB |
Blue |
These registers are optional and depend on the supported color modes of the hardware. They are necessary, when using a mapped color mode. Each entry in the COLOR_MAP is structured as a 32-bit value, where the bits are allocated for the RGB color channels. Specifically, the layout is as follows:
Example use:
Hex (ARGB) |
RGB Decimal |
Color |
|---|---|---|
0x00FF0000 |
(255, 0, 0) |
Red |
0x0000FF00 |
(0, 255, 0) |
Green |
0x000000FF |
(0, 0, 255) |
Blue |
Practical Access
The COLOR_MAP is used by setting the corresponding color index in color modes that map directly to the color table. For example, in a 2-bit color mode, you could access the first four colors with COLOR_MAP[index] as follows:
0 = Black(0x00000000)1 = White(0x00FFFFFF)2 = Red(0x00FF0000)3 = Green(0x0000FF00)
In higher bit modes (e.g., 8-bit), you can access up to 256 colors from the COLOR_MAP. A specific color is referenced by its index, and the respective color value is retrieved from the corresponding COLOR_MAP entry.
Soft Graphics
- group c_soft_graphics
This module is used to simulate the graphics peripheral. The module is implemented as a soft peripheral and can be used in the simulation environment.
- Author
Konrad Armbrecht
The module has a register for storing the output-images, called framebuffer. The framebuffer is set up as a single large array where all output-image lines are stored successively. The size is calculated by width and height given from the constructor. With a 10 × 10 px resolution, you have 100 array elements, and the framebuffer[10] element is the first pixel of the second output-image line. The module has a 32-bit memory interface and can be accessed by the soft peripheral interface.
Note: The module is not synthesizable and is only used for simulation purposes.
Registers
-
struct regs_t
Registers of the c_soft_graphics module.
-
enum c_soft_graphics::e_regs
Register address offsets.
Values:
-
enumerator CONTROL = 0x0
-
enumerator WIDTH = 0x4
-
enumerator HEIGHT = 0x8
-
enumerator RESOLUTION_MODE = 0xC
-
enumerator RESOLUTION_MODE_SUPPORT = 0x10
-
enumerator COLOR_MODE = 0x14
-
enumerator COLOR_MODE_SUPPORT = 0x18
-
enumerator FRAMEBUFFER = 0x1C
-
enumerator CONTROL = 0x0
Functions
-
c_soft_graphics::c_soft_graphics(uint64_t base_address, ResolutionMode resolution_mode, ColorMode color_mode, uint32_t clock_frequency, void (*flush_func)(uint32_t *framebuffer, uint32_t framebuffer_size_in_px), std::function<void(bool)> callback_signal_graphics_interrupt = nullptr)
Constructor.
- Parameters:
base_address – base address of the peripheral in the address space of the simulation
resolution_mode – resolution mode (recommended for performance reasons: “1” -> 60x80 px)
color_mode – color depth in bits per pixel (here only “4” is implemented -> 32 bit)
clock_frequency – maximum value for interrupt counter
flush_func – Callback function to flush the framebuffer to GUI.
callback_signal_graphics_interrupt – Callback function to signal graphics interrupts.
-
c_soft_graphics::~c_soft_graphics()
Destructor.
-
void c_soft_graphics::flush_graphics(void (*flush_to_gui)(uint32_t*, uint32_t), uint32_t framebuffer_size)
Flushes the graphics framebuffer using the provided callback function.
- Parameters:
flush_to_gui – Callback function to send framebuffer data to the GUI.
framebuffer_size – Size of the framebuffer in pixels.
-
void c_soft_graphics::register_meip_callback(std::function<void(bool)> callback)
Register a callback function for graphics interrupt changes.
- Parameters:
callback – The callback function
-
void c_soft_graphics::on_rising_edge_clock() override
Triggers interrupts when max_counter value is reached. This function is automatically called on every rising edge of the clock.
-
void c_soft_graphics::clear_framebuffer()
How to make use of the Graphics module
Create a pointer to the graphics module:
volatile uint32_t* graphics = (uint32_t*)0x40000000;
Read the framebuffer size:
int width = *(graphics + 0x1);
int height = *(graphics + 0x2);
int framebuffersize = width * height;
Now you can write pixel in hex-RGB color format to the framebuffer:
for (int i = 0; i < framebuffersize; i++) {
*(graphics + 0x7 + i) = 0x00123456;
}
See sw/apps/graphics_fancy_random_squares/graphics_fancy_random_squares.c for more details on that example.
Global config
Graphics-related settings in global config file /hw/piconut/config.mk
CFG_GRAPHICS_BASE_ADDRESS = 0x40000000
Defines the memory address of the graphics peripheral in the simulator address space.
Hardware Graphics
The wb_graphics peripheral offers an interface to external monitors. Currently, output via a VGA compatible interface at an resolution of 640x480 is supported. A wishbone interface gives access to control and status registers, as well as access to the internal framebuffer. Following figure shows the structure of this peripheral. It is designed around a streaming pipeline. Video signals flow unidirectional from source (e.g. internal framebuffer ) to sink modules (e.g. VGA signal generator). Controlled by the line/column counter, it outputs a continuous stream of pixels.
Fig. 36 Structure of the wb_graphics peripheral.
Color Modes
This peripheral supports several color modes shown in the table below. The color translator module interprets colors according to this table.
Fig. 37 Table of color mode definitions.
The 4 bit RGBI mode is similar to the 3 bit RGB mode, with an additional bit to select between two color intensities. Its 16 colors are shown in the figure below.
Fig. 38 4 bit RGBI color palette
Modules
Framebuffer
-
SC_MODULE(m_framebuffer_source)
Video source module with internal framebuffer.
The framebuffer source generates a video signal from an internal framebuffer. It offers two seperate interfaces for interaction with the system and video output, each driven by their own clocks.
- Author
Martin Erichsen
The system-side port offers a read/write interface to the internal framebuffer.
From the video-side port,
vid_columnandvid_lineare used to address pixels inside the buffer. Calculation of the buffer address is given by following equation:This results in a fixed upscaling factor of 16 and a maximum column address of 639. Column addresses greater than 639 wrap over to the next line. Whileaddress = (column / 16) + (line / 16) * 40
vid_enableis disabled, zero will be output overvid_output.Generation of the video signal requires one clock cycle.
- Ports:
- Parameters:
ctl_clk – [in] system-side clock input
ctl_reset – [in] system-side reset
ctl_addr – [in] system-side buffer address
ctl_data_in – [in] system-side buffer write data
ctl_data_out – [out] system-side buffer read data
ctl_write_en – [in] system-side buffer write enable
vid_clk – [in] video-side clock input
vid_enable – [in] video-side output enable
vid_column – [in] video-side horizontal address
vid_line – [in] video-side vertical address
vid_output – [out] video-side video output
-
SC_MODULE(m_framebuffer_ram)
Dual port RAM block for use as internal framebuffer.
The framebuffer RAM is a dual port RAM based on the Dual Port Block RAM template.
- Author
Martin Erichsen
Each port provides an interface for reading and writing into the memory. To read from the memory, an address must be set and enable must be activated. Additionally, for write access, input data must be provided and write enable must be set.
Its size can be changed using the configuration variable
CFG_WB_GRAPHICS_FB_SIZE.When synthesizing, this module is replaced by a verilog implementation held in a separate file.
- Ports:
- Parameters:
clka – [in] clock input for port A
wea – [in] write enable for port A
ena – [in] enable bram for port A
addra – [in] address for port A
dia – [in] data in for port A
doa – [out] data out for port A
clkb – [in] clock input for port B
web – [in] write enable for port B
enb – [in] enable bram for port B
addrb – [in] address for port B
dib – [in] data in for port B
dob – [out] data out for port B
Color Translator
-
SC_MODULE(m_color_translator)
The module translates an input color to 24-bit RGB. color_out[23:16], color_out[15:8], color_out[7:0] correspond to the 8-bit wide red, green and blue components respectively.
color_modeselects the input color’s format.- Author
Martin Erichsen
Conversion requires one clock cycle.
Color map modes are currently not supported and output black (0x000000).
- Ports:
- Parameters:
clk – [in] clock of the module
reset – [in] reset of the module
color_mode – [in] color mode of the input color
color_in – [in] input color
color_out – [out] output color as 24-bit RGB
VGA Signal Generator
-
SC_MODULE(m_vga_color_generator)
Generator for VGA compatible 4-bit wide color.
Generates 4-bit wide red, green and blue signals from a 24-bit RGB signal for with 4-bit video DACs.
blank_enableforces the output to black (all three channels to 0).- Authors
Beaurel I. Ngaleu
- Author
Martin Erichsen
Requires one clock cycle to output.
- Ports:
- Parameters:
clk – [in] clock of the module
reset – [in] reset of the module
blank_enable – [in] enable output blanking
video_in – [in] input color
vga_red – [out] 4-bit red channel intensity
vga_green – [out] 4-bit green channel intensity
vga_blue – [out] 4-bit blue channel intensity
-
SC_MODULE(m_vga_sync_generator)
Generator for VGA compatible hsync and vsync signals.
Outputs horizontal and vertical sync signals. Both hsync and vsync are inverted, so they are at logic 0 when asserted during synchronization and logic 1 otherwise.
- Author
Martin Erichsen
Either sync signal is asserted or deasserted the next clock cycle their address value matches
vga_*_beginorvga_*_end. They do not change otherwise.While
enableis not set, both sync signals are forced to deasserted state on the next clock cycle.- Ports:
- Parameters:
clk – [in] clock of the module
reset – [in] reset of the module
vga_hsync_begin – [in] horizontal address to assert hsync after
vga_hsync_end – [in] horizontal address to deassert hsync after
vga_vsync_begin – [in] vertical address to assert vsync after
vga_vsync_end – [in] vertical address to deassert vsync after
enable – [in] synchronous enable
column – [in] current column coutner address
line – [in] current line counter address
vga_hsync – [out] horizontal synchronization signal
vga_vsync – [out] vertical synchronization signal
VGA Timing Table
-
SC_MODULE(m_vga_timings)
Video timing configuration lookup table.
Outputs a timing configuration selected by
resolution_mode. Currently, only a resolution of 640x480 at pixel clock of 25 MHz is supported.- Author
Martin Erichsen
This module has no clock, lookup is done combinatorically.
- Ports:
- Parameters:
resolution_mode – [in] active resolution mode
vid_column_active – [out] number of active pixels on a video line
vid_column_end – [out] total number of pixels on a video line
vid_line_active – [out] number of active lines in a video frame
vid_line_end – [out] total number of pixels in a video frame
vga_hsync_begin – [out] horizontal address to assert hsync after
vga_hsync_end – [out] horizontal address to deassert hsync after
vga_vsync_begin – [out] vertical address to assert vsync after
vga_vsync_end – [out] vertical address to deassert vsync after
Demo Image Source
-
SC_MODULE(m_demo_image_source)
Generates a demo image.
Requires one clock cycle to output.
- Author
Beaurel I Ngaleu
- Ports:
- Parameters:
clk – [in] clock of the module
reset – [in] reset of the module
vid_enable – [in] video output enable
vid_column – [in] video horizontal address
vid_line – [in] video vertical address
vid_output – [out] video output
wb_graphics
-
SC_MODULE(wb_graphics_modul)
This module connects several subsystems such as Wishbone control, framebuffer, VGA sync generator, color generator, and timing logic into a complete video system.
- Author
Beaurel I. Ngaleu
- Ports:
- Parameters:
clk – [in] Main clock signal
reset – [in] Global reset signal
enable – [in] Module enable signal
clk_wishbone – [in] Clock for the Wishbone interface
wb_stb_i – [in] Wishbone strobe input
wb_we_i – [in] Wishbone write enable input
wb_cyc_i – [in] Wishbone cycle signal
wb_sel_i – [in] Wishbone byte select signal
wb_ack_o – [out] Wishbone acknowledge output
wb_err_o – [out] Wishbone error output
wb_rty_o – [out] Wishbone retry output
wb_adr_i – [in] Wishbone address input
wb_dat_i – [in] Wishbone data input
wb_dat_o – [out] Wishbone data output
fb_addr – [out] Framebuffer address bus
fb_write_en – [out] Write enable for framebuffer
fb_data_read – [in] Data read from the framebuffer
fb_data_write – [out] Data written to the framebuffer
reg_control – [out] Control register
reg_status – [in] Status register
reg_line – [in] Current line from the status module
reg_resolution_mode – [out] Selected video resolution mode
reg_resolution_mode_support – [in] Supported resolution modes
reg_color_mode – [out] Selected color mode
reg_color_mode_support – [in] Supported color modes
ctl_reset – [in] Reset signal for framebuffer access control
ctl_addr – [in] Address for framebuffer control access
ctl_data_in – [in] Input data for write operations
ctl_data_out – [out] Output data from read operations
ctl_write_en – [in] Write enable signal for control access
vid_clk – [in] Clock for video signal processing
vid_enable – [in] Enable signal for active video area
vid_column – [in] Current column (x position)
vid_line – [in] Current line (y position)
vid_output – [out] Current pixel data (e.g., color) from framebuffer
vga_red – [out] Red color component output (4-bit)
vga_green – [out] Green color component output (4-bit)
vga_blue – [out] Blue color component output (4-bit)
vga_hsync – [out] Horizontal sync signal
vga_vsync – [out] Vertical sync signal
vga_hsync_begin – [in] Start of horizontal sync phase
vga_hsync_end – [in] End of horizontal sync phase
vga_vsync_begin – [in] Start of vertical sync phase
vga_vsync_end – [in] End of vertical sync phase
column – [in] Current column position for sync generation
line – [in] Current line position for sync generation
resolution_mode – [in] Video resolution mode
column_timing_end – [out] End of horizontal visible area
column_timing_active – [out] Active horizontal display area
line_timing_end – [out] End of vertical visible area
line_timing_active – [out] Active vertical display area
vga_hsync_timing_begin – [out] Timing of horizontal sync start
vga_hsync_timing_end – [out] Timing of horizontal sync end
vga_vsync_timing_begin – [out] Timing of vertical sync start
vga_vsync_timing_end – [out] Timing of vertical sync end
vid_column_end – [in] Last column (maximum horizontal counter value)
vid_line_end – [in] Last line (maximum vertical counter value)
vid_column_active – [in] Visible horizontal area
vid_line_active – [in] Visible vertical area
vid_line_column – [out] Current column counter output
vid_line_line – [out] Current line counter output
vid_line_enable – [out] Enable signal for visible video data
clk_color_translator – [in] Clock for color translation module
color_mode – [in] Color mode (e.g., RGB888, RGB444, etc.)
color_in – [in] Input color value
color_out – [out] Translated output color value (e.g., RGB888)
wb_slave
-
SC_MODULE(m_wb_slave)
The “wb_slave” serves as the central interface for control and communication via the Wishbone bus. It enables reading and writing of register values or memory data within the wb_graphics_module. It responds to bus accesses to execute internal control functions (e.g., framebuffer accesses).
- Author
Beaurel I. Ngaleu
- Ports:
- Parameters:
clk – [in] clock of the module
reset – [in] reset of the module
wb_adr_i – [in] Wishbone Adress input
wb_dat_o – [out] Wishbone Data out
wb_dat_i – [in] Wishbone Data in
wb_we_i – [in] Wishbone Write-Enable in
wb_stb_i – [in] Wishbone Strobe in
wb_cyc_i – [in] Wishbone Cycle in
wb_we_i – [in]
wb_ack_o – [out] Wishbone ACK input
wb_cti_i – [in] // Wishbone cycle type identifier (optional, for registered feedback)
wb_bte_i – [in] // Wishbone burst type extension (optional, for registered feedback)
wb_error_o – [out] // Wishbone termination w/ error (optional)
wb_rty_o – [out] // Wishbone termination w/ retry (optional)
reg_control – [out] Register zur Steuerung
reg_status – [in] Statusregister
reg_line – [in] Aktuelle Zeile aus Statusmodul
reg_resolution_mode – [out] Ausgewählter Auflösungsmodus
reg_resolution_mode_support – [in] Unterstützte Auflösungen
reg_color_mode – [out] Ausgewählter Farbmodus
reg_color_mode_support – [in] Unterstützte Farbmodi