JanusHDL

Quick start

Last updated: 

This chapter runs a small counter and its testbench, first from the command line, then in the window. It assumes JanusHDL is installed and jhdl is on your PATH (Installing).

1. Write a design and a testbench

Make a folder and save this as counter.vhd:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity counter is
  generic (WIDTH : positive := 8);
  port (
    clk   : in  std_logic;
    rst   : in  std_logic;
    count : out unsigned(WIDTH - 1 downto 0)
  );
end entity;

architecture rtl of counter is
  signal n : unsigned(WIDTH - 1 downto 0) := (others => '0');
begin
  process (clk)
  begin
    if rising_edge(clk) then
      if rst = '1' then
        n <= (others => '0');
      else
        n <= n + 1;
      end if;
    end if;
  end process;
  count <= n;
end architecture;

And this as counter_tb.vhd:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.env.all;

entity counter_tb is
end entity;

architecture sim of counter_tb is
  signal clk   : std_logic := '0';
  signal rst   : std_logic := '1';
  signal count : unsigned(7 downto 0);
begin
  clk <= not clk after 5 ns;

  dut : entity work.counter
    generic map (WIDTH => 8)
    port map (clk => clk, rst => rst, count => count);

  stimulus : process
  begin
    wait for 20 ns;
    rst <= '0';
    wait until count = 10;
    report "count reached " & to_string(to_integer(count));
    assert count = 10 severity error;
    finish;
  end process;
end architecture;

2. Run it

In that folder:

jhdl counter.vhd counter_tb.vhd

JanusHDL analyzes the two files in the order given, into library work, elaborates the last entity it analyzed (counter_tb) and runs it. It prints:

115 ns (delta 2) counter_tb.vhd:25:12: note: count reached 10
simulation of work.counter_tb ended at 115 ns (stopped); analysis 210 ms, elaboration 6 ms, run 2 ms

The first line is the testbench's report: the simulation time, the delta cycle within that time, the place in the source, the severity and the text. The last line is JanusHDL's summary: where the run ended and why (stopped, because the testbench called finish), and how long each phase took on your machine.

The exit code is 0. Had the assertion failed, or any report of severity error or failure come up, it would be 1, so a script or a CI job can rely on it:

jhdl counter.vhd counter_tb.vhd && echo "passed"

3. Record and look at the waveforms

Run again, recording every signal into a waveform database:

jhdl counter.vhd counter_tb.vhd --wave counter.jhw
jhdlw counter.jhw

The window opens with the recording:

  1. The Hierarchy tab, at the top left, shows the design: counter_tb, and inside it the instance dut. Click counter_tb.
  2. The Signals tab, below it, lists that scope's signals with their types. Double-click clk, rst and count to add them to the Waves tab, or click the button beside the filter box to add every signal listed.
  3. Press F to fit the whole run in view. Click in the waves to place the cursor: the Value column shows each signal's value there. count shows in hexadecimal; right-click its name and choose Unsigned decimal to see 0 to 10.
  4. Hold Ctrl and turn the mouse wheel over the waves to zoom; drag to pan.

The waveform viewer covers everything else: markers, finding values, analog rows, groups and saving the view.

4. Run it in the window

The window can run the simulation itself, and keeps the design loaded so you can run it again, pause it or restart it.

  1. Save a file list, counter.f, in the same folder. It names the files to analyze, in order:

text library work counter.vhd counter_tb.vhd

  1. Start jhdlw (or use the window you have open) and choose Simulate → Run simulation… (Ctrl+Shift+R).
  2. Type the path of counter.f, or press Browse… to pick it, and press Run. (The dialog also takes a top entity, a stop time, the VHDL version, generics and compatibility mode; the defaults suit this example, and what you choose is remembered for the file.)

The Terminal tab shows the analysis, the report and how the run ended; the waveform opens as the simulation runs, with the top level's signals shown. Press F5 to run it again from time 0, and Ctrl+Shift+F5 to go back to time 0 and wait there. If you change a source file, the next run analyzes it again.

You can also drop counter.f onto the window: it runs straight away.

5. Ask why a signal has its value

Select count in the waves, place the cursor anywhere after the reset, and choose Signals → Why this value?. The panel shows the value at the cursor, since when it has it, and the process that drives it, with a link to the line in counter.vhd and the values of the signals that process reads. Click the link to open the line in the code editor. Insight panels explains the three panels.

6. Keep it as a project

For anything bigger than this, keep the sources and settings in a project file. Choose File → Import a file list (.f) as a project…, pick counter.f, and save the project as counter.jhdlproj. The project's settings open: on the Top level page set the top to work.counter_tb, and on Simulation a stop time if you want one; press Save. F5 now runs the project, and on the command line:

jhdl run counter.jhdlproj

Projects describes the project file and project mode.

Where to go next