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

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.

../../_images/wb_graphics_structure.svg

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.

../../_images/color_definition.svg

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.

../../_images/rgbi_palette.svg

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_column and vid_line are used to address pixels inside the buffer. Calculation of the buffer address is given by following equation:

address = (column / 16) + (line / 16) * 40
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. While vid_enable is disabled, zero will be output over vid_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_mode selects 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_enable forces 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_*_begin or vga_*_end. They do not change otherwise.

While enable is 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