Skip to content

sylefeb/Silice

master
Switch branches/tags
Code

Files

Permalink
Failed to load latest commit information.

Silice

A language for hardcoding Algorithms into FPGA hardware


Quick links:

Important: Silice is in alpha stages and under active development read more.

Important: To enjoy the latest features please use the draft branch. Read more about development branches.

Note: In a recent update the default file extension switched from .ice to .si to avoid overlapping with existing tools (see #206). This will only impact designs including code provided with Silice (e.g. from projects/common/). Simply change the extension of any included file to be .si. Silice also has to be recompiled as it looks for files from frameworks/libraries/ which changed extension as well. I recommend using .si from now on, but Silice is otherwise happy to compile files with any extension.


What is Silice?

Silice simplifies prototyping and implementing algorithms on FPGAs. It provides a comfortable yet thin abstraction above Verilog (a typical hardware description language), simplifying design without loosing precise control over the hardware. It provides "quality of life" features to group signals, define generic interfaces and circuitries, instantiate block RAMs, describe pipelines, deal with multiple clock domains and automatically manage flip-flops. It gives the (optional) ability to write parts of your design as sequences of operations, subroutines that can be called, and to use control flow statements such as while and break, describing operations and algorithms that run in parallel and are precisely in sync. Silice detects combinatorial loops and many other error-prone cases, and features a Lua-preprocessor enabling advanced code generation.

Silice does not aim to be a high level synthesis language: it remains close to the hardware and lets you fully exploit FPGA architectures, with a fine grain control on how your design maps to the hardware: You remain in control of what happens at each and every clock cycle, with predictable rules for flow control, how and when execution states appear, how flip-flops map to variables, and what gets registered or not. In fact, if you chose so you can design in a way that is very similar to Verilog, while still benefiting from the "quality of life" improvements of Silice syntax. This allows to refine an initial prototype from concept to efficient implementation. Silice compiles to and inter-operates with Verilog: you can directly instantiate and bind with existing modules.

The language comes with a complete build system, many examples and basic components (VGA, HDMI, OLED, UART, and SDRAM controllers). The build system allows to get started easily, and already supports many popular boards such as the IceBreaker, ULX3S, Fomu and IceStick.

You do not need an FPGA to start with Silice: designs and their outputs (e.g. VGA signal) can be simulated and visualized. Silice works great with the open source FGPA toolchain (yosys/nextpnr/icestorm), see our Ice40 and ECP5 examples.

While I developed Silice for my own needs, I hope you'll find it useful for your projects!

Design principles and features

Silice does not abstract away the hardware: the programmer remains in control and very close to hardware features. It provides syntactic helpers simplifying design and reuse (signal groups, generic interfaces, pipelining). Silice can also help you reason in terms of execution flow and operation sequences. However, this is not mandatory and you can also take full control and use a more direct hardware design style. When developing with Silice you can focus optimization efforts on critical parts, and use a simpler approach in other parts of the design.

The main features are:

  • A clean, simple syntax that clearly exposes the flow of operations and where clock cycles are spent.
  • Precise rules regarding flow control (loops, calls) and their clock cycle consumption.
  • Familiar hardware constructs such as always blocks, instantiation, expression tracking (wires).
  • An optional flow-control oriented design style (automatic FSM generation), that naturally integrates within a design: while, break, subroutines.
  • The possibility to easily describe pipelines.
  • Automatically takes care of creating flip-flops for variables, with automatic pruning (e.g. const or bindings).
  • Generic interfaces and grouped IOs for easy reuse and modular designs.
  • Generic circuitries that can be instantiated and reused easily.
  • Explicit clock domains and reset signals.
  • Familiar syntax with both C and Verilog inspired elements.
  • Inter-operates with Verilog, allowing to import and reuse existing modules.
  • Powerful LUA-based pre-processor.

These examples are different and representative of this approach:

A first example:

(see also the full blinky tutorial)

Code:
1  algorithm main(output uint8 led) {
2    uint28 counter = 0;      // a 28 bits unsigned integer
3    led := counter[20,8];    // LEDs updated every clock with the 8 most significant bits
4    while (1) {              // forever
5      counter = counter + 1; // increment counter
6    }
7  }
Compile:
cd projects
cd blinky
make mojov3
Enjoy!

First example in action on a Mojo v3

Explanations:

Line 1 is the entry point of any Silice hardware: the main algorithm. Line 2 we define a 28 bits unsigned int, initialized to 0. Initializers are mandatory and are always constants. Line 3 we request that the output led tracks the eight most significant bits of the counter variable. The syntax [20,8] means 8 bits wide starting from bit 20. The assignment to led uses the := operator which is an always assignment: led is now automatically updated with counter after each rising clock. Such assignments have to appear at the top of an algorithm, right before any other instruction.

Finally, lines 4-6 define the infinite loop that increments the counter. Of course the 28 bit counter will ultimately overflow and go back to 0, hence the cyclic LED light pattern. In this case, the loop takes exactly one cycle to execute: we have one increment per cycle at 50 MHz (the clock frequency of the Mojo v3).

We then compile with silice. The -f parameter indicates which framework to use: this is an FPGA plateform dependent wrapper code. Here we are using the Mojo framework with LEDs only. Several other frameworks are provided, and it is easy to write your own.

The -o parameter indicates where to write the Verilog output. In this example we overwrite the main file of a pre-existing project, which is then compiled using Xilinx ISE toolchain. Fear not, we also have examples working with yosys, nextpnr and project icestorm!

Cycles and control flow:

Here is another small example outlining a core principle of Silice:

Code:
1 algorithm main() {
2    brom int12 sintbl[4096] = {...}
3    ...
4    while (1) { // render loop
5      // get cos/sin view
6      sintbl.addr = (viewangle) & 4095;
7  ++:
8      sinview     = sintbl.rdata;
9      sintbl.addr = (viewangle + 1024) & 4095;
10 ++:
11     cosview     = sintbl.rdata;
12     ...
Explanations:

This code is storing a sine table in a block ROM and accesses it to obtain a cosine and sine for the current view angle. Note the use of the ++: step operator in lines 7 and 10. This explicitely splits the exectution flow and introduces a one cycle delay, here waiting for the brom to output its result in field rdata for the select address in addr. Anything in between is considered combinational; for instance lines 8 and 9 are evaluated in parallel on hardware, as they each produce two pieces of independent circuitry.

Other examples with detailed explanations

This repo contains many example projects, some including detailed code walkthrough:

Getting started with Silice

See the getting started guide. Silice runs great on Windows, Linux, and macOS! To start writing code, see writing your first design. To see what can be done with Silice, checkout our example projects (all are available in this repo).

Project status: Alpha release

Silice can already be used to create non trivial designs, from a tiny Risc-V processor to an entire game render loop (visit the examples page).

However Silice is under active development. I decided to open the repo so everyone can join in the fun, but it is far from complete: documentation is lacking, some examples are outdated or far from polished, some very important language features are missing, and many known issues exist (head out to the Issues page). I am confident I can avoid major code breaking syntax changes, but some adjustments may be necessary.

I hope you'll nevertheless enjoy diving into it, and will find it useful. Please let me know your thoughts: comments and contributions are welcome!

Development branches

  • master is the latest, most stable version
  • wip is where new features are being implemented, less stable but reasonnable
  • draft is heavy experimental work in progress, likely unstable, may not compile

Directory structure

  • learn-silice contains documentation and tutorials
  • projects contains many demo projects (see README therein) as well as build scripts for several boards
  • bin contains the Silice binaries after compiling using the compile_silice_*.sh script
  • frameworks contains the frameworks for various boards and setups
  • tools contains tools useful for Silice development, either source or binary form (to be installed, see getting started)
  • src contains Silice core source code
  • antlr contains Silice grammar and parsing related source code
  • tests contains test scripts for Silice development

License

GPLv3 (Silice compiler) and MIT (examples and glue code), but please refer to the dedicated page.

Credits

  • Silice logo by Pierre-Alexandre Hugron (Twitter)

About

Silice is an open source language that simplifies prototyping and writing algorithms on FPGA architectures.

Topics

Resources

License

Unknown, GPL-3.0 licenses found

Licenses found

Unknown
LICENSE.md
GPL-3.0
LICENSE_GPLv3

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published