Toolchain integration

Vendor Integration

Vendor project handoff, synthesis boundaries, wrappers, constraints, timing, and release artifacts.

Livt projects can enter existing FPGA and ASIC toolchains while keeping the design boundary clear and reviewable. Vendor integration is about creating a clean handoff: source code stays in Livt, tests stay available for simulation, and vendor-specific project files live in a predictable workspace.

Build Artifacts

The normal flow is:

  1. Write Livt source.
  2. Build the project.
  3. Run simulation.
  4. Create vendor project files.
  5. Open the vendor project for synthesis, implementation, packaging, or downstream integration.

The livt vendor command creates vendor integration files under .livt/vendor. This folder is the workspace for generated project scripts, openable vendor projects, logs, and packaged output.

Treat .livt/vendor as generated workspace, not hand-maintained source. Keep Livt source, custom wrappers, constraints, and configuration under version control and regenerate the workspace from those inputs.

bash
livt vendor vivado
livt vendor vivado-ip

Both Vivado templates show a configuration overview before the vendor tool is launched. This makes it clear which template, part, top, wrapper, and test settings are being used.

Synthesis Boundaries

Keep synthesizable design code separate from test and simulation code. A source component should avoid simulation-only APIs unless it is explicitly not part of the synthesis path.

Good boundaries make vendor integration simpler:

  • src/ contains design code
  • tests/ contains test components and simulation scenarios
  • top-level constructors expose clear physical signals
  • interfaces group protocol signals
  • top-level ports are easy to review

Top-Level Components

The top-level component is the bridge to the vendor project. Keep its constructor clear and hardware-facing:

livt
component Top
{
    app: AppCore

    new(clk: clock, rst: reset, rx: in logic, tx: out logic)
    {
        this.context.clk = clk
        this.context.rst = rst
        this.app = new AppCore(rx, tx)
    }
}

Avoid hiding board-level signals deep inside the design. A reviewer should be able to open the top-level component and understand the external contract.

HxS Register Interfaces

Components annotated with Livt.HxS use the same vendor commands as other Livt components. Test the memory-mapped contract first, then create the standalone or IP project:

bash
livt test
livt vendor vivado-ip

Keep the bus visible in the component constructor, for example bus: flip IAxi4Lite32Master. This makes the component boundary clear in Livt tests, parent components, and the vendor project.

Treat register IDs, addresses, bit positions, reset values, and delegated ranges as a versioned interface. A change to that map may require a matching software or integration update.

See HxS Register Interfaces for the default-first annotation and Livt.Bus testing workflow.

Vendor Templates

Livt currently provides two Vivado-oriented vendor templates:

  • vivado creates an openable standalone Vivado project.
  • vivado-ip creates an openable Vivado IP project and package output.

Both templates use the shared Vivado settings in livt.toml. You can pass the target part directly on the command line:

bash
livt vendor vivado-ip xc7a100tcsg324-1

If no part is passed, Livt uses the configured part or scaffolds a default value into livt.toml.

Vivado Standalone Projects

Use the standalone template when the Livt project should become a normal Vivado project:

bash
livt vendor vivado

The project is created under .livt/vendor/work and can be opened in Vivado after the command succeeds. This flow is useful for board-level applications, experiments, and projects where Vivado owns the final implementation flow.

Vivado IP Packages

Use the IP template when the Livt project should be packaged as reusable Vivado IP:

bash
livt vendor vivado-ip

The Vivado project is created under .livt/vendor/work, and the packaged IP output is created under .livt/vendor/package. The consuming Vivado project selects the final board or device context; the IP project only needs a valid packaging part for the tool run.

Auto and Custom Wrappers

By default, Livt can create an automatic wrapper for the selected component. The auto wrapper exposes the component constructor parameters as the hardware boundary. Auto wrappers live in .livt/vendor because they are created as part of the vendor workspace.

Use a custom wrapper when a project needs board-specific naming, reset handling, special clocking, or hand-written vendor connections. Custom wrappers belong in src/ and are selected in livt.toml.

Configuration

A Vivado IP project can use:

toml
[vendor.vivado]
part = "xc7a100tcsg324-1"

[vendor.vivado.ip]
component = "WebApp"
wrapper = "auto"
top = "webapp_wrapper"
include_tests = true

A standalone Vivado project uses the same shared part setting and a project section:

toml
[vendor.vivado]
part = "xc7a100tcsg324-1"

[vendor.vivado.project]
component = "WebApp"
wrapper = "auto"
top = "webapp_wrapper"
include_tests = true

If these settings are missing, livt vendor adds sensible defaults without removing existing project settings.

Tests in Vendor Projects

Both Vivado templates can include test files for simulation. With include_tests = true, design files are used for the main project and test files are added to the simulation fileset. This keeps synthesis boundaries clear while still making project-level simulation convenient.

Vendor Wrappers

Many designs need to connect Livt-generated VHDL to vendor-specific primitives: PLLs, block RAMs, transceivers, IO buffers, clocking resources, or generated IP.

The usual strategy is to wrap vendor-specific functionality behind a stable Livt interface:

livt
interface IUartPins
{
    rx: in logic
    tx: out logic
}

The Livt design depends on the interface. The vendor-specific wrapper handles the details of the target device.

Constraints and Timing

Livt source does not replace timing constraints. Vendor flows still need clock definitions, pin assignments, I/O standards, generated clocks, false paths, and other constraints.

Keep constraints versioned with the project. When a Livt interface or top-level port changes, check whether constraints must change too.

A port rename can affect wrapper maps, pin and timing constraints, board automation, and consuming IP projects. Review those consumers together with the generated top-level VHDL.

Inspecting Top-Level Ports

Before integrating into a vendor project, inspect top-level ports:

  • Are input and output directions correct?
  • Are clock and reset ports named and connected as expected?
  • Are interface signals grouped and named in a way the board-level design can review?
  • Are public stored fields exposed intentionally?
  • Are test-only components excluded from synthesis?

This inspection catches boundary mistakes early.

Deployment Considerations

Deployment is project-specific, but the pattern is consistent:

  • build Livt
  • run tests
  • collect project output
  • create or update the vendor project
  • run vendor synthesis and implementation
  • archive reports and bitstreams

As the design matures, automate these steps in CI so hardware integration is repeatable.

Summary

Livt should fit into existing hardware flows, not replace them all at once. Keep build artifacts visible, maintain clean top-level boundaries, wrap vendor-specific blocks behind interfaces, use .livt/vendor for vendor workspace output, and treat constraints as part of the design.