JanusHDL

Diagnostics, rules and compatibility mode

Last updated: 

JanusHDL checks your design against the VHDL standard, IEEE 1076 (the LRM), and reports every violation it finds: where it is, why it is wrong, how to fix it, and which section of the LRM says so. This chapter explains how to read those messages, how to change how each kind of message is reported, and how to run existing code that the standard forbids but whose meaning is clear.

The same analyzer, with the same messages, runs on the command line, in the window's code editor and in the language server.

Reading a message

error[undeclared]: `x` is not declared
 --> bad.vhd:8:10
  |
8 |     s <= x;
  |          ^
  = help: check the spelling, or add the use clause that makes it visible
  = LRM 12.3
Part Meaning
error The severity: error stops the analysis of the design; warning does not.
[undeclared] The rule the message belongs to: a stable name, to search for and to configure.
`x` is not declared What is wrong.
--> bad.vhd:8:10 The file, line and column.
The source line with ^ marks The text in question.
= help: How to fix it.
= LRM 12.3 The section of the LRM (IEEE 1076-2019) with the rule.

When analysis finds errors, jhdl prints them all and ends with analysis failed (exit code 1). Warnings are printed and the run goes on.

Fix the first error first

A design unit with an error is not added to its library (as the LRM says). Each unit that needs it then reports, once, that its analysis failed and where its errors are:

error[call-before-body]: `twice` is called before its body is elaborated
 --> cbb.vhd:3:27
...
error[undeclared]: package `p` is not in library `work`: its analysis failed
 --> cbb.vhd:5:1
  |
5 | package body p is
  | ^^^^^^^^^^^^^^^^^
  = help: fix the errors reported for `p` in cbb.vhd; this unit needs it
  = LRM 13.5

The second error is a consequence of the first: package p failed, so its body has no declaration to belong to. Fix the errors the help points to, and the errors that followed from them go away.

Where the help points

The help line is written for the case at hand. Some examples:

Message Help
A name used before its package is analyzed library work has no design units yet: analyze its sources into it first, before the files that use it
A package body before its declaration analyze the package declaration first
A unit that needs a unit whose analysis failed fix the errors reported for p in cbb.vhd; this unit needs it
A VHDL-2019 directive in a VHDL-2008 file analyze the file with --std 19, or remove the directive
A shared variable of an unprotected type wrap the value in a protected type, or analyze the file as VHDL-93 (--std 93); or run with --compat, ...
A number against the next word insert a space after 10, as in 10 ns; or run with --compat, ...
Code that compatibility mode accepts the legal way to write it, or run with --compat, which accepts it and simulates it as written

The rules

Every analysis message belongs to a rule. jhdl --rules lists them all with their level:

Rule Default What it covers
syntax error Text that is not VHDL: tokens, grammar, tool directives.
future-reserved-word warning A word used as a name that is reserved in a later VHDL version.
missing-separator error; a warning with --compat A number directly followed by a letter or digit, as in 10ns (LRM 15.3).
directive-warning warning A `warning tool directive (LRM 24.2).
directive-error error An `error tool directive (LRM 24.2).
unsupported error A construct JanusHDL does not support yet.
undeclared error A name that is not declared, or not visible where it is used.
redeclaration error A name declared twice in one region (LRM 12.3).
use-conflict error A name made visible by two use clauses, so that neither is (LRM 12.4).
wrong-kind error A name that denotes the wrong kind of thing: a type where a value is needed, a signal where an entity is.
type-mismatch error A value of the wrong type.
type-from-context error A literal, aggregate, null or allocator whose type the context does not give.
no-match error A call that no visible subprogram matches.
ambiguous error A call or name that more than one declaration matches.
assignment-target error An assignment to something that cannot be assigned.
association error A wrong association of generics, ports or parameters.
range error A wrong range, bound or constraint.
misplaced error A statement where it is not allowed, such as exit outside a loop.
instance error A generic package that could not be instantiated.
unprotected-shared-variable error; a warning with --compat A shared variable of a type that is not protected: allowed in VHDL-1993, an error since VHDL-2002 (LRM 6.4.2.4). UVVM declares some.
port-attribute-in-architecture error; a warning with --compat An attribute specification for a port in an architecture instead of its entity (LRM 7.2). In compatibility mode the attribute decorates the port, as written.
protected-before-body error; a warning with --compat An object of a protected type created before the type's body is elaborated: in the same declarative part before the body, or in the package declaration whose body holds it (LRM 14.4.2.1).
call-before-body error; a warning with --compat A subprogram called while its declarative part is elaborated, before its body is: in the same declarative part before the body, or in the package declaration whose body holds it (LRM 14.4.2.1).
index-out-of-range error; a warning with --compat An index or slice outside its prefix's index range, both known at analysis (LRM 8.4, 8.5). Inside a generate statement it is a warning: the statement is elaborated only if its condition holds, and the error comes if the name is evaluated.
file-read-form error; a warning with --compat A file READ in the form its file type does not declare (LRM 5.5.2): with LENGTH for a file of a scalar, record or fully constrained array type, or without it for a file of an array type that is not fully constrained, such as file of string.

Constructs not supported yet

A construct that JanusHDL does not support yet is reported under the rule unsupported, by name, at the place it is used: never as an error in your code, and never silently ignored. Known limits lists them.

Changing how a rule is reported

Three options set the level of a rule, for the whole run:

Option Effect
--allow RULE Do not report the rule's diagnostics at all.
--warn RULE Report them as warnings.
--deny RULE Report them as errors.

Give one option per rule; they can be repeated for several rules.

# UVVM in compatibility mode, without its shared-variable warnings:
jhdl --compat -f uvvm.f -f tb.f --allow unprotected-shared-variable

# Keep code portable to newer VHDL versions:
jhdl -f design.f --deny future-reserved-word

A warning can be dropped or made an error. An error can only be lowered where the design still has a meaning without the rule: those are the rules that compatibility mode accepts, marked error (--compat: warning) in jhdl --rules. Asking for more is refused, with the reason:

error: `undeclared` is an error that cannot be lowered: the design has no meaning without it

An unknown rule name is refused with the list of rules. In a project, write the same as statements (allow RULE, warn RULE, deny RULE, one per line); in the window, on the Simulation page of Project settings, under Diagnostic rules at another level than their default.

Compatibility mode

Some code that the LRM forbids still has one clear meaning, and existing designs contain it:

  • a shared variable whose type is not protected (legal only in VHDL-1993), as UVVM declares;
  • an attribute of a port specified in the architecture rather than in the entity, as some FPGA flows expect;
  • a number written against the next word (10ns);
  • an index or slice outside its prefix's range, in code that may never run;
  • a file READ in the form its file type does not declare;
  • an object of a protected type created before the type's body is elaborated;
  • a function called before its body is elaborated.

By default such code is an error, as the LRM makes it, and the analysis stops. The error says how to make the code legal, and that compatibility mode accepts it:

error[call-before-body]: `twice` is called before its body is elaborated
 --> cbb.vhd:3:27
  |
3 |   constant c : integer := twice(2);
  |                           ^^^^^^^^
  = help: call it from the package body, after the subprogram body, or compute the value in another package; or run with --compat, which accepts it and simulates it as written
  = LRM 14.4.2.1

With --compat, the same code is a warning, and the design runs as written:

warning[call-before-body]: `twice` is called before its body is elaborated
 --> cbb.vhd:3:27
  |
3 |   constant c : integer := twice(2);
  |                           ^^^^^^^^
  = help: accepted in compatibility mode (--compat) and simulated as written; to make it legal: call it from the package body, after the subprogram body, or compute the value in another package
  = LRM 14.4.2.1

Turn it on with:

  • --compat on the command line;
  • compat on in a project file, or Compatibility mode on the Simulation page of Project settings in the window;
  • Compatibility mode in the Run dialog, for a file list or VHDL file run in the window;
  • the compat option of the language server, or jhdl-lsp --check DIR --compat (Options).

Of the libraries this manual covers, UVVM needs compatibility mode; OSVVM and VUnit's own libraries run without it.

The rules it accepts are marked in jhdl --rules (error (--compat: warning)). --allow, --warn and --deny still set any single rule, and take precedence: --compat --deny call-before-body keeps that one an error.

The front ends in the compat folder always run in compatibility mode, so that existing scripts keep working unchanged (Running existing scripts).

Compatibility mode changes what is accepted, never what a legal design does: a design that analyzes without it simulates the same with it.

Elaboration errors

Errors found while elaborating, after analysis succeeded, print as error: lines with the path of the instance concerned, followed by elaboration of TOP failed:

error: /conv/u/o: an output port can be associated only with a signal name or parts of one (LRM 6.5.6.3)
elaboration of work.conv failed

A generic given on the command line that does not fit its type is reported the same way (Generics). A component instance that nothing binds (no entity of that name, no configuration) is left unbound with a warning, and the rest of the design runs.

Run-time errors

Errors found during the simulation, such as an index out of range or a value outside its subtype, stop the run with a message that gives the time, the place in the source and the process (Run-time errors).

Messages in the window and in editors

  • In the window, analysis messages appear in the Terminal tab when you run a simulation; click a line with a source location to open the file there. The code editor shows the same diagnostics as you type, underlined, with the help and the LRM section when you hover over them, and lists them in the Problems tab (The code editor).
  • In other editors, the language server shows them with their rule name and LRM section (External editors and the language server).