Block Preview

Introduction

Principle of Operation

User HDL lets you drop a hand-written VHDL entity straight into a schematic. You do three things:

  1. Type (or paste) one VHDL file into the built-in editor.
  2. Name the entity in that file — the Main Entity Name.
  3. Declare that entity’s ports, one row per port, in the table next to the editor.

The block then draws itself: one pin per declared port, input pins on the left, output pins on the right. At compile time the code is written out into the project’s pcores folder and instantiated, with your pins connected to the ports of the same name.

The code lives inside the project file (base64-encoded in a property), so a project is self-contained: no external folder to keep in step.

Relationship to Custom HDL (NEW)

This block predates Custom HDL (NEW) (Custom HDL (NEW), version 2.0.0.0) and both are still registered and shipped in the same plugin. Nothing was removed and nothing was deprecated in code: a design that uses User HDL keeps compiling exactly as before.

That said, the newer block is a strict superset for anything new, and the differences are not cosmetic:

User HDL (this block) Custom HDL (NEW)
Files per block exactly one — only the top file is written out many; sub-components are written alongside the top
Generics none — no generic is ever passed to your entity INTEGER, BOOLEAN, STRING, STD_LOGIC, STD_LOGIC_VECTOR, TIME, REAL
Verilog listed in the property, but the file is always written as .vhd written as .vhd or .v following the Language setting
Text encoding ASCII — non-ASCII characters in your code are mangled UTF-8
Entity-end syntax accepted only end <name>; / end <name> ; also end entity <name>; and bare end entity;
Port discovery typed by hand into the table typed by hand or scanned out of the HDL
Syntax checking none GHDL, in the editor
Editor Scintilla, single buffer Monaco, file tree, hierarchy view

Which one to use: for a new design, use Custom HDL (NEW). Reach for User HDL only when you are maintaining an existing block, or when you want the simplest possible thing: one small entity, no generics, no sub-components. There is no automatic converter — migrating means creating a new block and re-entering the code and the port table.

If you would rather keep the HDL in files on disk, under your own version control, use User HDL Link instead: same idea, but the sources stay in an external folder.

Pin Description

User-defined ports Input Programmable bit

All pins on this block come from the port table. There are no fixed pins: the symbol is rebuilt from the stored port list every time the interface changes, one pin per row, named after the Port Name column and placed left or right according to Direction.

Pin width follows Port Size, except:

  • Any Size rows take the width of the net they are wired to;
  • STD_LOGIC_VECTOR_TM rows are instantiated as a flat vector of Port Size × Time Multiplexing bits.

An unconnected input pin is not an error. What it is tied to depends on the Function column: the typed Default Value for Port, the project acquisition clock for Clock, the project global reset for Reset.

Properties

Interface Definitions InterfaceDefinition

JSON with list of interfaces

The port table, serialised as JSON. Each entry carries PortName, PortType (Port / Clock / Reset), Size, Direction, DataType, TimeMultiplexing, AnySize and DataDefault.

Managed by the HDL editor — edit it there, not in the property grid. Changing it rebuilds the symbol.

Default: empty — a block with no ports draws as an empty box.

Entity Entity

VHDL/Verilog user code (encoded in base64)

The HDL source itself: a JSON container holding one file whose content is base64-encoded ASCII, plus the top-file index and the language.

Despite the name this is the code, not the entity name — that one is in EntityName.

Managed by the HDL editor.

Default: empty

Code Language CodeLanguage

Select between VHDL and Verilog

Language selector for the editor’s syntax colouring and for the stored file type.

Value Effect
VHDL the intended, fully supported setting
Verilog selectable, but the compiler still writes the file as .vhd

Use Custom HDL (NEW) if you need a Verilog source to be emitted as .v.

Default: empty (the editor opens on VHDL)

Options: VHDL Verilog

Mode Mode

Select between text input and file mode

Intended to switch the block between typing code into the editor (Text) and referencing files (File).

The legacy editor only ever reports Text, so File is never actually selected and the property has no effect on what is compiled. For the file-on-disk workflow use the User HDL Link block.

Default: empty (behaves as Text)

Options: Text File

List of File FileList

JSON array list of file in the component

A JSON array of files, kept for the unimplemented File mode. It is never read by the compiler and never written by the editor.

Default: empty

Main Entity Name EntityName

Specify the entity in the code that is bounded to the I/O of the block

The Main Entity Name: the name of the entity in your code that this block binds its pins to. It must match the entity … is, end …; and architecture … of … is lines in the source, and it is also what every <NAME> token in the code is replaced with when you save.

It becomes part of the emitted file name and of the unique entity name (<designator>_UserHDL_<EntityName>), and it is shown in the block caption as HDL - <EntityName>.

Changing it rebuilds the symbol. The editor refuses to save while it is empty.

Default: empty

⚙️ Detailed Operation

The editor

Double-click the block to open the HDL editor. It has three parts:

  • a Scintilla code editor with VHDL syntax colouring;
  • a Main Entity Name box and a Code Language selector (VHDL / Verilog);
  • the port table, with Add / Delete buttons.

Editor shortcuts:

Keys Action
Ctrl+F incremental search
Ctrl+Shift+F find all
F3 / Shift+F3 find next / previous
Ctrl+H replace
Ctrl+G go to line
Ctrl+Q / Ctrl+W comment / uncomment selection

A convenience worth knowing: on save, every occurrence of the literal token <NAME> in your code is replaced by the text in the Main Entity Name box. Writing entity <NAME> is … end <NAME>; means you only have to rename the block in one place.

Saving is refused, with You must define an entity as TOP, if the Main Entity Name box is empty.

The port table

One row per port of your entity. The columns map one-to-one onto what the compiler does:

Column Values Effect
Function Port, Clock, Reset what to connect when the pin is left open — see below
Port Name text must match the port name in your VHDL, and becomes the pin caption
Port Size integer bit width
Direction IN, OUT pin side
Type STD_LOGIC, STD_LOGIC_VECTOR, STD_LOGIC_VECTOR_TM, INTEGER the VHDL type of the port
Any Size checkbox width is taken from whatever net you wire to the pin
Time Multiplexing integer TM factor, only meaningful for STD_LOGIC_VECTOR_TM
Default Value text what an unconnected Port input is tied to

A new row is created as Port / PORT1 / 32 / IN / STD_LOGIC_VECTOR / not any-size / TM 0 / no default.

Function decides what happens when a pin is left unconnected on the schematic:

  • Port — the pin is tied to the Default Value you typed.
  • Clock — the pin is tied to the project’s acquisition clock.
  • Reset — the pin is tied to the project’s global reset.

Clock and Reset ports must be STD_LOGIC, or STD_LOGIC_VECTOR of size 1. Anything else is a compile error (see the message table below).

Time-multiplexed ports. A port declared STD_LOGIC_VECTOR_TM with a TM factor of k appears on the symbol as a TM pin, but is instantiated as a plain STD_LOGIC_VECTOR of Port Size × k bits. Your entity must declare it that way: the TM packing is a schematic-level convention, the block passes the flat vector.

Any Size. Ticking it makes the pin adopt the width of the net it is connected to. Your entity still has to be able to take that width — there are no generics in this block, so in practice this is only useful for a port whose width you already know matches.

What the compiler does

For a block with designator U12, component name UserHDL and Main Entity Name my_filter, the compiler:

  1. Base64-decodes your file (as ASCII).

  2. Collapses every run of two or more spaces into one. This normalised text is both what the parser searches and, importantly, what is written to disk — so aligned columns in your source come out squashed in the generated file. Tabs and newlines are untouched.

  3. Checks that all three of the following appear, case-insensitively:

      entity my_filter is
    end my_filter;          (or  end my_filter ;)
    of my_filter is
      
  4. Renames all three to the unique name U12_UserHDL_my_filter, so two copies of the same block in one design do not collide.

  5. Writes pcores/U12_UserHDL_my_filter.vhd.

  6. Emits the instantiation, connecting each declared port to its pin (or to the default / clock / reset if the pin is open).

Compiler messages

Message Type Meaning
<unique name> Connecting signal: <port> info one line per port that was wired
Unable to find the entity: <name>. Please verify your HDL custom code. This parser has looked for the following string in your code: error followed by the three patterns it looked for and the line If even one is missing or mispelled the compilation of custom HDL block is halted by the parser
Unable to find the entity: <name>. Clock signal must be or STD_LOGIC or STD_LOGIC_VECTOR with size 1 error a port with Function = Clock has the wrong type or a width other than 1
Unable to find the entity: <name>. Reset signal must be or STD_LOGIC or STD_LOGIC_VECTOR with size 1 error same, for Function = Reset
Error occoured in custom HDL block. Error message is: <exception> error the stored JSON could not be decoded — usually a block whose editor was never opened, or corrupted properties

Example

A small counter, written so that the <NAME> trick does the renaming:

vhdl
  library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity <NAME> is
    Port (
        CLK    : in  STD_LOGIC;
        RESET  : in  STD_LOGIC;
        ENABLE : in  STD_LOGIC_VECTOR(0 downto 0);
        COUNT  : out STD_LOGIC_VECTOR(15 downto 0)
    );
end <NAME>;

architecture Behavioral of <NAME> is
    signal cnt : unsigned(15 downto 0) := (others => '0');
begin
    process(CLK)
    begin
        if rising_edge(CLK) then
            if RESET = '1' then
                cnt <= (others => '0');
            elsif ENABLE(0) = '1' then
                cnt <= cnt + 1;
            end if;
        end if;
    end process;

    COUNT <= std_logic_vector(cnt);
end Behavioral;
  

The matching port table:

Function Port Name Size Direction Type Any TM Default
Clock CLK 1 IN STD_LOGIC 0
Reset RESET 1 IN STD_LOGIC 0
Port ENABLE 1 IN STD_LOGIC_VECTOR 0 "1"
Port COUNT 16 OUT STD_LOGIC_VECTOR 0

With CLK and RESET marked as Clock and Reset, those two pins can simply be left open on the schematic and they will pick up the project clock and reset.

Where it can be used

The block is available on every board, on subpages, and inside state machines. It owns no endpoint and no registers: it is pure logic, invisible to software.

Quick reference

Item Value
Files one, stored in the project (base64, ASCII)
Generics not supported
Emitted file pcores/<designator>_UserHDL_<entity>.vhd
Entity renaming automatic, so the block can be instantiated many times
Registers / endpoint none
Successor Custom HDL (NEW) — use it for new designs

Resources & Timing

  • The block adds no logic of its own: resource usage is exactly that of the entity you wrote, plus any width adaptation the schematic wiring needs.
  • The source is written to pcores/ on every compile, so editing the block is enough — there is nothing to copy by hand.
  • The generated file is the whitespace-normalised copy of your code (runs of two or more spaces collapsed to one), not a byte-for-byte copy.
  • No endpoint, no registers, no SDK output.