legoHDL Documentation
legoHDL is the package manager and development tool for Hardware Description Languages (HDL). The goal of this documentation is to provide materials to learn, use, and understand the legoHDL project.
Sections
The following documentation is mainly divided into 4 sections:
- Tutorials - step-by-step lessons working with legoHDL
- User Guide - general procedures for "how-to" solve common problems
- Topic Guide - explanations that clarify and provide more detail to particular topics
- Reference - technical information
Better IP management. For All.
legoHDL is a complete and custom open-source solution to better developing and managing HDL designs. Stop wasting time and resources reinventing the wheel, fighting with tools, and copying HDL files into new projects.
VHDL and Verilog are supported as well as mixed-language.
Cross-platform compatibility with macos, ubuntu, and windows.
About the Project
The project is open-source under the MIT license and is available on GitHub.
About the Documentation
Documentation system and methodology is inspired by Divio.
Getting Started
In this chapter, we will install legoHDL onto our local machine using the terminal and set up some preliminary settings.
Tip: How to Understand the Code
Any time a code snippet is presented in this documentation beginning with a $
, the text on that line proceeding it is to be entered into the terminal (excluding the $
).
Installation
There are very minimal requirements to get legoHDL up and running. Even though git is a requirement, developers do not need to fully understand git nor directly run git commands.
Requirements
Some recommended text-editors:
- visual studio code (ubuntu, macos, windows)
- atom (ubuntu, macos, windows)
- notepad++ (windows)
- emacs (ubuntu, macos, windows)
Note: If you have never ran
git
before, make sure to configure your name and email address before continuing. Check out git's documentation for first time setup (notably the section titled "Your Identity").
Verify an acceptable python version is installed (greater than or equal to 3.5).
$ python --version
Verify git is installed.
$ git --version
There are two places to install legoHDL from: GitHub or PYPI.
Installing from GitHub
- Clone the project from GitHub
$ git clone https://github.com/c-rus/legoHDL.git
- Install the python program using PIP
$ pip install ./legoHDL
- Delete the cloned project.
ubuntu | macos: $ rm -r ./legoHDL
windows: $ rmdir /S ./legoHDL
- Verify legoHDL is installed.
$ legohdl --version
Installing from PYPI
Note: This method is currently unavailable.
- Install the python program using PIP
$ pip install legohdl
- Verify legoHDL is installed.
$ legohdl --version
Initial Setup
Follow the process below to set up required preliminary settings.
Running legohdl
for the first time will prompt the user if they would like to set up a profile.
$ legohdl
INFO: This looks like your first time running legoHDL! Would you like to use a
profile (import settings, template, and plugins)? [y/n]
Returning y
gives the user 3 choices.
$ y
Enter:
1) nothing for default profile
2) a path or git repository to a profile
3) 'exit' to cancel configuration
Unless you have a profile already that you would like to use, let's go ahead and return an empty response to use the default profile.
$
INFO: Setting up default profile...
INFO: Reloading default profile...
INFO: Importing default profile...
INFO: Overloading legohdl.cfg...
CREATED: plugin.hello = echo "hello world!"
CREATED: plugin.demo = python $LEGOHDL/plugins/demo.py
OBSERVE: hdl-styling.auto-fit = on
OBSERVE: hdl-styling.alignment = 1
ALTERED: hdl-styling.port-modifier = w_*
CREATED: [workspace.primary]
CREATED: workspace.primary.path =
CREATED: workspace.primary.vendors =
INFO: Importing template...
INFO: Overloading template in legohdl.cfg...
OBSERVE: general.template =
INFO: Importing plugins...
INFO: Copying demo.py to built-in plugins folder...
INFO: Overloading plugins in legohdl.cfg...
OBSERVE: plugin.hello = echo "hello world!"
OBSERVE: plugin.demo = python $LEGOHDL/plugins/demo.py
legoHDL then asks for your name
Enter your name:
$ Chase Ruskin
ALTERED: general.author = Chase Ruskin
and how it should call your text-editor to run.
Enter your text-editor:
$ code
ALTERED: general.editor = code
Finally, you must specify a path for the current active-workspace, which is named "primary" by default.
INFO: Local path for workspace primary cannot be empty.
Enter path for workspace primary:
$ ~/develop/hdl/primary/
Note: If the entered path does not exist, legoHDL will notify you and ask to verify the creation of the new path.
Now the default console output from legoHDL appears. All required configurations are complete.
Usage:
legohdl <command> [entry] [<flags>] [-h]
Commands:
Development
new create a new legohdl block (project)
init initialize existing code into a legohdl block
open open a block with the configured text-editor
get print instantiation code for an HDL unit
graph visualize HDL dependency graph
export generate a blueprint file
build execute a custom configured plugin
release set a newer version for the current block
del delete a block from the local workspace path
Management
list print list of all blocks available
refresh sync local vendors with their remotes
install bring a block to the cache for dependency use
uninstall remove a block from the cache
download bring a block to the workspace path for development
update update an installed block to be its latest version
info read further detail about a block
config modify legohdl settings
Type 'legohdl help <command>' to read about that command.
You can modify settings at any time in the GUI with
$ legohdl open -settings
See Managing Settings for more information regarding settings.
Tutorials
In this chapter, you will be taken through step-by-step lessons to begin working with legoHDL.
Note: Hardware Description Languages
The following tutorials have HDL code that is in majority written in VHDL. Basic knowledge of an HDL, such as Verilog, should be sufficient to understanding and following along with the code throughout the tutorials.
First Project: Gates
On this page, we will go through the entire process for creating, building, and releasing a block.
1. Creating the Block
Let's create our first block, under the name gates, which will be under the library tutorials. Gates will be a project involving two logical gates: NOR and AND.
$ legohdl new tutorials.gates
Open the block using your configued text-editor.
$ legohdl open tutorials.gates
Your text-editor should have opened the block's root folder and a couple of files should be automatically added in the block. This is because a template was used, which we loaded during initial setup.
Note: The commands presented throughout the remainder of this page assume they are ran from the block's root folder.
Creating a new design: NOR Gate
Let's create our first HDL design, nor_gate.
$ legohdl new ./src/nor_gate.vhd -file
Here we specified we wanted to create a new file nor_gate.vhd
. Your editor should automatically focus on this new file.
The following is the code for our first HDL design, nor_gate. Copy it into nor_gate.vhd
.
--------------------------------------------------------------------------------
-- Block: tutorials.gates
-- Entity: nor_gate
-- Description:
-- Takes two bits and performs the NOR operation. Q = ~(A | B).
--
-- Both A and B are a singular bit and must both be '0' for Q to be '1'.
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
entity nor_gate is
port(
a, b : in std_logic;
q : out std_logic);
end entity;
architecture rtl of nor_gate is
begin
--logic to drive 'Q' output using 'NOR' keyword
q <= a nor b;
end architecture;
Awesome, nothing too fancy going on here. Now its time to reuse our IP in other designs.
Reusing designs: AND Gate
Reusing designs is at the core of what legoHDL is built to be. Not reinventing the wheel saves time and resources that can be spun into designing more innovation, faster. Our next task will be to create a logical AND gate using only NOR gates.
Let's review the schematic for creating an AND gate from purely NOR gates.
The design requires 3 instances of a NOR gate.
Let's create another file and_gate.vhd
using the new
command like last time.
$ legohdl new ./src/and_gate.vhd -file
Copy the following code into and_gate.vhd
; we will complete it shortly.
--------------------------------------------------------------------------------
-- Block: tutorials.gates
-- Entity: and_gate
-- Description:
-- Takes two bits and performs the AND operation. Q <- A & B.
--
-- Both A and B are a singular bit and each must be '1' for Q to be '1'. Built
-- from 3 instances of logical NOR gates.
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
entity and_gate is
port(
a, b : in std_logic;
q : out std_logic);
end entity;
architecture rtl of and_gate is
begin
end architecture;
HDL languages support the use of a structural modelling technique, which will be applied here to create 3 instances of the NOR gate.
Getting NOR gate
There is a specific syntax within HDL languages that must be followed to instantiate components within larger designs. Not only must a developer get the syntax correct, the developer must know all the I/O ports to list, which can get out of hand as designs become more complex.
We introduce the get
command.
Let's generate the VHDL code required to create our NOR gates using our design written in nor_gate.vhd
.
$ legohdl get nor_gate -inst
The console outputs the following:
--- ABOUT ---
------------------------------------------------------------------------------
Block: tutorials.gates
Entity: nor_gate
Description:
Takes two bits and performs the NOR operation. Q = ~(A | B).
Both A and B are a singular bit and must both be '0' for Q to be '1'.
------------------------------------------------------------------------------
--- CODE ---
signal w_a : std_logic;
signal w_b : std_logic;
signal w_q : std_logic;
uX : entity work.nor_gate port map(
a => w_a,
b => w_b,
q => w_q);
The --- ABOUT ---
section returns the initial comments from the design's source file to potentially help inform the user.
The --- CODE ---
section produces instantly-compatible code to be directly copied and pasted into the necessary design (and_gate.vhd
in our case).
After copying and pasting the compatible code and making minor adjustments, our and_gate.vhd
should now be complete.
--------------------------------------------------------------------------------
-- Block: tutorials.gates
-- Entity: and_gate
-- Description:
-- Takes two bits and performs the AND operation. Q = A & B.
--
-- Both A and B are a singular bit and each must be '1' for Q to be '1'. Built
-- from only NOR gates.
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
entity and_gate is
port(
a, b : in std_logic;
q : out std_logic);
end entity;
architecture rtl of and_gate is
signal w_a_not : std_logic;
signal w_b_not : std_logic;
signal w_q : std_logic;
begin
--negate a
u_A_NOT : entity work.nor_gate port map(
a => a,
b => a,
q => w_a_not);
--negate b
u_B_NOT : entity work.nor_gate port map(
a => b,
b => b,
q => w_b_not);
--perform /a nor /b
u_A_AND_B : entity work.nor_gate port map(
a => w_a_not,
b => w_b_not,
q => w_q);
--drive output
q <= w_q;
end architecture;
Viewing a design
In our project, and_gate depends on nor_gate. We can visualize this dependency by using the graph
command.
$ legohdl graph
The console outputs the following:
INFO: Identified top-level unit: and_gate
WARNING: No testbench detected.
INFO: Generating dependency tree...
--- DEPENDENCY TREE ---
\- tutorials.and_gate
\- tutorials.nor_gate
--- BLOCK ORDER ---
[1]^- tutorials.gates(@v0.0.0)
Note: If at any point you want to stop the tutorial and continue later, you can always reopen your text editor and terminal at the block's root folder, or from anywhere run:
legohdl open tutorials.gates
2. Building the Block
The other half to hardware designing involves verification. We will create a testbench to verify the entity and_gate behaves according to the following truth table.
A | B | Q |
---|---|---|
0 | 0 | 0 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
Creating a file from the template
Different types of HDL files can follow similiar code layouts, such as when designing a 2-process FSM or a testbench. For these situations, its beneficial to create a boilerplate template file for when that code-style is needed.
We can see what files exist in our legoHDL template by using the list
command.
$ legohdl list -template
INFO: Files available within the selected template: C:/Users/chase/.legohdl/template/
Relative Path Hidden
------------------------------------------------------------ --------
/.gitignore -
/.hidden/tb/TEMPLATE.vhd yes
/src/TEMPLATE.vhd -
We have a testbench template file /.hidden/tb/TEMPLATE.vhd
available for use within our template, however, it wasn't automatically copied into our project when we created it because it is hidden.
Reference this file for creating our testbench and_gate_tb.vhd
.
$ legohdl new ./test/and_gate_tb.vhd -file="/.hidden/tb/TEMPLATE.vhd"
The contents of and_gate_tb.vhd
should resemble the following:
--------------------------------------------------------------------------------
-- Block : tutorials.gates
-- Author : Chase Ruskin
-- Created : December 16, 2021
-- Entity : and_gate_tb
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
entity and_gate_tb is
end entity;
architecture bench of and_gate_tb is
--declare DUT component
--declare constants/signals
constant dly : time := 10 ns;
begin
--instantiate DUT
--verify design within process
process begin
report "SIMULATION COMPLETE";
wait;
end process;
end architecture;
Getting a component declaration and instantiation
Now we need to instantiate our Design-Under-Test (DUT), which is and_gate, and run it through the previous truth table.
Use the get
command to return both the component declaration and instantiation code for the and_gate entity.
$ legohdl get and_gate -comp -inst
The console outputs the following:
--- ABOUT ---
------------------------------------------------------------------------------
Block: tutorials.gates
Entity: and_gate
Description:
Takes two bits and performs the AND operation. Q <- A & B.
Both A and B are a singular bit and each must be '1' for Q to be '1'. Built
from only NOR gates.
------------------------------------------------------------------------------
--- CODE ---
component and_gate
port(
a : in std_logic;
b : in std_logic;
q : out std_logic);
end component;
signal w_a : std_logic;
signal w_b : std_logic;
signal w_q : std_logic;
uX : and_gate port map(
a => w_a,
b => w_b,
q => w_q);
In and_gate_tb.vhd
, perform the following:
- Below the line
--declare DUT component
, copy and paste the component declaration. - Below the line
--declare constants/signals
, copy and paste the I/O connection signals. - Below the line
--instantiate DUT
, copy and paste the instantiation code.
Now within our process we write a few lines of code to assert the DUT functions properly.
The testbench and_gate_tb is now complete.
--------------------------------------------------------------------------------
-- Block : tutorials.gates
-- Author : Chase Ruskin
-- Created : December 16, 2021
-- Entity : and_gate_tb
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
entity and_gate_tb is
end entity;
architecture bench of and_gate_tb is
--declare DUT component
component and_gate
port(
a : in std_logic;
b : in std_logic;
q : out std_logic);
end component;
--declare constants/signals
constant dly : time := 10 ns;
signal w_a : std_logic;
signal w_b : std_logic;
signal w_q : std_logic;
begin
--instantiate DUT
DUT : and_gate port map(
a => w_a,
b => w_b,
q => w_q);
--verify design within process
process begin
--test 00
w_a <= '0';
w_b <= '0';
wait for dly;
assert w_q = '0' report "(0 & 0) /= 1" severity error;
--test 01
w_a <= '0';
w_b <= '1';
wait for dly;
assert w_q = '0' report "(0 & 1) /= 1" severity error;
--test 10
w_a <= '1';
w_b <= '0';
wait for dly;
assert w_q = '0' report "(1 & 0) /= 1" severity error;
--test 11
w_a <= '1';
w_b <= '1';
wait for dly;
assert w_q = '1' report "(1 & 1) /= 0" severity error;
report "SIMULATION COMPLETE";
wait;
end process;
end architecture;
Our testbench uses an instance of the entity and_gate. Let's verify this with the graph
command like last time.
$ legohdl graph
INFO: Identified top-level unit: and_gate
INFO: Identified top-level testbench: and_gate_tb
INFO: Generating dependency tree...
--- DEPENDENCY TREE ---
\- tutorials.and_gate_tb
\- tutorials.and_gate
\- tutorials.nor_gate
--- BLOCK ORDER ---
[1]^- tutorials.gates(@v0.0.0)
Generating a blueprint
At this point in the design process, we want to verify that and_gate is performing correctly before we begin using it. We introduce 2 new commands to handle this: export
and build
.
Note: For the purposes of this tutorial trying to be as dependency-free as possible so that everyone may follow it, we will utilize a pseudo-plugin called demo. This is a legoHDL plugin that mainly just prints text to the console. We will use this to avoid assuming/forcing a backend EDA tool/simulator.
From the graph
command, we can see legoHDL knows how our designs are connected, yet our plugin does not. We need a way to tell our plugin what files we need to build our current design.
Create a blueprint so any plugin can know what files will be are needed.
$ legohdl export
The last line from the console should say where the blueprint file is located:
INFO: Blueprint found at: C:/Users/chase/develop/hdl/tutorials/gates/build/blueprint
Building a design
Now that the blueprint is created, we can build our project with a plugin. Let's look at what plugins we have available.
$ legohdl list -plugin
Alias Command
--------------- ----------------------------------------------------------------
hello echo "hello world!"
demo python $LEGOHDL/plugins/demo.py
We currently have 2 plugins at our disposal: hello and demo. The hello plugin will only output "hello world!" to our console; not helpful at all but demonstrates that plugins are at the most basic level a command.
$ legohdl build +hello
INFO: echo "hello world!"
hello world!
Build with the demo plugin.
$ legohdl build +demo
The plugin's help text will display due to the plugin internally defining this functionality. legoHDL's role during build
is to only pass off the command python $LEGOHDL/plugins/demo.py
to the terminal to execute.
Note: All arguments after the plugin's alias will be also passed down from legoHDL to the terminal when it executes the plugin's command.
Build with the demo plugin to perform a pseudo-simulation.
$ legohdl build +demo -sim
INFO: python $LEGOHDL/plugins/demo.py -sim
echo PSEUDO SIMULATOR
PSEUDO SIMULATOR
Compiling files...
VHDL C:/Users/chase/develop/hdl/tutorials/gates/src/nor_gate.vhd
VHDL C:/Users/chase/develop/hdl/tutorials/gates/src/and_gate.vhd
VHDL C:/Users/chase/develop/hdl/tutorials/gates/test/and_gate_tb.vhd
Running simulation using testbench and_gate_tb...
Simulation complete.
3. Releasing the Block
Creating a block-level VHDL package
Before we release the first version, let's create a package file that consists of all the component declarations available within this block. A package is an optional but helpful VHDL unit that will allow easier reference to these components later. legoHDL automates this package file creation.
$ legohdl export -pack="./src/gates.vhd"
We specified the VHDL package file to be created at ./src/gates.vhd
. Opening the file shows the following contents.
--------------------------------------------------------------------------------
-- Block: tutorials.gates
-- Created: December 16, 2021
-- Package: gates
-- Description:
-- Auto-generated package file by legoHDL. Components declared:
-- nor_gate and_gate
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
package gates is
component nor_gate
port(
a : in std_logic;
b : in std_logic;
q : out std_logic);
end component;
component and_gate
port(
a : in std_logic;
b : in std_logic;
q : out std_logic);
end component;
end package;
Setting the first version
We are done making changes and working with the HDL code within this block; it's time for release! We will call this version 1.0.0.
$ legohdl release v1.0.0
We can check the status of all of our workspace's blocks in the catalog using the list
command.
$ legohdl list
Library Block Status Version Vendor
---------------- -------------------- -------- ---------- ----------------
tutorials gates D I 1.0.0
Notice that the release
command also installed the gates block to the workspace cache, indicated by the I
in status.
The D
indicates the block is also downloaded/developing because it is found in our workspace's local development path.
We are done developing gates, so close the text-editor and delete the block from the downloads space.
$ legohdl del gates
Note: Deleting the folder where the project is located will have the same effect as the command above.
Page Review
Woo-hoo! On this page, We learned how to:
- create a new block and new files with
new
- view blocks, plugins, and template files with
list
- check how our design connects together with
graph
- generate a blueprint file of the current design with
export
- build with a plugin that will perform some desired action with
build
- create a VHDL package file consisting of the block's components with
export -pack
- release a completed block with a specified version with
release
On the next page, we will see how legoHDL handles using HDL designs from external blocks by making a new block comparator that will require the gates block.
Using Blocks: Comparator
On this page, we begin to see more of the package management aspects of legoHDL as we create a second project called comparator.
Comparator will need to use external designs previously created in the block gates. Before we create our next block, let's learn how to edit the template.
1. Editing the template
Open the template's folder.
$ legohdl open -template
All files in here we will copied when creating a new block, except for any files within folders beginning with .
. A Block.cfg file will always be created by legoHDL for every block, so no need to include that here.
Edit the ./src/TEMPLATE.vhd
file with the following code.
--------------------------------------------------------------------------------
-- Block: %BLOCK%
-- Author: %AUTHOR%
-- Created: %DATE%
-- Entity: TEMPLATE
-- Description:
--
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
entity TEMPLATE is
port(
);
end entity;
architecture rtl of TEMPLATE is
begin
end architecture;
We use placeholders to mark the spot for data be filled in when the file is created. These placeholders will change values based on factors external of the template, such as today's date for %DATE%
, the block's identifier for %BLOCK%
, or the file's name for TEMPLATE
.
Save the file and exit the template.
Create a new block comparator
under the library tutorials
and open it.
$ legohdl new tutorials.comparator -open
Our comparator will require an XOR gate, so let's design an XOR gate next.
2. Creating XOR gate
The first design for the comparator block will be an XOR gate.
Let's review the schematic for an XOR gate from purely NOR gates.
Notice how the upper 3 NOR gates are the equivalent to the AND gate we previously designed. Rather than using 5 instances of a NOR gate, we will save time by using 1 AND gate instance and 2 instances of the NOR gate.
Create a new file from our previously edited template file and call it xor_gate.vhd
.
$ legohdl new ./src/xor_gate.vhd -file="/src/TEMPLATE.vhd"
Fill in a description for how the design will behave below the -- Description:
line. Note that the block's identifier, your name, and the day's date should already be filled in. Also define the entity's port interface.
--------------------------------------------------------------------------------
-- Block: tutorials.comparator
-- Author: Chase Ruskin
-- Created: December 18, 2021
-- Entity: xor_gate
-- Description:
-- Q = A ^ B.
--
-- Takes two singular bits A and B, and performs the XOR operation to produce
-- Q.
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
entity xor_gate is
port(
a, b : in std_logic;
q : out std_logic);
end entity;
...
Now it is time to describe the architecture according to the previous schematic.
Hang on, and_gate and nor_gate are not defined in this block!
That's okay, accessing these entities is the same as before.
$ legohdl get and_gate -inst
--- ABOUT ---
------------------------------------------------------------------------------
Block: tutorials.gates
Entity: and_gate
Description:
Takes two bits and performs the AND operation. Q <- A & B.
Both A and B are a singular bit and each must be '1' for Q to be '1'. Built
from 3 instances of logical NOR gates.
------------------------------------------------------------------------------
--- CODE ---
signal a : std_logic;
signal b : std_logic;
signal q : std_logic;
uX : entity tutorials.and_gate port map(
a => a,
b => b,
q => q);
Note: Specifying the entity's entire scope will produce the same result.
legohdl get tutorials.gates:and_gate -inst
Copy and paste the outputted code to instantiate an and_gate. Connect signals according to the schematic.
Get the nor_gate instance code.
$ legohdl get nor_gate -inst
--- ABOUT ---
------------------------------------------------------------------------------
Block: tutorials.gates
Entity: nor_gate
Description:
Takes two bits and performs the NOR operation. Q = ~(A | B).
Both A and B are a singular bit and must both be '0' for Q to be '1'.
------------------------------------------------------------------------------
--- CODE ---
signal a : std_logic;
signal b : std_logic;
signal q : std_logic;
uX : entity tutorials.nor_gate port map(
a => a,
b => b,
q => q);
Copy and paste the nor_gate code to create 2 instances connected together with the 1 and_gate according to the schematic.
The final code should resemble the following.
--------------------------------------------------------------------------------
-- Block: tutorials.comparator
-- Author: Chase Ruskin
-- Created: December 18, 2021
-- Entity: xor_gate
-- Description:
-- Q = A ^ B.
--
-- Takes two singular bits A and B, and performs the XOR operation to produce
-- Q.
--------------------------------------------------------------------------------
library ieee;
library tutorials;
use ieee.std_logic_1164.all;
entity xor_gate is
port(
a, b : in std_logic;
q : out std_logic);
end entity;
architecture rtl of xor_gate is
signal w_and_q : std_logic;
signal w_nor_q : std_logic;
begin
--send inputs A and B through AND-gate
u_AND : entity tutorials.and_gate port map(
a => a,
b => b,
q => w_and_q);
--send inputs A and B through NOR-gate
u_NOR : entity tutorials.nor_gate port map(
a => a,
b => b,
q => w_nor_q);
--send outputs from AND and NOR through a NOR-gate to produce XOR
u_XOR : entity tutorials.nor_gate port map(
a => w_and_q,
b => w_nor_q,
q => q);
end architecture;
Note: nor_gate and and_gate are external HDL files. They belong to the library tutorials. Since we instantiated them using VHDL's entity instantiation technique, we must declare their library at the top of the file with the line
library tutorials;
Run the graph command, but now with each entity's entire scope being displayed using the -disp-full
flag.
$ legohdl graph -disp-full
INFO: Identified top-level unit: xor_gate
WARNING: No testbench detected.
INFO: Generating dependency tree...
--- DEPENDENCY TREE ---
\- tutorials.comparator:xor_gate
+- tutorials.gates:and_gate
| \- tutorials.gates:nor_gate
\- tutorials.gates:nor_gate
--- BLOCK ORDER ---
[2]^- tutorials.comparator(@v0.0.0)
[1]^- tutorials.gates(@v1.0.0)
Looks good! Notice how we now have a block order of requirements, and it shows what version of the block gates is being referenced to create the current design.
3. Creating a Comparator
Now open ./src/comparator.vhd
to create our final design, which will use 3 nor_gates, 2 and_gates, and 1 xor_gate.
First, write a description about our design and fill in the entity interface.
--------------------------------------------------------------------------------
-- Block: tutorials.comparator
-- Author: Chase Ruskin
-- Created: December 18, 2021
-- Entity: comparator
-- Description:
-- Compares two singular bits: A and B. Outputs 3 different results.
--
-- 'lt' = (A < B)
-- 'eq' = (A == B)
-- 'gt' = (A > B)
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
entity comparator is
port(
a, b : in std_logic;
lt, eq, gt : out std_logic);
end entity;
Now imagine we have completely blanked on what entities we can use. How could we remember?
View what blocks are available.
$ legohdl list
Library Block Status Version Vendor
---------------- -------------------- -------- ---------- ----------------
tutorials comparator D
tutorials gates I 1.0.0
Okay, we have a gates block installed to use, but what entities were designed in there?
View information about the gates block.
$ legohdl info tutorials.gates
--- METADATA ---
[block]
name = gates
library = tutorials
version = 1.0.0
remote =
vendor =
requires = ()
Not very helpful right now, but we can see the metadata defined in its Block.cfg. Let's try to get more information with the -more
flag.
$ legohdl info tutorials.gates -more
--- METADATA ---
[block]
name = gates
library = tutorials
version = 1.0.0
remote =
vendor =
requires = ()
--- STATS ---
Location = C:/Users/chase/.legohdl/workspaces/primary/cache/_/tutorials/gates/gates/
Size = 31.98 KB
Level = INSTL
Required by:
N/A
VHDL units:
and_gate gates nor_gate and_gate_tb
And look! We can see what VHDL primary design units are defined in the block (as well as if there were any Verilog modules).
Now that we know the units at our disposal, let's inspect them.
$ legohdl get gates
--- ABOUT ---
------------------------------------------------------------------------------
Block: tutorials.gates
Created: December 16, 2021
Package: gates
Description:
Auto-generated package file by legoHDL. Components declared:
and_gate nor_gate
------------------------------------------------------------------------------
gates is a VHDL package file. Let's use it to help instantiate our nor_gate and and_gate.
Add the library
and use
clauses for the gates package above library ieee;
.
library tutorials;
use tutorials.gates.all;
library ieee;
...
In the comparator's architecture, we only need the component instantiations for and_gate and nor_gate. We can access those by combining flags -comp
and -inst
.
Get the component instantiations for nor_gate and and_gate, as well as the entity instantiation for xor_gate.
$ legohdl get and_gate -comp -inst
$ legohdl get nor_gate -comp -inst
$ legohdl get xor_gate -inst
Copy and paste their outputted code into comparator.vhd
, and connect signals accordingly. The final comparator architecture resembles the following.
architecture rtl of comparator is
signal w_not_a : std_logic;
signal w_not_b : std_logic;
signal w_not_eq : std_logic;
begin
--invert incoming A bit
u_NEG_A : nor_gate port map(
a => a,
b => a,
q => w_not_a);
--invert incoming B bit
u_NEG_B : nor_gate port map(
a => b,
b => b,
q => w_not_b);
--output a < b when /a = '0' and b = '1'
u_AND_LT : and_gate port map(
a => w_not_a,
b => b,
q => lt);
--output a > b when a = '1' and /b = '0'
u_AND_GT : and_gate port map(
a => a,
b => w_not_b,
q => gt);
--inequality logic created by XOR
u_NOT_EQ : entity work.xor_gate port map(
a => a,
b => b,
q => w_not_eq);
--invert the XOR output to get equality logic
u_EQ : nor_gate port map(
a => w_not_eq,
b => w_not_eq,
q => eq);
end architecture;
View the current design's hierarchy tree.
$ legohdl graph
INFO: Identified top-level unit: comparator
WARNING: No testbench detected.
INFO: Generating dependency tree...
--- DEPENDENCY TREE ---
\- tutorials.comparator
+- tutorials.nor_gate
+- tutorials.and_gate [A]
| \- tutorials.nor_gate
\- tutorials.xor_gate
+- tutorials.and_gate [A]
\- tutorials.nor_gate
--- BLOCK ORDER ---
[2]^- tutorials.comparator(@v0.0.0)
[1]^- tutorials.gates(@v1.0.0)
Awesome! This is how we intended our design to look.
Note: Graphs are compressed by default; meaning duplicate branches use referecnce points. Use
-expand
to see the graph completely output duplicate branches.
Export a blueprint file so we can use a plugin to build our design.
$ legohdl export
4. Defining Labels
Commonly, your workflow for your HDL projects may require project-specific files outside of the HDL code such as constraints files, test vector files, tcl scripts, etc.
Imagine our task now is to use our pseudo-plugin to implement this design for an FPGA.
Try to route (implement) our exported design using the demo plugin.
$ legohdl build +demo -route
INFO: python $LEGOHDL/plugins/demo.py -route
Error: no routing file (.csv) was found for label @PIN-MAP.
Note: Remember, the plugin produced its own error; all build commands are simply a wrapper for the entered plugin's command.
Our plugin expects a custom label to collect data for the routing step.
FPGA implementations typically require a constraints file like in this example, which lists the pin assginments for our top-level design.
For our projects, our constraints file will be .csv
files. How can we get this file into our blueprint for our plugin to use?
Add a new local label called PIN-MAP
that will search for any .csv
files within the current block.
$ legohdl config -"label.local.PIN-MAP=*.csv"
CREATED: label.local.pin-map = *.csv
Create a new file called pins.csv
.
$ legohdl new ./pins.csv -file
Copy the following contents in ./pins.csv
.
PA1,a
PA7,b
PC3,lt
PC2,gt
PC0,eq
Assume our FPGA has pins called PA1
, PA7
, PC3
, PC2
, and PC0
, that we want to map to our design's ports a
, b
, lt
, gt
, and eq
, respectively.
Export a new blueprint.
$ legohdl export
Inspecting the blueprint file, we can see legoHDL included a file under the custom PIN-MAP
label.
@PIN-MAP C:/Users/chase/develop/hdl/tutorials/comparator/pins.csv
@VHDL-LIB tutorials C:/Users/chase/.legohdl/workspaces/primary/cache/_/tutorials/gates/gates/src/gates.vhd
@VHDL-LIB tutorials C:/Users/chase/.legohdl/workspaces/primary/cache/_/tutorials/gates/gates/src/nor_gate.vhd
@VHDL-LIB tutorials C:/Users/chase/.legohdl/workspaces/primary/cache/_/tutorials/gates/gates/src/and_gate.vhd
@VHDL-SRC C:/Users/chase/develop/hdl/tutorials/comparator/src/xor_gate.vhd
@VHDL-SRC C:/Users/chase/develop/hdl/tutorials/comparator/src/comparator.vhd
@VHDL-SRC-TOP comparator C:/Users/chase/develop/hdl/tutorials/comparator/src/comparator.vhd
Now rebuild with the demo plugin and its -route
option.
$ legohdl build +demo -route
INFO: python $LEGOHDL/plugins/demo.py -route
echo PSEUDO PIN MAPPER
PSEUDO PIN MAPPER
Routing pins for device A2CG1099-1...
PA1 --> a
PA7 --> b
PC3 --> lt
PC2 --> gt
PC0 --> eq
Pin assignments complete.
Great work! We've customized our workflow to go along with our plugin.
Note: Remember, plugins are developed by you, meaning you can choose what labels to expect and what to do with the listed files in the blueprint!
Page Review
Woo-hoo! On this page, we learned how to:
- edit the template and use placeholders for generic run-time values within files
- use entities from outside the current block
- find information such as units defined for a particular block with
info
- create a label to search for particular supportive files during export and added into the blueprint
User Guide
In this chapter, you will learn how to use legoHDL for common problems and scenarios.
Converting Code
This page walks through the general procedure for transforming an already existing HDL project into a usable block within legoHDL.
Local projects
- Determine the local path of your current workspace.
$ legohdl list -workspace
-
Move the HDL project's root folder within the current workspace's local path.
-
Open a terminal at the HDL project's root folder.
-
Initialize a block and provide its identifier,
<block>
.
$ legohdl init <block>
Remote projects
-
Copy the remote repository URL (paste it where
<url>
is in the following command). -
From the terminal run, create a new block and provide its identifier,
<block>
.-
Add the
-fork
flag to detach the block from the remote repository url if you will not be able to push changes to it. -
Add the
-open
flag to optionally open the block in your configured text-editor.
-
$ legohdl new <block> -remote="<url>"
Off-The-Shelf Examples
This section lists random or popular HDL git repositories available on GitHub that are easily integrated into legoHDL.
Basic RISC-V CPU
- Project: https://github.com/Domipheus/RPU.git
- Author: Colin Riley
One-line command:
$ legohdl new cpu.riscv -remote="https://github.com/Domipheus/RPU.git" -fork -open
From the project's root directory:
$ legohdl info -more
--- METADATA ---
[block]
name = riscv
library = cpu
version = 0.0.0
remote =
vendor =
requires = ()
--- STATS ---
Location = /Users/chase/develop/eel4712c/cpu/riscv/
Size = 465.19 KB
Level = DNLD
Required by:
N/A
VHDL units:
tb_unit_decoder_RV32_01 alu_int32_div_tb
tb_unit_alu_RV32I_01 rpu_core_tb
register_set constants
core alu_RV32I
mem_controller control_unit
decoder_RV32 alu_int32_div
lint_unit csr_unit
pc_unit
Viewing the entity design hierarchy:
$ legohdl graph
INFO: Identified top-level unit: core
INFO: Identified top-level testbench: rpu_core_tb
INFO: Generating dependency tree...
--- DEPENDENCY TREE ---
\- cpu.rpu_core_tb
\- cpu.core
+- cpu.mem_controller
+- cpu.pc_unit
+- cpu.control_unit
+- cpu.decoder_RV32
+- cpu.alu_RV32I
| \- cpu.alu_int32_div
+- cpu.register_set
+- cpu.csr_unit
\- cpu.lint_unit
--- BLOCK ORDER ---
[1]^- cpu.riscv(@v0.0.0)
Everything checks out; from here you can release this block as a new version using release
and reuse any designs in a different project.
Simple UART
- Project: https://github.com/jakubcabal/uart-for-fpga
- Author: Jakub Cabal
One-line command:
$ legohdl new comms.uart -remote=https://github.com/jakubcabal/uart-for-fpga.git -fork -open
From the project's root directory:
$ legohdl info -more
--- METADATA ---
[block]
name = uart
library = comms
version = 0.0.0
remote =
vendor =
requires = ()
--- STATS ---
Location = /Users/chase/develop/eel4712c/comms/uart/
Size = 331.37 KB
Level = DNLD
Required by:
N/A
VHDL units:
RST_SYNC UART_LOOPBACK_CYC1000 UART2WBM
UART2WB_FPGA_CYC1000 UART UART_PARITY
UART_CLK_DIV UART_TX UART_DEBOUNCER
UART_RX UART_TB
Viewing the entity hierarchy:
$ legohdl graph uart -tb=uart_tb
INFO: Identified top-level testbench: UART_TB
INFO: Generating dependency tree...
--- DEPENDENCY TREE ---
\- comms.UART_TB
\- comms.UART
+- comms.UART_CLK_DIV
+- comms.UART_DEBOUNCER
+- comms.UART_RX
| +- comms.UART_CLK_DIV
| \- comms.UART_PARITY
\- comms.UART_TX
+- comms.UART_CLK_DIV
\- comms.UART_PARITY
--- BLOCK ORDER ---
[1]^- comms.uart(@v0.0.0)
Everything checks out; from here you can release this block as a new version using release
and reuse any designs in a different project. Before releasing, you could also run legohdl export -pack
to create a VHDL package file for all non-testbench design components.
Writing Plugins
This page walks through a general procedure for how a plugin could be written within the scope of legoHDL.
A plugin is loosely defined as a command. However, to be beneficial to HDL designing, these commands will typically be a wrapper of a FPGA-tool, such as quartus, GHDL, verilator, etc.
Plugins are defined under the [plugin]
section in legohdl.cfg
file.
[plugin]
backend1 = echo "hello world!"
backend2 = python c:/users/chase/hdl/plugins/ghdl.py
backend2 is a plugin that call python to run the file ghdl.py
, which is a custom user-defined script that wraps the GHDL command-line tool.
The general series of steps a plugin should follow are:
- Collect data from the blueprint file
- Perform an action with the collected data
Note: Remember, you can extend your plugin to handle its own command-line arguments for an even more customized experiences/shortcuts.
The blueprint file, if created, can be guaranteed to located from the block's base directory at /build/blueprint
after a successful export.
Pseudo-code
Here is some general pseudo-code for creating a plugin script that wraps an EDA tool's functionality.
Create data structures that will store commonly labeled files listed in the blueprint.
Open BLUEPRINT.
While BLUEPRINT has lines:
Parse the line to obtain the file's LABEL.
Determine filepath's storage based on label.
if LABEL == @VHDL-SRC
store filepath in collection of vhdl files
else if LABEL == @VLOG-SRC
store filepath in collection of verilog files
...
Close BLUEPRINT.
Handle command-line arguments to determine EDA tool's ACTION.
Route action based on command-line arguments.
if ACTION == CHECK SYNTAX
Perform linting using EDA tool.
else if ACTION == SYNTHESIZE
Perform synthesize using EDA tool.
else if ACTION == PLACE AND ROUTE
Perform place-and-route using EDA tool.
Defining a Template
A template is helpful in that it can encourage a team to use a particular coding practice and removes the need to continually write boilerplate code.
A template can exist anywhere on a user's machine.
To set a folder as the defined template, edit the template
key under the [general]
section in the legohdl.cfg
file.
[general]
template = /users/chase/develop/template/
Organize the folder's directory as fit. A block is created using the defined template by default. This means the folder is copied into a new location under the workspace's local path.
Viewing templated files
$ legohdl list -template
Relative Path Hidden
------------------------------------------------------------ --------
/.hidden/tb/TEMPLATE.vhd yes
/.gitignore -
/src/TEMPLATE.vhd -
Editing the template
To open the template folder in your configured text-editor run the following command:
$ legohdl open -template
Importing a templated file into an existing block
An existing block can have a new file based off a templated file with the following command:
$ legohdl new <file> -file=<template-file>
where <file>
is a relative non-existent path and <template-file>
is a value listed under the template's "Relative Path" column.
Use -force
to overwrite a file that already exists.
Hiding files for particular scenarios
Templates will not copy in hidden directories when creating a block.
To hide a file for availability when only needed on a case-by-case basis, nest it inside a hidden directory.
An example defining a folder named .hidden
located at the root of our template's path.
/.hidden/tb/TEMPLATE.vhd
Sharing Settings: Profiles
Managing Settings
Topic Guide
In this chapter, we go in-depth explaining legoHDL and its major concepts.
Why does legoHDL exist?
Design reuse is of importance in any development environment. For hardware designing in HDL, this is even more important as more complex designs follow a hierarchal approach. The benefits to resuing designs are identified as saving time and resources while increasing productivity.
From a VLSI Technology paper about VHDL coding techniques, design reusability means that the design is:
- able to solve a general problem
- well coded, documented, and commented
- rigorously verified
- technology independent
- synthesis tool independent
- simulator independent
- application independent
legoHDL is the solution to the design resusability challenge.
legoHDL:
-
enables developers to write code once and have it maintained in its single location; enforcing the DRY principle.
-
decouples your HDL code from EDA tools, producing highly portable designs.
-
provides quick access to previous designs for instant integration. legoHDL can return the required code to instantiate any of your designs in VHDL or Verilog.
-
empowers developers through its management commands to effortlessly install HDL code for usability, reference specific versions of a design, and release new versions.
-
sets up an environment to take advantage of natural language constructs, such as VHDL libraries and packages, that target resuability.
-
places zero to little additional work on the developer to get existing code compatible with legoHDL
Blocks
This page explains how legoHDL packages projects into blocks for reusability.
What's a block?
A block is an HDL project managed by legoHDL. At its root folder exists a special file that must be exactly called "Block.cfg".
Where do blocks live?
Blocks can exist at one or more levels:
- downloaded/developing (
D
) - installed (
I
) - available (
A
)
Downloaded/Developing
Blocks at the downloaded/developing level are projects that are currently in-development. They exist under the workspace's local path, which is defined in the legohdl.cfg file.
These blocks are considered un-stable because there designs can freely change at any time.
Installed
Blocks at the installed level are installed to the workspace's cache. Their location is abstracted away from the developer because these blocks are not to be edited. These blocks have their files stored as read-only to add a extra precautious layer to prevent accidental alterations.
These blocks are considered stable because they are "snapshots" of the project from the repository's version control history. A block can be installed under multiple versions.
Installed blocks are intended to be referenced as dependencies for blocks at the downloaded/developing level.
Available
Blocks at the available level are found in one of the workspace's vendors as having the potential to be installed for use or downloaded for further development.
What's in a block?
The files in a block can be grouped into 3 categories:
- HDL source files
- Block.cfg file
- supportive files
HDL source files
These are the project's relevant internal HDL code files written in either VHDL or verilog. External HDL code files are to be referenced and do not need to be copied into the project. External HDL files are known to be used from the Block.cfg file's block.requires
key.
Block.cfg file
A metadata file necessary for legoHDL to mark a folder as a block. Zero to minimal editing is to be done by the developer within this file.
Supportive files
All other files relevant to the current project; whether it be tcl scripts, do files, constraint files, test vectors, etc. You can integrate any filetype into your workflow by creating labels and supporting that label in a plugin.
Workspaces
This page explains how legoHDL uses workspaces to group and manage your blocks.
Workspaces allow your blocks to be found and managed for a given context. A user can have multiple workspaces for different contexts, such as for work and for hobbyist designs.
A user configures a workspace by defining a path where all downloaded blocks should exist and which vendors to link to.
Workspaces are defined as subsections in the [workspace]
section of the legohdl.cfg
file. Here is an example defining two different workspaces.
[workspace]
[.EEL4712c]
path = /Users/chase/develop/eel4712c/
vendors = (uf-ece, vhd-vault)
[.personal]
path = /Users/chase/develop/hdl/
vendors = ()
-
Workspace
EEL4712C
looks under/Users/chase/develop/eel4712c/
for downloaded blocks, and links to vendors defined asuf-ece
andvhd-vault
. -
Workspace
personal
looks under/Users/chase/develop/hdl/
for downloaded blocks, and links to no vendors.
Levels on Levels
Workspaces manage blocks at 3 different levels: downloaded/in-development, installed, and available.
-
Downloaded blocks are found within the workspace's user-defined path, sometimes called local path.
-
Installed blocks are internally managed by the workspace within a hidden folder currently found at
~/.legohdl/workspaces/<workspace>/cache/
. -
Available blocks depend on what vendors are linked to the workspace, and can be installed or downloaded.
Active Workspace
Only 1 workspace can be active at a given time. This is defined in the [general]
section of the legohdl.cfg
file.
[general]
active-workspace = EEL4712C
NOTE: The value for
active-workspace
must be a case-insensitive match with a workspace section defined under[workspace]
.
Versioning
This page explains how legoHDL handles different block versions.
Versions contain 3 distinct integer values under the semantic versioning scheme.
Here is a quick example:
v1.0.3
The first digit is the major version (1
).
The second digit is the minor version (0
).
The third digit is the patch version (3
).
Tip: Throughout this page, a
*
will indicate an arbitrary integer value in a version.
legoHDL identifies a block's different versions by checking its git repository for all the commits tagged with v*.*.*-legohdl
. This tag is automatically created during the release
command.
There are two different types of versions: partial versions and full-versions. These two version types are created to help the user determine what degree of restriction is necessary for the dependent design.
Whenever a version is installed (except for when being installed as latest
), all references to designs internal to that block are renamed with _v*_*_*
.
Full Versions
A user can install full versions. These are the exact versions spelled out to 3 integer values (v1.0.3
). When a full version is ins
Partial Versions
Partial versions are automatically handled and updated by legoHDL as a user installs/uninstalls full versions.
Installation Example
Scenario:
A block called tutorials.gates
with version v1.0.3
is to be installed so it can be used in creating new blocks. It has designs and_gate
(VHDL entity), nor_gate
(VHDL entity), and gates
(VHDL package). No other installations exist for this block in this workspace.
Every reference to and_gate
, nor_gate
and gates
for all HDL files within the tutorials.gates
block will be renamed to and_gate_v1_0_3
, nor_gate_v1_0_3
and gates_v1_0_3
, respectively.
Design transformations in the workspace's cache for tutorials.gates(v1.0.3@v1.0.3)
:
and_gate
->and_gate_v1_0_3
nor_gate
->nor_gate_v1_0_3
gates
->gates_v1_0_3
A partial version will be created under v1
. To minimize the amount of space used, partials only keep their own HDL files and will reference all other supporting files in the block's full version.
A partial version v1
will be installed.
Design transformations in the workspace's cache for tutorials.gates(v1@v1.0.3)
:
and_gate
->and_gate_v1
nor_gate
->nor_gate_v1
gates
->gates_v1
A partial version will also be created under v1.0
.
A partial version v1.0
will be installed.
Design transformations in the workspace's cache for tutorials.gates(v1.0@v1.0.3)
:
and_gate
->and_gate_v1_0
nor_gate
->nor_gate_v1_0
gates
->gates_v1_0
Why Partials?
Partial versions exist to give a dependency flexibility. If a developer chooses to say use a partial v1
, then they assume as this design improves while holding the major version constant (1
), this block can use any changes/improvements that may occur over time.
Latest Versions
You can also reference the latest
version that's installed in the cache (and also giving a dependency maximum flexibility) by using no identifier modifier when instantiating a dependent design (no design name transformations occur in the latest
version installation).
Plugins
Vendors
Intelligent Component Recognition (ICR)
Both VHDL and Verilog have limited levels of scopes; although VHDL has libraries for design units, Verilog has no such concept.
This page describes how legoHDL handles scope-overlapping.
What is scope-overlapping?
For this document, we define scope-overlapping to be when two unique design units share the same scope and identifier.
The Problem
Take two design units available for use in your legoHDL workspace.
- math.ALU:adder
- an entity named adder found in the block ALU under the library math
-- Block: math.ALU
-- Entity: adder
entity adder is
generic (
N : positive := 8
);
port (
c_in : in std_logic;
a : in std_logic_vector(N-1 downto 0);
b : in std_logic_vector(N-1 downto 0);
sum : out std_logic_vector(N-1 downto 0);
c_out : out std_logic
);
end entity;
- math.counter:adder
- an entity named adder found in the block counter under the library math
-- Block: math.counter
-- Entity: adder
entity adder is
generic (
N : positive := 32
);
port (
c_in : in std_logic;
input1 : in std_logic_vector(N-1 downto 0);
input2 : in std_logic_vector(N-1 downto 0);
sum : out std_logic_vector(N-1 downto 0);
c_out : out std_logic
);
end entity;
Scope-overlapping occurs between these two entities because they share the same identifier, which consists of their entity name and library name.
If taking a VHDL coding approach, both entities could be instantiated with the following code.
u_ADD : entity math.adder
generic map (
...
) port map (
...
);
The problem lies in that math.adder
may refer to either entity.
As the developer, your latest project involves using the adder from the counter block, yet how would legoHDL know this when the identifiers to instantiate the unit is the same?
The Solution: ICR
ICR is a scoring algorithm ran when scope-overlapping occurs in the current design. It selects the unit with the highest computed score among its contenders.
We define a contender to be those unique entities that share the same space a in scope-overlapping problem. In the problem statement above, there are 2 contenders: the adder from math.ALU and the adder from math.counter.
We define an interface as the collective combination of an entity's defined generics and ports.
We define the instance as the code that could lead to multiple entity solutions based off its identifier (math.adder
in the problem stated).
ICR gathers the interface data from all contenders as well as the interface data defined in the mapping of the instance. Based on this data and a set of known rules, it begins to calculate scores and rule out ineligible contenders.
Some rules are the following:
- +1 point is awarded to a contender for having a matching interface piece with the instance
- An output port can be omitted/left unconnected and a contender can still remain elgibile.
- If a contender's interface does not define a default value for a generic or an input port, the instance must have that generic or input port mapped. Failure to have this mapping will cause the contender to be ineligible.
- If any generic or port from the instance is not found in the contender's interface, the contender must be ruled inelgibile.
Solving the problem
Using the legohdl get
command, you as the developer would instantiate the adder from counter with the following output.
$ legohdl get math.counter:adder -inst
--- ABOUT ---
------------------------------------------------------------------------------
Block: math.counter
Entity: adder
Description:
Instantiates N full adders to create a N-bit ripple carry adder
architecture.
------------------------------------------------------------------------------
--- CODE ---
constant N : positive := 8;
signal w_cin : std_logic;
signal w_input1 : std_logic_vector(N-1 downto 0);
signal w_input1 : std_logic_vector(N-1 downto 0);
signal w_sum : std_logic_vector(N-1 downto 0);
signal w_cout : std_logic;
uX : entity math.adder generic map(
N => N)
port map(
c_in => w_c_in,
input1 => w_input1,
input2 => w_input2,
sum => w_sum,
c_out => w_cout);
Within your latest entity's architecture, you have instantiated the math.adder
entity.
architecture ...
begin
...
--please use the adder from our counter block here!
u_ADD : entity math.adder generic map(
N => N)
port map(
c_in => w_c_in,
input1 => w_input1,
input2 => w_input2,
sum => w_sum,
c_out => w_cout);
...
end architecture;
To build the latest design, we must export the blueprint file for our plugin to use.
During export, ICR is ran to determine which contender the given instance should belong to in order to complete the design hierarchy tree.
Data collected for contenders labeled as A and B:
instance | math.counter:adder (A) | math.ALU:counter (B) |
---|---|---|
N (G) | N (G*) | N (G*) |
c_in | c_in (IN) | c_in (IN) |
input1 | input1 (IN) | a (IN) |
input2 | input2 (IN) | b (IN) |
sum | sum (OUT) | sum (OUT) |
c_out | c_out (OUT) | c_out (OUT) |
Note: A '(G)' represents a generic defined, while '(IN)' and '(OUT)' represents input and output ports, respectively. Notice for the instance we are unable to determine the port directions from code. A '*' indicates it has a default value (and thus may be omitted from the instance code).
Since both A and B have the generic N, we cannot determine which one the instance belongs to yet. We move on to the ports.
contender A | contender B |
---|---|
1 | 1 |
Both A and B have an input port "c_in", and the instance must define this connection for either contender because there's no default value. However, this port gives no insight as the name is identical in both contenders.
contender A | contender B |
---|---|
2 | 2 |
Contender A has an input port "input1", which matches with a name in the instance's interface. A's score gets +1. Contender B has no such port, and thus it is ineligible. At this point ICR knows which entity the instance belongs to. We will carry the remaining checks out for completeness.
contender A | contender B |
---|---|
3 | 0 |
Contender A has an input port "input2", which matches a name in the instance's interface and thus gets +1. Contender B no longer can check against the instance interface due to being previously ineligible/disqualified.
contender A | contender B |
---|---|
4 | 0 |
Contender A's port "sum" matches with a port in the instance.
contender A | contender B |
---|---|
5 | 0 |
Contender A's port "c_out" matches with a port in the instance.
contender A | contender B |
---|---|
6 | 0 |
There are no more interface pieces in the instance to check. Scoring is done. Scores are transformed into a percentage.
contender's %-score = (contender's score) / (total instance interface elements)
contender A | contender B |
---|---|
100% | 0% |
ICR selected contender A, which was the math.counter:adder entity. This was what we wanted!
Pitfalls
There are 2 methods to instantiating a unit in VHDL and Verilog: positional association and name association. Name association is generally recommended and is the format legoHDL outputs compatible code. However, positional association is still a synthesizable construct and based on the previous problem could hinder ICR.
When positional association is used, legoHDL loses data on what the interface names are to cross-check with the contenders. The only data it can collect is on the number of connections in the instance's interface. See more examples to see how ICR performs when encountering positional association.
I don’t think there is a single synthesis tool that will support a design using more than one unique entity from the same scope-overlapping space, even though legoHDL can distinguish when each one is used in context from ICR. For this, a design may be limited to only using one of these unique entities for every scope-overlapping problem, yet all the entities are allowed to coexist through legoHDL.
This means any time the same scope-overlapping problem appears in a design, it must select the same entity every time in order to be synthesizable.
If a design would not select the same entity every time when running ICR, an extra layer of scope could be added to an entity’s name by prepending the block name to the entity name. For example, making entity ALU_adder
and entity counter_adder
. This would resolve the scope-overlapping problem and avoid running ICR entirely.
More ICR examples
positional association
Reference
In this chapter, relevant technical information is supplied for thorough review of certain concepts.
.cfg Files
This page describes technical information about the structure and syntax of configuration files (.cfg files) under legoHDL.
legoHDL stores and retrieves data from files with a .cfg
extension. This file structure has been pre-existing and loosely defined here on wikipedia. Some differences/unique features will be highlighted on this page relating to how legoHDL interprets these file types.
Syntax
- Keys and sections are case-insensitive.
- leading and trailing whitespace is trimmed from keys and regular values (indentation is ignored).
Grammar
- Sections must be on their own line (ignoring leading whitespace).
- A key declaration must be the beginning of a line (ignoring leading whitespace).
Structure
There are 4 components to legoHDL cfg files:
- comments
- sections
- keys
- values
Comments
Single-line comments are supported and must begin with a ;
.
; a comment!
Sections
Sections are enclosed with [
]
. Sections must be defined on their own line. Sections can be nested up to 2 levels; begin a section with [.
instead of [
to signify this section is nested within the immediately previously declared section.
[workspace]
[.lab] ; flattens out to section "workspace.lab"
Keys
Keys must be the first thing on a new line and followed by a =
. Keys must be a single word wihout spaces. Keys are used to define values.
public-key = 42942
secret-key = 30
Values
Values are WYSIWYG. There are three types of value intpretations: basic literals, string literals, and lists.
Basic literals
A basic literal evaluates as a string and is not encapsulated by any delimiters. Leading and trailing whitespace is trimmed. A new-line within a basic literal is converted into a space. This design implementation allows for neater formatting, increasing user readability.
basic-key = What you see is what you get!
summary = This is a long block of text. In order to keep readability a priority,
newlines will be treated as a space and the leading whitespace for
each line will be ignored.
String literals
A string literal evaluates as a string and allows for any character to be stored within the string except the delimiting character ("
).
; a key that captures the ';' character
true-key = "Do not touch; this is important!"
; a key that captures the '=' character
question = "Does P = NP ?"
Lists
A list evaulates each item as either a string literal or basic literal. The value must begin with a (
character and end with a )
character. Items are separated by a ,
character.
; this key lists items of basic literals
list-key = (item1, item2, item3)
; this stores a combination of string literals and basic literals
combo-key = (
"0",
200,
"1",
300
)
Commands
In this chapter, reference is provided for how to interface with legoHDL. The commands are loosely divided into two main categories: development and management.
Tip: How to Read Commands
The basic usage structure for every command is:
legohdl <command> [item] [flags]
Everything written after the call to legohdl
is considered an argument. All commands and flags are evaluated as case-insensitive.
A flag must start with a -
. Flags are used to control how the command functions.
-comp
Any time < >
are used, the string within the < >
is used as a hint as to what the value should be to replace the entire < >
.
<block>
Any time [ ]
are used, that argument is optional.
[-open]
Any time ( )
are used, the arguments grouped within only function together.
(-url [-fork])
Any time |
is used, only one of the arguments in question can be chosen per call (this is an OR operator).
-profile | -template
Sometimes a flag can store a value, in that case a =
follows the name of the flag along with the desired value.
-comp=vhdl
Quotes can be used to make sure a flag or value is correctly captured on the command-line.
-comp="vhdl"
Development Commands
new
Name
new - Create a new legoHDL block (project)
Synopsis
legohdl new <block> [-open] [-remote=<url> [-fork]] [-path=<path>]
[-no-template]
legohdl new <file> -file[=<template-file>] [-force] [-no-open]
Description
Create a new HDL project recognized by legoHDL as a "block". The block
will be created under a new folder at the workspace's local path such
as <workspace-path>/<block-library>/<block-name>. A git repository will
be automatically created, and a bare git remote repository URL can be
passed for automatic configuration. If a non-bare remote repository is
passed, the block will be created and can be optionally forked using
-fork.
When copying in the template, files hidden within a hidden directory
will not be copied. The files a designer would place inside a hidden
directory may be extra files that could be initialized later on a
per-block basis.
If trying to create a new file and that path already exists, the
existing file will not be overwritten unless -force is used. Creating
new files by default will auto-open in the configured text editor.
Options
<block>
The project's title. A library and a name must be included, and
optionally a vendor can be prepended to the title.
-open
Upon creating the block, open it in the configured text-editor.
-remote=<url>
A bare remote git repository to be attached to the created block's
git repository.
-fork
Separate the remote repository from the local repository. Do not
push changes to the original remote.
-path=<path>
Overrides the default download path and instead creates block at
<path> relative to the workspace's local path.
-no-template
Do not copy in the configured template folder. The created block
folder will only contain the necessary Block.cfg file.
<file>
The filepath to intialize a new file.
-file[=<template-file>]
Initialize a new file within the current block. Specifying
<template-file> will copy the template file to the desired directory
with placeholders correctly replaced. Omitting <template-file> will
create a blank file.
-force
Overwrite the filepath even if it already exists when initializing a
file.
-no-open
Do not open the newly created file in the configured editor.
init
Name
init - Initialize a legoHDL block from existing code and block metadata.
Synopsis
legohdl init <block> [-remote=<url> [-fork]] [-vendor=<mkrt>]
[-summary=<summary>]
Description
When the current directory or provided remote repository already is a
valid legoHDL block, the <block> is ignored.
When a remote repository is given and it already is a valid block (i.e.
the root directory contains a Block.cfg file), the <block> will be
ignored and the actual title will be used. This becomes an equivalent to
using the 'download' command.
Options
<block>
:ref:
-remote=<url>
:ref:
-fork
Do not link to the remote repository and try to push any changes
to the provided <url>.
-vendor=<vndr>
Set the block's vendor. <vendor> must be a valid vendor
available in the current workspace.
-summary=<summary>
Fill in the summary for the block's metadata. <summary> is a
string that describes the current block.
open
Name
open - Use a text-editor to open a variety of legoHDL-related things
Synopsis
legohdl open <block>
legohdl open [<plugin-alias>] -plugin
legohdl open <profile-name> -profile
legohdl open (-template | -settings[=<mode>])
legohdl open <vendor-name> -vendor
Description
:todo:
Options
<block>
:ref:
<plugin-alias>
The alias for the saved custom plugin within legoHDL. It is a
user-defined key in settings under "plugins". If the alias's value
is a command that references a real existing file, that file will be
opened.
-plugin
The flag to indicate a plugin is trying to be opened. If no
<plugin-alias> value is given with this flag, the built-in plugins
folder will be opened.
<profile-name>
The profile configuration name stored within legoHDL settings. When
valid, that profile directory will open.
-profile
The flag to indicate a profile is trying to be opened.
-template
The flag to indicate the template is trying to be opened. If the
configured template value in settings is blank, the built-in
template folder will be opened.
-settings[=<mode>]
The flag to indicate the settings are trying to be opened.
<mode> determines how to open the settings. Accepted values are gui
and file. When omitted, the default is to open the settings in gui
mode.
get
Name
get - Print the compatible code for the ports list of a specified unit
Synopsis
legohdl get [<block>:]<unit> [-comp[=<lang>]] [-inst[=<lang>]] [-arch]
[-edges] [-D | -I] [-no-about]
Description
When trying to access current block-level entities, the <block>
can be omitted (a form of shortcutting). To reference a unit,
<vendor>.<library>.<project>:<unit>.
By default, it will print the 'about' section and the component
declaration for VHDL entities or the module interface for Verilog
modules. This is the comment header block found at the beginning of this
unit's file (if exists). Helpful to read more information about an unit
and how it behaves (if a developer wrote one).
If -comp is present when -inst is also present and the language
outputted is VHDL, the returned VHDL instantiation code will be a
component instantiation. If -comp is omitted in this scenario,
the returned VHDL instantiation code will be a direct entity
instantiation.
The <lang> assignment from -inst has higher precedence of the <lang>
assignemnt from -comp when both are present.
Options
<block>
The block's title. If omitted, the <entity> is searched for only
within the current block's scope.
<unit>
The design unit name. For VHDL this is a package or entity, and
for Verilog this is a module.
-comp[=<lang>]
Print the component declaration. For Verilog language, the
module interface is printed instead of a component declaration.
<lang> specifies what HDL language to use to print the formatted
code. Accepted values are vlog and vhdl. Omitting <lang> prints
the code in the entity's original language.
-inst[=<lang>]
Print the direct entity instantiation (VHDL-93 feature) or
component instantiation. This includes relevant constants for
each generic, relevant signals for each port, and the
instantiation code.
<lang> specifies what HDL language to use to print the formatted
code. Accepted values are vlog and vhdl. Omitting <lang> prints
the code in the unit's original language.
-arch
List the available architectures. If the unit is a Verilog
module, only "rtl" will be listed.
-edges
Print the units are required by this unit and print the units
that integrate this unit into their design. Gets the edges from
the hierarchical graph.
-D
Search the downloaded blocks to get this unit, regardless of
the status of 'multi-develop'.
-I
Search the installed blocks to get this unit, regardless of
the status of 'multi-develop'.
-no-about
Do not print the 'about' section for the given design unit.
graph
Name
graph - Visualize the dependency tree for the design
Synopsis
legohdl graph [<entity>] [-tb=<tb> | -ignore-tb] [-expand] [-disp-full]
Description
Create and view the dependency tree for the current block design. This
command is provided as a guide to quickly help the designer see how the
design unfolds.
When no <entity> is given, the top-level will be auto-detected and the
user will be prompted to select one if multiple exist. When -ignore-tb
and -tb=<tb> are absent, the testbench for the top-level entity will be
auto-detected, if one exists. The user will be prompted to select one if
multiple exist.
By default, the graph is in compression mode and will create reference points
when a duplicate branch occurs. Raising -expand will explicitly display all
branches without reference points.
Options
<entity>
The design unit to request as top-level.
-tb=<tb>
The relevant testbench file to explicitly include in the
dependency tree. Has higher precedence of -ignore-tb.
-ignore-tb
Do not include any testbench unit in the dependency tree.
-expand
Decompress reference points into their duplicate branchs.
-disp-full
Display full block identifiers for each unit.
export
Name
export - Generate a blueprint file or VHDL package file
Synopsis
legohdl export [<unit>] [-tb=<tb> | -ignore-tb] [-quiet] [-no-clean]
[-all]
legohdl export -pack[=<file>] [-omit=<units>] [-inc=<units>]
Description
-ignore-tb has higher precedence than when a <tb> is stated.
For generating a VHDL package file, passing -inc will ignore -omit if it
is passed to the command-line as well. -inc has higher precedence than
-omit.
The default VHDL package file name is the block's project name appended
with '_pkg', and its path will be located at the same directory of the
Block.cfg file. Override its location and name by entering a <file>.
Testbench units (design units with no port interfaces) are always
omitted.
Options
<unit>
The design unit to request as top-level. All relevant HDL files
will stem from this unit's file.
-tb=<tb>
Explicitly request what top-level simulation file to include in
the blueprint.
-ignore-tb
Do not include a testbench file in the blueprint.
-quiet
Do not print intermediate information while the blueprint file
is being created.
-no-clean
Do not delete the build/ directory when writing the blueprint.
-all
Add all block-level source files and their dependencies.
-pack[=<file>]
Create a VHDL package file with component declarations for the
current block. Optionally add a relative path and file name for
<file>.
-omit=<units>
Specific list of units to exclude when generating the package
file. <units> is a list separated by ','.
-inc=<units>
When given, it will only allow these explicit units to be
included in the VHDL package file. <units> is a list separated
by ','.
build
Name
build - Execute a custom backend plugin/tool command
Synopsis
legohdl [build] +<plugin-alias> [<plugin-args...>]
Description
:todo:
Options
<plugin-alias>
The alias for the saved custom plugin within legoHDL. It will
execute the command as if it was called through the terminal.
<plugin-args...>
Any additonal arguments to pass directly to the called command.
All arguments after <plugin-alias> will be passed to the
executed command.
release
Name
release - Set a newer version for the current block
Synopsis
legohdl release <version> [-msg=<msg>] [-strict] [-dry-run]
[-no-changelog] [-no-install]
Description
:todo:
Options
<version>
The next version for the current block. The value must be either
major, minor, patch, or an explicit version.
-msg=<msg>
The message to commit with. The value for <msg> is a string and
if the string includes spaces then quotes must encapsulate
<msg>. The default message is: "Releases legohdl version
<version>".
-strict
Only adds and commits the modified changelog (if exists) and the
Block.cfg file. All other uncommitted changes will not be in
the following release.
-dry-run
Perform the complete release process as-if the block was to be
released, but leaves the block unmodified and unreleased.
-no-install
Will not automatically install the latest version to the cache.
-no-changelog
Skip auto-opening a changelog file (if exists) during the
release process.
del
Name
del - Remove a variety of legoHDL-related things
Synopsis
legohdl del <block> [-uninstall]
Description
:todo:
Options
:todo:
Management Commands
list
Name
list - View a variety of legoHDL-related things
Synopsis
legohdl list [<search>] [[-unit [-all] [-ignore-tb]] | [-D] [-I] [-A]] [-alpha]
legohdl list [-plugin | -label | -vendor | -workspace | -profile |
-template]
Description
Retrieves a requested data from the catalog.
When passing a value for <search>, each subsection of a block's
identifier can be omitted. With each additionally provided subsection,
the values shift left to the next subsection. See EXAMPLES for more
information.
Options
<search>
Optional field to narrow the given list by.
-unit
Instead of listing blocks, list the units.
-alpha
Organize the list in alphabetical order.
-I
Filter only installed blocks or units.
-D
Filter only downloaded blocks or units.
-A
Filter only available blocks or units from vendors.
-all
Display all units, regardless if they are usable or not
according to what 'multi-develop' is set to.
-plugin
Return the list of plugins. Fields are alias and command.
-label
Return the list of labels. Fields are label, extensions,
and global.
-vendor
Return the list of vendors. Fields are vendor, remote
repository, block count, and active.
-workspace
Return the list of workspaces. Fields are workspace, active,
path, and vendors.
-profile
Return the list of profiles. Fields are profile, last import,
legohdl.cfg, template/, and plugins/.
-template
Return the list of all availble files from the current template.
These files can be referenced exactly as listed when
initializing a new file with the 'init' command.
Examples
legohdl list lab0
Since a vendor is omitted and a library is omitted, all blocks
starting with "lab0" in their name are returned.
legohdl list eel4712c.
Since a vendor is omitted and a name is omitted, all blocks
starting with "eel4712c" in their library are returned.
legohdl list uf-ece..
Since a library is omitted and a name is omitted, all blocks
starting with "uf-ece" in their vendor are returned.
legohdl list ..:mux_2x1 -unit
All V.L.N subsections are blank, so the entire catalog is
searched to see if an unit exists with the name "mux_2x1".
refresh
Name
refresh - Synchronize local vendor repositories with their remotes
Synopsis
legohdl refresh [<vendor> | -all]
legohdl refresh [<profile> | -all] -profile
Description
Checks for updates from vendor remote repositories and pulls them down
to stay up-to-date.
If no arguments are given, by default all vendors available to the
current workspace will try to refresh. If -all is given, every possible
vendor, even outside workspace availability, will sync with its remote
(if exists).
Options
<vendor>
The name of the known vendor to synchronize.
-all
Synchronize all profiles or vendors across all workspaces.
<profile>
The name of the profile to syncrhonize.
-profile
Flag to indicate that a profile is trying to be refreshed.
install
Name
install - Bring a block to the workspace's cache for usage
Synopsis
legohdl install <block> [-<version> | -requirements]
Description
Options
uninstall
Name
uninstall - Remove a block from the workspace's cache
Synopsis
legohdl uninstall <block> [-<version>]
Description
Removes installed block versions from the workspace cache.
If -<version> is omitted, then ALL versions for the specified block will
be removed. Specifying -<version> will only remove it and no others,
given it is installed.
Can also remove groups of versions by passing a partial version to
-<version>.
Options
<block>
:ref:
-<version>
Specific version to uninstall.
download
Name
download - Bring a block to the local workspace for development
Synopsis
legohdl download (<block> | (<url> [-fork])) [-open] [-path=<path>]
Description
Options
-path=<path>
Overrides the default download path and instead creates block at
<path> relative to the workspace's local path.
update
Name
update - Get the latest installed block or profile
Synopsis
legohdl update <block>
legohdl update <profile-name> -profile
Description
<block>
:ref:
<profile-name>
:todo:
-profile
:todo:
Options
info
Name
info - Read detailed information about a block
Synopsis
legohdl info <block> [-D | -I | -<version> | -A] [-more]
[-vers[=<range>]] [-changelog]
legohdl info <profile> -profile
legohdl info <vendor> -vendor
Description
By default, will print the metadata about the given block.
If -vers is applied, it will list all the available versions for
installation, and hightlight which versions are installed under the
workspace cache.
If -changelog is applied, only the changelog file will be printed to
the console (if exists).
Options
<block>
:ref:
-D
Return data from block at the download level, regardless of
the status of 'multi-develop'.
-I
Return data from latest block at the installation level,
regardless of the status of 'multi-develop'.
-<version>
Return data from the block with specified version/partial
version.
-A
Return data from the block at the available level.
-more
Get relevant stats about the block such as the path, project
size, design units, and block integrations.
-vers[=<range>]
List all available versions for the specified block. <range>
will constrain the list of versions. Accepted values for <range>
are I or a version indexing.
-changelog
Print the associated changelog with the block.
<profile>
:ref:
-profile
Indicate that a profile is to be searched for its information.
<vendor>
:ref:
-vendor
Indicate that a vendor is to be searched for its information.
config
Name
config - Edit/modify legoHDL settings
Synopsis
legohdl config <profile-name> [-ask]
legohdl config [-<keypath>[(+ | -)]=<value>] [-<sectionpath>]
Description
:todo:
Options
<profile-name>
An existing profile to import settings from.
-ask
Prompts the user before each import step (settings, template,
plugins) if the following should be imported and overloaded.
:todo:
Glossary
Argument
An argument is a string/value proceding a call to a software program on the command-line that will be passed to that program.
Available
Available refers to a level at which the block is seen in the catalog. A block has available status (A) when the block is within a vendor that is linked to the active workspace. Blocks cannot be used nor opened from this level.
Backend Tool
In this context, a backend tool is a software program capable of performing a specific task on HDL files. Some examples are: Quartus, Vivado, and GHDL.
Block
A legoHDL block is a project that contains a special Block.cfg metadata file at its root folder. These are the "packages" that this package manager manages.
Since a block contains the HDL code, blocks therefore contain HDL units.
Block.cfg
The Block.cfg file is a metadata configuration file that follows similiar syntax to that of an ini file. legoHDL uses this file to mark that folder as a block.
Block Identifier
A block identifier is a unique case-insensitive title for a block composed of 3 sections: vendor, library, and name. An identifier's sections are separated by a dot (.
). The vendor section is optional and can be left blank.
Blueprint
A blueprint is the outputted plain text file when a block is exported for building. It mainly consists of labels and their respective file paths. A blueprint is the "glue" between legoHDL and any plugin.
This file is always created in the build/
directory found at the root of the current block.
Catalog
The catalog is the list of searchable blocks within the current active workspace. Blocks can exist at 3 levels within the catalog: downloaded (D), installed (I), and/or available (A).
Development Tool
A development tool is a software program specialized for a particular language that automates specific tasks to developing new projects for that language.
Downloaded
Downloaded refers to a level at which the block is seen in the catalog. A block has download status (D) if the block is within the active workspace's local path. Blocks that are downloaded are said to be "developing" or "in-development".
Blocks can be used from this level within other blocks only if the multi-develop
setting is enabled.
Flag
A flag is a special type of argument that controls or modifies how the specified command will function.
Full version
A full version contains all 3 parts of a semantic version (version v*.*.*
). Also related: partial version.
Hardware Description Languages (HDLs)
Hardware Description Languages are a type of specialized computer language to describe electronic circuits. Two popular HDLs are VHDL and verilog.
Installed
Installed refers to a level at which the block is seen in the catalog. A block has install status (I) when the block is within the active workspace's cache.
Installed blocks are considered stable and are able to be used within blocks in-development.
Intellectual Property (IP)
Intellectual Property is a created design. The HDL designs within legoHDL blocks can be considered IP.
Label
A label is a unique name given to a group of files defined by their file extension. Defined labels are written to the blueprint file. Every label is evaluated as all upper-case and will have an @
symbol preceding it.
Special default labels are:
VHDL-SRC
,VHDL-SIM
,VHDL-LIB
,VHDL-SRC-TOP
,VHDL-SIM-TOP
for VHDL filesVLOG-SRC
,VLOG-SIM
,VLOG-LIB
,VLOG-SRC-TOP
,VLOG-SIM-TOP
for Verilog files
legohdl.cfg
The legohdl.cfg file contains the system-wide configuration settings for legoHDL. Its file format is based off of INI configuration files.
Library
A library is the namespace that encapsulates blocks. When using VHDL entities or packages, this is also those respective library.
Package Manager
A package manager is a software program used to automate the finding, installing, and uninstalling of modular groups of related files ("packages").
The "packages" this package manager maintains are called blocks.
Partial version
A partial version consists of either 1 or 2 of the most significant parts of a semantic version (version v*
or version v*.*
). Also related: full version.
Placeholder
A placeholder is a temporary word that will be replaced by a value that cannot be determined until run-time. legoHDL finds all placeholders when creating a file and replaces them with their determined value.
All placeholders are enclosed with %
symbols, except the TEMPLATE
placeholder.
Plugin
A plugin is a custom program to build the current block's design. It can consist of an executable or script written in any language to call any desired tool to perform any task such as linting, simulation, synthesis, generating a bitstream, or programming a bitfile to a target FPGA. A plugin commonly either wraps or directly is a backend tool.
In general, a plugin should read the blueprint file to collect necessary data regarding what files are used for the current design. It is up to the plugin's developer to do what they want with the blueprint's collected information.
Profile
A profile is a folder/repository that is a combination of settings defined in a legohdl.cfg
file, a template defined in a template/
folder, and/or a set of plugins defined in a plugins/
folder. Profiles are used to share or save particular legoHDL configurations.
Project
A project is a folder containing HDL code and optionally any supporting files.
Semantic Versioning
Semantic Versioning is a popular versioning scheme consisting of 3 different levels of numerical significance: major, minor, and patch.
Shortcutting
Shorcutting refers to only giving legoHDL partial information about a block's identifier, given that it can logically deduct the rest of the identifier based on what identifier's exist.
Unit
A unit is a "piece of hardware" described in HDL. This is called an entity in VHDL and a module in Verilog.
Vendor
A vendor is the namespace that encapsulates libraries. Furthermore, a vendor can be a repository that tracks all of the blocks belonging to it by storing their metadata.
A block does not have to belong to a vendor. If no vendor is specified for a block, then by default it belongs to the null vendor.
Verilog
Verilog is a hardware description language used to model and structure digital circuits. It is one of the major languages legoHDL supports.
VHDL
VHSIC Hardware Description Language, or VHDL, is a hardware description langauge used to model and structure digital circuits. It is one of the major languages legoHDL supports.
Workflow
A workflow is a developer's particular needs and actions required on HDL source files. The typical HDL workflow consists of linting, synthesis, simulation, implementation, generating a bitstream, and programming a bitfile to a target FPGA.
Developers define their own workflow by writing plugins based on their available tools, environments, and needs.
Workspaces
Workspaces define what vendors to use and the local path to search under for blocks that are downloaded/under-development. Each workspace has its own cache for block installations, but can share vendors.