Overview
The Private Island ® open source project is written using Verilog 2001 (IEEE 1364-2001). Verilog was chosen due to its ubiquitous presence in both industry and education, clean and simple 'C' like syntax, and it's universal adoption by FPGA manufacturers and related synthesis engines.
Per IEEE, Verilog was designed "to be simple, intuitive, and effective at multiple levels of abstraction in a standard textual format for a variety of design tools, including verification simulation, timing analysis, test analysis, and synthesis."
Regardig Verilog versions, we generally refer to IEEE 1364-2005 when reviewing what the standard says about a particular language feature. As conveyed in the 2005 standard, this version was mainly a clean up of outstanding issues with the 2001 specification.
SystemVerilog (IEEE 1800-2023) is utilized for test benches in order to take advantage of its wealth of newer features for test & verification.
Note that we have found over the years that using SystemVerilog for FPGA implementations can lead to unpredictable synthesis results and can prove to be incompatible with FPGA tool features, such as internal logic analyzers.
Listed below are code and style conventions for the project. The documentation and adoption of coding conventions is in its early stages, and this page will be updated often.
This following conventions are used on this page to provide examples:
- module names are shown in italics
- FSM state names are CAPITALIZED.
- variable and wire names are shown lower case and bold.
- reserved words are shown lower case, bold, and in green
General Guidelines
- The project strives to use a hierarchical approach with emphasis on smaller, well defined modules.
- The goal of the project is to keep it simple as a template for others to use to build more complicated, specialized projects.
- Each module is defined in its own Verilog source file with same name (e.g., module spi is in file spi.v)
- The top project module (e.g., betsy) should only contain instantiation statements of sub modules. Exceptions are well defined, behavioral, top-level data muxes and tri-state output statements.
- The top module directly instantiates each sub module independently rather than use generate statements in order to enable simple and quick customizations of the top layer by those experimenting with the project and code.
- Tri-state statements for bidirectional ports are only permitted in the top module.
- Always verify that your changes don't significantly reduce the overall timing margin on a particular clock. If it does, restructuring your code or adding pipeline registers may be required.
- Readability is essential. Before submitting code, walk away from it for at least an hour and then revisit it. If you have trouble understanding what you did, then break it up and / or take a fresh approach.
- Do not use long, compounded, ternary conditional statements (condition ? valueIfTrue : valueIfFalse). Either break them up or rewrite your logic as a combinatorial behavioral block
Modules
- Verilog 95 style port declarations are not permitted.
- Register all module outputs that may be timing sensitive. It is OK to directly declare an output as a reg (e.g., output reg mem_we,).
- Encapsulate technology dependent / proprietary blocks in a generic module using generic, easy to understand I/O declarations.
Comments
- Block line comments are not acceptable when used in between a Verilog statement on a single line. For example "assign a = /* a is for apple */ b;" is not acceptable.
- Block line comments (/* .... */) should only be used when an entire line or more is commented.
- Conventions for commenting entire code sections (e.g., Transmit or a large state machine) are TBA.
Reset
- A global, active low, asynchronous (power up) reset is provided across the fabric. This signal is rstn. For Lattice devices, it drives the GSR primitive.
- Clearly define synchronous set / reset in behavioral blocks as needed, and place this as the first conditional line after the asynchronous reset conditional statement.
Case statements vs if-then-else
- When priority logic isn't required, strive to use case statements for non trivial logic.
Combinatorial Logic
- Use behavioral blocks and always @(*)
- Use non blocking assignments (=)
- Be aware of creating un-intentional latches
Behavioral synchronous blocks
- Separate unrelated outputs into separate behavioral blocks for easier understanding and to reduce the chances of unintended priority encodings.
- Do not gate clocks, instead use a clock enable.
Much more coming...



