legoHDL Documentation

legoHDL title

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:

  1. Tutorials - step-by-step lessons working with legoHDL
  2. User Guide - general procedures for "how-to" solve common problems
  3. Topic Guide - explanations that clarify and provide more detail to particular topics
  4. 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

  • python (version 3.5+)
  • git
  • your favorite text-editor

Some recommended text-editors:

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

  1. Clone the project from GitHub

$ git clone https://github.com/c-rus/legoHDL.git

  1. Install the python program using PIP

$ pip install ./legoHDL

  1. Delete the cloned project.

ubuntu | macos: $ rm -r ./legoHDL

windows: $ rmdir /S ./legoHDL

  1. Verify legoHDL is installed.

$ legohdl --version

Installing from PYPI

Note: This method is currently unavailable.

  1. Install the python program using PIP

$ pip install legohdl

  1. 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.

  1. First Project: Gates
  2. Referencing Blocks: Comparator

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
  2. Building
  3. Releasing

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.

and_from_nor

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.

ABQ
000
010
100
111

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:

  1. Below the line --declare DUT component, copy and paste the component declaration.
  2. Below the line --declare constants/signals, copy and paste the I/O connection signals.
  3. 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.

  1. Editing the template
  2. Creating XOR gate
  3. Creating a Comparator
  4. Defining Labels

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.

xor_from_nor

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

  1. Determine the local path of your current workspace.
$ legohdl list -workspace
  1. Move the HDL project's root folder within the current workspace's local path.

  2. Open a terminal at the HDL project's root folder.

  3. Initialize a block and provide its identifier, <block>.

$ legohdl init <block>

Remote projects

  1. Copy the remote repository URL (paste it where <url> is in the following command).

  2. 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:

  1. Collect data from the blueprint file
  2. 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 as uf-ece and vhd-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.

  1. Downloaded blocks are found within the workspace's user-defined path, sometimes called local path.

  2. Installed blocks are internally managed by the workspace within a hidden folder currently found at ~/.legohdl/workspaces/<workspace>/cache/.

  3. 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:

instancemath.counter:adder (A)math.ALU:counter (B)
N (G)N (G*)N (G*)
c_inc_in (IN)c_in (IN)
input1input1 (IN)a (IN)
input2input2 (IN)b (IN)
sumsum (OUT)sum (OUT)
c_outc_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 Acontender B
11

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 Acontender B
22

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 Acontender B
30

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 Acontender B
40

Contender A's port "sum" matches with a port in the instance.

contender Acontender B
50

Contender A's port "c_out" matches with a port in the instance.

contender Acontender B
60

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 Acontender 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 files
  • VLOG-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.