Platform

Introduction

A modern development platform for FPGA applications, combining expressive hardware programming with reusable libraries, integrated testing, and AI-assisted development.

Livt brings modern software engineering practices to FPGA development through a hardware-native programming language and an integrated development platform. It combines expressive abstractions, reusable libraries, package management, automated testing, and AI-assisted workflows. Developers can build sophisticated FPGA applications while retaining control over timing, concurrency, and hardware resources. The compiler generates readable, synthesizable HDL that integrates with established FPGA toolchains.

Background and Motivation

The motivation for Livt grew out of my own experience developing FPGA systems. FPGAs have always fascinated me because of what they make possible. Yet turning an idea into a working design often felt more restrictive than it should. I could imagine the application, but too much of the work went into rebuilding or adapting its foundations before I could explore the idea itself.

Reuse was a particular frustration. Bringing a working component into another project often meant changing it to fit a different configuration, interface, or timing environment. Those changes brought another round of verification. Even when I began with something proven, it often felt as though I was starting again.

My perspective comes from working across hardware engineering, software engineering, and language design. Hardware taught me to respect timing, concurrency, finite resources, and the physical consequences of every abstraction. Software taught me the value of clear boundaries, reusable libraries, focused tests, and code that communicates intent. It also broadened my sense of what becomes possible when a project can build on established capabilities rather than repeatedly implementing its foundations.

Some complexity is essential to hardware engineering. Timing, concurrency, memory architecture, clock domains, and resource constraints cannot simply disappear behind an abstraction. Other complexity arises from the languages, tools, and workflows we use. Much FPGA development involves demanding but repetitive work: implementing familiar protocols, connecting buses, managing buffers, and adapting existing components. These tasks require care, but their underlying solutions are often well understood. I wanted to reduce this accidental complexity without losing control over the hardware decisions that matter.

In software, design patterns had taught me how to separate what a component promises from how it fulfils that promise. They offered ways to replace an implementation, supply a different policy, or adapt an interface without rewriting the code that used it. What mattered was not the pattern's name, but the ability to accommodate change while keeping the rest of the design stable. HDL could describe the circuit I needed, but I often struggled to express that same flexibility in a form that remained convenient to compose and reuse.

A protocol handler, for example, should not need to change simply because its buffer moves from registers to block RAM, provided the replacement satisfies the agreed timing and access requirements. How much must be rewritten and reverified when a requirement changes? That question reveals the quality of a design's boundaries.

My approach to language design grows from these experiences. Repeated solutions reveal patterns; patterns suggest APIs; APIs mature into libraries and frameworks. Some concepts eventually become clear and general enough to deserve language support. A good programming language should not require developers to repeatedly express implementation details that can be reliably derived from their intent. Those details can become the responsibility of the compiler or reusable libraries, allowing source code to remain closer to the problem being solved.

In FPGA workflows, packaged IP often becomes the main unit of reuse. It serves system integration well, but I also want to reuse the algorithms, contracts, and composition patterns from which those blocks are built. IP can remain an output of development without becoming its abstraction ceiling.

Over time, I began to realise that the most interesting consequence of better abstractions was not simply writing less code or completing projects faster. It was the possibility of building things I would previously have considered too expensive or time-consuming to attempt.

In software, higher-level languages, libraries, and frameworks did more than improve productivity. They changed what developers could realistically build. Established capabilities became the foundations of increasingly sophisticated applications. I wanted to explore whether FPGA development could evolve in a similar direction. What happens when networking, storage, numerical processing, or machine-learning algorithms become reusable capabilities rather than substantial projects in their own right? What becomes possible when developers can begin with an application and descend into its hardware architecture only where the requirements demand attention?

This is the broader ambition behind Livt: to make application development on FPGAs practical without sacrificing the control and predictability that make programmable hardware valuable.

These experiences led to the question behind Livt: how can a language let developers focus on what their design should do, while giving them control over how it is implemented when that matters?

Straightforward behaviour should need straightforward code. The compiler should handle routine implementation choices while keeping their timing and resource implications understandable. Where tighter requirements demand precise sequencing, storage, or resource sharing, the code should become more explicit. Livt gives familiar programming constructs a hardware meaning: components operate concurrently, combinational calculations describe logic, and scheduled behaviour becomes clocked control. Explicit states make sequencing visible where necessary. The goal is not to hide hardware, but to express it at an appropriate level while retaining the ability to inspect and control the resulting implementation.

Development Approach

Supporting this approach requires more than a language. Versioned packages, automated tests, continuous integration, and a connected development workflow allow capabilities to accumulate and evolve rather than being copied and adapted for each new project. Livt fits into that workflow: source and tests live together in version control, package dependencies make reuse explicit, and automated builds provide repeatable feedback as a design changes.

Another part of this workflow has become increasingly important: AI-assisted development.

Large language models can generate substantial amounts of code, but generating code faster does not necessarily reduce the complexity of engineering. The language in which a design is expressed has a significant influence on what a model can understand and reliably implement. Clear semantics, concise constructs, explicit contracts, and reusable abstractions reduce the amount of implementation detail a model must reason about. They allow an AI agent to work with meaningful components and their relationships rather than repeatedly constructing low-level implementation machinery.

Combined with automated tests, package management, and deterministic compiler behaviour, these abstractions also provide a way for agents to validate and refine their work through repeated build-and-test cycles. AI assistance can therefore extend beyond code generation to implementing reusable components, exploring alternatives, and developing increasingly sophisticated applications. Developers remain responsible for requirements, architecture, critical hardware decisions, and verification. Livt provides a structured environment in which humans and AI agents can collaborate at a level closer to the intended design.

Together, higher-level abstractions, reusable libraries, integrated development workflows, and AI assistance change the cost of experimentation. They allow more effort to go into deciding what to build rather than repeatedly implementing the same foundations. The essential challenges of hardware engineering remain, but they can be addressed where they become relevant instead of dominating every stage of development.

This documentation introduces Livt from that perspective. Start with a small component and its test in your first project, then explore when operations execute, which clocks govern them, and what hardware they require. From there, learn to compose components, define reusable contracts, and make timing and resource choices explicit. The documentation also covers packages and reuse, vendor integration, automated workflows, and AI-assisted development.

My hope is that this documentation will help you understand the hardware you create without requiring you to start every design at its lowest level. More importantly, I hope it encourages you to explore applications that previously seemed too complex or too costly to build on an FPGA.

The best way to understand Livt is to build a small component and see it run. Continue with Hello, Livt! to write your first design, test its behavior, and explore the generated hardware.