Inspiration

I wanted to strengthen my understanding of digital hardware design by building a graphics accelerator from scratch. I was particularly interested in how GPUs translate drawing commands into pixel operations and how hardware designs can be verified through simulation without a physical FPGA.

What it does

It is a small 2D graphics accelerator built in SystemVerilog. It accepts rectangle commands, clips pixels outside a 64×64 display, and writes RGB332 pixel values into a framebuffer.

A Python renderer reads the simulated framebuffer and converts it into enlarged PNG images, including "CAL HACKS," a checkerboard, and vertical stripes.

How I built it

The hardware is divided into three SystemVerilog modules:

  • draw_engine: Converts rectangle commands into pixel-write transactions using an FSM and coordinate counters.
  • framebuffer: Stores pixel colors in a 64×64 memory array with synchronous read and write operations.
  • gpu_top: Integrates the drawing engine and framebuffer into a complete system.

I used Icarus Verilog for simulation and cocotb for module-level and system-level verification. Python reference models validate the framebuffer contents, while Pillow converts RGB332 pixel data into RGB888 PNG images.

Challenges I ran into

One of the biggest challenges was understanding clock-cycle timing and synchronization between modules.

Commands are accepted through a valid/ready handshake, framebuffer reads are synchronous, and the final pixel must be written at the same clock edge that transitions the drawing engine into its completion state.

I also had to account for out-of-bounds clipping, zero-sized rectangles, and uninitialized framebuffer memory when designing the verification tests.

Accomplishments that I'm proud of

I implemented and tested a complete graphics pipeline, from receiving a drawing command to generating pixel writes, storing colors in memory, and rendering the resulting image.

My verification environment covers boundary conditions, maximum-size rectangles, reset behavior, command handshaking, and randomized rectangle operations.

I also successfully generated visual outputs entirely from simulated hardware behavior, without requiring a physical FPGA.

What I learned

I strengthened my understanding of SystemVerilog FSMs, counters, synchronous memory, framebuffer addressing, and hardware module integration.

I also gained practical experience with cocotb verification, Python reference models, and debugging clock-cycle timing issues.

Most importantly, I learned how to approach a larger RTL project by breaking it into independently testable modules before integrating them into a complete system.

What's next for 2-D Graphics Accelerator

I plan to expand this project with additional graphics operations, such as DRAW_PIXEL, CLEAR_SCREEN, line rasterization, and sprite rendering.

I also want to develop a reusable cocotb verification framework that can support future RTL projects.

Eventually, I plan to synthesize it for an FPGA, evaluate resource utilization and timing, and implement a display controller capable of showing the framebuffer output in real time.

Built With

Share this project:

Updates

Submission history