A retro-style FPGA-based microcomputer. The microcomputer serves as a platform for software and RTL experimentation.

Public Chat
Similar projects worth following
BoxLambda is an open-source project with the goal of creating a retro-style FPGA-based microcomputer. The microcomputer serves as a platform for software and RTL experimentation.

BoxLambda is a software-hardware cross-over project. The plan is to provide room for experimentation both on the FPGA RTL side and on the software side.

Key Goals

  • Create a sandbox for experimenting with software and (FPGA) HW.

    • Simplicity: It should be easy to jump in and do something: create, hack, tinker.
      • It should be doable for a single person to develop a good understanding of the entire system, software and hardware.
      • Deterministic Behavior: By design, it should be clear how long an operation, be it an instruction or a DMA transfer, is going to take.
      • Single User/Single Tasking OS booting to a console shell.
    • Create a Modular Architecture allowing for a mix-and-match of software and hardware components.
      • Support for partial FPGA reconfiguration.
  • Target Hardware is Digilent's Arty-A7 and/or the Nexys-A7.

  • The computer should support the following peripherals:

    • Keyboard
    • Mouse (optional)
    • Joystick (optional)
    • Serial port
    • SD card storage
    • VGA Display
    • Audio output
  • Sound and graphics should be sufficient to support retro-style 2D gameplay.

I'm keeping a project Blog and documentation here.

  • On USB HID, Keyboard LEDs, and device emulation.

    Epsilon03/12/2024 at 16:37 0 comments
  • The Interconnect, Harvard Architecture, and Dual Port RAM.

    Epsilon01/06/2024 at 12:09 0 comments
  • An attempt at a PicoRV32-based Soft DMA Controller - Optimizations.

    Epsilon11/14/2023 at 12:00 0 comments
  • An attempt at a PicoRV32-based Soft DMA Controller.

    Epsilon10/21/2023 at 08:40 0 comments
  • Chiptunes! A Dual YM2149 PSG Audio core for BoxLambda.

    Epsilon08/19/2023 at 11:49 0 comments
  • Post-Implementation Memory Updates.

    Epsilon06/18/2023 at 13:55 0 comments
  • Bringing up the SD-Card Controller and File System.

    Epsilon05/12/2023 at 13:05 0 comments

    I added an SD-Card Controller and File System to BoxLambda:

  • Integrating VERA

    Epsilon04/20/2023 at 12:25 0 comments

    I integrated the VERA Versatile Embedded Retro Adapter into the BoxLambda SoC. The Blog post below discusses the changes I made to the VERA core to interface it with a 32-bit system. ... ting-vera/

  • Building Software and Gateware with CMake and Bender.

    Epsilon02/14/2023 at 21:39 0 comments


    This is a summary of the current state of affairs for BoxLambda. We have:

    • An Ibex RISC-V core, a Wishbone shared bus, a Debug Core, internal memory, a timer, two GPIO ports, and a UART core.
    • A Picolibc-based standard C environment for software running on the Ibex RISC-V core.
    • Test builds running on Arty-A7-35T and Verilator.
    • Automated testing on Verilator.
    • OpenOCD-based Debug Access, both on FPGA and Verilator.
    • A Linux GNU Makefile and Bender-based RTL build system.
    • DDR3 external memory access through the Litex Memory Controller.

    The Case for CMake

    Around the time I integrated Picolibc into BoxLambda it became clear that I needed to invest a bit more energy in BoxLambda’s build system. The build system was based on a simple set of GNU Make rules and Bender manifests. It worked reasonably well for Verilator and FPGA synthesis, but there were a few limitations that were starting to hurt. Specifically, I wanted to add the following features to the build system:

    • Proper dependency tracking for software: The old build system used forced build rules. Every software build was a full rebuild. The improved build system should use incremental builds with proper dependency tracking from memory files to executables, to libraries, and sources.
    • Proper dependency tracking for RTL: Implementation and bitstream generation depends on synthesis. Synthesis depends on HDL sources, constraints files, and memory files. Memory files depend on software.
    • Out-of-Tree build trees: Out-of-Tree build trees are way more convenient than In-Tree build trees. You can create as many of them as you want, they’re easy to remove when you no longer need them, and the derived objects don’t clutter up your source tree.
    • Support for build options: I want to be able to specify whether the build tree is to be used for simulation builds, or for FPGA synthesis.
    • Support for different FPGA targets: Arty-A7-35T and Arty-A7-100T to begin with.

    I thought this would be a good opportunity to try out Meson, a modern build system generator with a clean, elegant python-like syntax. The Meson experiment came to a halt pretty quickly, however. I just couldn’t get my head around the fact that the Meson DSL does not include functions or macros. I ended up with a bunch of virtually identical files because I didn’t have a way to abstract common patterns. You can take a look at BoxLambda’s meson branch if you’re interested.

    I decided to switch over to CMake. Compared to Meson, CMake has a more cluttered, messy syntax, but it is more flexible. It has functions, macros, and all the other goodies you can expect of a build system generator:

    • Easy dependency tracking.
    • Support for Out-of-Tree builds.
    • Support for build options.
    • Support for automated testing.
    • Configure-Time source code generation.

    This is the first time I’m using a build system generator. I always got by with GNU Make itself. Now that I that I tried CMake, I have to say that I like it a lot. It’s almost like going from assembly language to C. I probably could have implemented all the build system features I wanted directly in GNU Make, but it’s so much easier in CMake.

    Sidenote: Gateware

    I first encountered the term Gateware in the LiteX project.

    Gateware comprises the description (of behaviour, structure and/or connections) of digital logic gates, a high level abstraction thereof, and/or the implementation thereof in (re)configurable logic devices (such as FPGAs and ASICs).

    I think the term covers its meaning very well and it’s the perfect counterpart for software. I’ll be using it from here on out.

    The Directory Structure

    <BoxLambda Root Directory>
    ├── CMakeLists.txt
    ├── sub/
    │   └── <git submodules>
    ├── gw/
    │   ├── CMakeLists.txt
    │   ├── components/
    │   │   ├── CMakeLists.txt
    │   │   ├── wbuart32/
    │   │   │   ├── rtl/
    │   │   │   ├── CMakeLists.txt
    │   │   │   └── Bender.yml
    │   │   └── <other gw component directories>
    │   └── projects/
    Read more »

  • Exit MIG, Enter LiteDRAM.

    Epsilon12/29/2022 at 09:50 0 comments

    LiteDRAM in the BoxLambda Architecture.

    LiteDRAM in the BoxLambda Architecture.

    Initially, the plan was to use Xilinx’s MIG (Memory Interface Generator) to generate a DDR Memory Controller for Boxlambda. At the time, that was (and maybe still is) the consensus online when I was looking for memory controller options for the Arty A7. Meanwhile, Reddit user yanangao suggested I take a look at project LiteX for a memory controller. I took the advice and started playing around a bit with Litex. One thing led to another and, long story short, BoxLambda now has a DDR memory controller based on LiteDRAM, a core of the LiteX project. If you’re interested in the longer story, read on.


    This is a summary of the current state of BoxLambda. We have:

    • An Ibex RISCV core, a Wishbone shared bus, a Debug Core, internal memory, a timer, two GPIO ports, and a UART core.
    • A Picolibc-based standard C environment for software running on the Ibex RISCV core.
    • Test builds running on Arty-A7-35T and Verilator.
    • Automated testing on Verilator.
    • OpenOCD-based Debug Access, both on FPGA and on Verilator.
    • A Linux Makefile and Bender-based RTL build system.

    LiteX and LiteDRAM

    LiteX is an Open Source SoC Builder framework for FPGAs. You specify which CPU, memory, interconnect, and peripherals you want. The framework then generates the SoC and the software to go along with it. Here’s an example (with semi-randomly picked settings):

    python3 --bus-standard wishbone --bus-data-width 32 --bus-interconnect crossbar --cpu-type rocket --integrated-sram-size 32768 --with-ethernet --with-sdcard --sys-clk-freq 50000000 --build --load
    INFO:S7PLL:Creating S7PLL, speedgrade -1.
    INFO:S7PLL:Registering Single Ended ClkIn of 100.00MHz.
    INFO:S7PLL:Creating ClkOut0 sys of 50.00MHz (+-10000.00ppm).
    INFO:S7PLL:Creating ClkOut1 eth of 25.00MHz (+-10000.00ppm).
    INFO:S7PLL:Creating ClkOut2 sys4x of 200.00MHz (+-10000.00ppm).
    INFO:S7PLL:Creating ClkOut3 sys4x_dqs of 200.00MHz (+-10000.00ppm).
    INFO:S7PLL:Creating ClkOut4 idelay of 200.00MHz (+-10000.00ppm).
    INFO:SoC:        __   _ __      _  __
    INFO:SoC:       / /  (_) /____ | |/_/
    INFO:SoC:      / /__/ / __/ -_)>  <
    INFO:SoC:     /____/_/\__/\__/_/|_|
    INFO:SoC:  Build your hardware, easily!
    INFO:SoC:Creating SoC... (2022-12-19 16:28:38)

    … and off it goes. That single command generates, synthesizes and loads the SoC onto your Arty A7.

    LiteX is written in Migen, a Python-based tool that automates further the VLSI design process, to quote the website. At the heart of Migen sits FHDL, the Fragmented Hardware Description Language. FHDL is essentially a Python-based data structure consisting of basic constructs to describe signals, registers, FSMs, combinatorial logic, sequential logic etc. Here’s an example:

            aborted = Signal()        offset  = base_address >> log2_int(port.data_width//8)
            self.submodules.fsm = fsm = FSM(reset_state="CMD")        self.comb += [            port.cmd.addr.eq(wishbone.adr - offset),            port.cmd.we.eq(wishbone.we),            port.cmd.last.eq(~wishbone.we), # Always wait for reads.            port.flush.eq(~wishbone.cyc)    # Flush writes when transaction ends.        ]        fsm.act("CMD",            port.cmd.valid.eq(wishbone.cyc & wishbone.stb),            If(port.cmd.valid & port.cmd.ready &  wishbone.we, NextState("WRITE")),            If(port.cmd.valid & port.cmd.ready & ~wishbone.we, NextState("READ")),            NextValue(aborted, 0),        )        self.comb += [            port.wdata.valid.eq(wishbone.stb & wishbone.we),            If(ratio <= 1, If(~fsm.ongoing("WRITE"), port.wdata.valid.eq(0))),  ,            port.wdata.we.eq(wishbone.sel),        ]

    You can more or less see the Verilog equivalent. However, the fact that this is a Python data structure means that you have Python at your disposal as a meta-language to combine and organize these bits of HDL. This is a huge increase in abstraction and expressiveness, and it explains how LiteX can do what it does. The flexibility...

    Read more »

View all 25 project logs

Enjoy this project?



Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates