Featured image of post RTL Analysis on MacOS under 300MB

RTL Analysis on MacOS under 300MB

Intro and Overview

References

CLAIM: This article synthesizes conclusions and methods from multiple websites and is not pure original. 本文综合了多个网站的结论和方法,并非原创。

You may find these websites useful:

First Project in Verilog

Install Icarus Verilog Compiler

1
brew install icarus-verilog

Compilation and Simulation

Create new folder called Verilog, then create two test files named GatedDLatch.v and GatedDLatch_tb.v. The former is the description file of the circuit, the latter is for testbench. And write the following contents respectively:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
// in GatedDLatch.v
module GatedDLatch (Data, WE, Out, OutBar);

    input Data;
    input WE;

    output Out;
    output OutBar;

    // component name(output, input1, input2)
    wire S;
    wire R;
    wire Dbar;
    nand g1(S, Data, WE);
    not g2(Dbar, Data);
    nand g3(R, WE, Dbar);
    nand g4(Out, S, OutBar);
    nand g5(OutBar, R, Out);
    

endmodule

and

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// in GatedDLatch_tb.v
`timescale 1ns / 1ns // simulation time, time precision = 1ns
//Import the main code into the testbench
`include "GatedDLatch.v"

module GatedDLatch_tb;
//Inputs as registers
reg Data;
reg WE;

//Outputs as wires
wire Out;
wire OutBar;

//Initialisation
GatedDLatch uut(Data, WE, Out, OutBar);

initial begin
    //Name of the graph file that gets generated after we run
    $dumpfile("GatedDLatch_tb.vcd");
    $dumpvars(0,GatedDLatch_tb);

    Data = 0;
    WE = 0;
    #10;

    Data = 1;
    #4;
    WE = 1;
    #2;
    WE = 0;
    #4;

    Data = 0;
    #4;
    WE = 1;
    #2;
    WE = 0;
    #4;

    $display("Test complete");
end
endmodule

Run this in the terminal:

1
iverilog -o GatedDLatch_tb.vvp GatedDLatch_tb.v

Use vvp command to convert the binary temperary file GatedDLatch_tb.vvp to GatedDLatch_tb.vcd waveform file:

1
vvp GatedDLatch_tb.vvp

Install Wavetrace in vscode to view the waveform:

Display the waveform in vscode

You can also install gtkwave to view the waveform.

1
2
brew install gtkwave
gtkwave GatedDLatch_tb.vcd

Before imported

Expand GatedDLatch_tb list to display the waveform:

Displaying waveform

Synthesis and Visualization

We can also visualize the circuit topology (called generating schematics). First, use YoSYS to convert the verilog code into gate-level netlist. Of course you should install the command line tool YoSYS:

1
2
brew install yosys
yosys -V # Verify Yosys installation

YoSYS will first convert the circuit structure description file GatedDLatch.v into a json file:

1
yosys -p "prep -top GatedDLatch; write_json GatedDLatch.json" GatedDLatch.v

Then we install another tool called netlistsvg:

1
2
3
4
5
6
7
8
# Install Node.js (if not already installed)
brew install node

# Install netlistsvg globally using npm
npm install -g netlistsvg

# Verify netlistsvg installation
netlistsvg --version

Using the netlistsvg tool to convert GatedDLatch.json to GatedDLatch.svg:

1
netlistsvg GatedDLatch.json -o GatedDLatch.svg

Previewing GatedDLatch.svg will give you the circuit schematic:

GatedDLatch.svg

Makefile Work Flow

The entire workflow can be divided into two major independent parts:

  • Compilation and Simulation:
    • iverilog (Compilation)
    • vvp (Simulation)
  • Synthesis and Circuit Structure Visualization:
    • yosys (Synthesis)
    • netlistsvg (Visualization)

We use a Makefile to automate this process (ensure that Make and related components are installed): Create a Makefile file in the previously created Verilog folder and add the following content:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# Description: Makefile for GatedDLatch
CIRCUIT_STRUCT = GatedDLatch

# Directories
BUILD_DIR = build

# Ensure the build directory exists
$(BUILD_DIR):
	mkdir -p $(BUILD_DIR)

# Compilation: iverilog compilation
iverilog: $(CIRCUIT_STRUCT).v $(CIRCUIT_STRUCT)_tb.v | $(BUILD_DIR)
	iverilog -o $(BUILD_DIR)/$(CIRCUIT_STRUCT)_tb.vvp $(CIRCUIT_STRUCT)_tb.v

# Simulation: generate waveform (.vcd)
vvp: $(BUILD_DIR)/$(CIRCUIT_STRUCT)_tb.vvp
	vvp $(BUILD_DIR)/$(CIRCUIT_STRUCT)_tb.vvp

# Synthesis: generate circuit structure configuration file (.json)
YOSYS: $(CIRCUIT_STRUCT).v | $(BUILD_DIR)
	yosys -p "prep -top $(CIRCUIT_STRUCT); write_json $(BUILD_DIR)/$(CIRCUIT_STRUCT).json" $(CIRCUIT_STRUCT).v

# Visualization: generate human readable (.svg) from .json
NETLISTSVG: $(BUILD_DIR)/$(CIRCUIT_STRUCT).json | $(BUILD_DIR)
	netlistsvg $(BUILD_DIR)/$(CIRCUIT_STRUCT).json -o $(BUILD_DIR)/$(CIRCUIT_STRUCT).svg

# Schematic diagram only: Synthesis then Visualization
schematic: YOSYS NETLISTSVG

# Run all steps
run_all: iverilog vvp schematic

# Clean build directory
clean:
	rm -rf $(BUILD_DIR)
	rm -f $(CIRCUIT_STRUCT)_tb.vcd

After modifying the files, simply execute:

1
2
make clean
make run_all

This will generate all the relevant files:

Project File Structure

First Project in VHDL

Install GHDL Compiler

Similar to Verilog, VHDL is also a hardware description language. Compiling it requires another tool: GHDL. Installing it on macOS can be tricky. The following steps have been tested on an M2 Mac (as of 2024-09-01):

Install vhdl using brew:

1
brew install vhdl

vhdl has two versions: LLVM and mcode. The LLVM version has some issues on macOS, and the brew-installed version uses LLVM, so we manually download the mcode version from here. I downloaded ghdl-macos-11-mcode.tgz.

Extract it by double-clicking, and you will get three files:

GHDL-mcode package

Copy and paste these three files to the following path: /opt/homebrew/Caskroom/ghdl/4.1.0:

Copy and Paste

In the terminal, type:

1
ghdl --version

If you encounter security prompts, go to System Settings > Privacy & Security to allow access:

Allow Access in Privacy & Security

Compilation, Linking and Simulation

Unlike Verilog, VHDL requires an additional Linking step, which connects the component declarations with their implementation files (testbench). Why doesn’t Verilog require this? Because the testbench file in Verilog includes the declaration contents (include "GatedDLatch.v"), so it links automatically.

In Verilog, we used two separate tools (iverilog and vvp) for compilation and simulation. However, for VHDL, we only need one tool: GHDL.

Create a new folder VHDLDemo, and within it, create two files: demo.vhdl and demo_tb.vhdl. The former describes the circuit structure, and the latter serves as the testbench file (you can also use .vhd as the suffix). Add the following content to the respective files:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity demo is
    port (
        A : in  STD_LOGIC;
        B : in  STD_LOGIC;
        O : out STD_LOGIC
    );
end demo;

architecture Behavioral of demo is
begin
    O <= not (A and B); -- NAND gate
end Behavioral;

and

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity demo_tb is
end demo_tb;

architecture Behavioral of demo_tb is
    signal A : STD_LOGIC := '0';
    signal B : STD_LOGIC := '0';
    signal O : STD_LOGIC;

    -- Instantiate the unit under test (UUT)
    component demo
        port (
            A : in  STD_LOGIC;
            B : in  STD_LOGIC;
            O : out STD_LOGIC
        );
    end component;
begin
    UUT: demo port map (
        A => A,
        B => B,
        O => O
    );

    -- Test process
    process
    begin
        -- Test case 1: A = 0, B = 0
        A <= '0';
        B <= '0';
        wait for 10 ns;
        
        -- Test case 2: A = 0, B = 1
        A <= '0';
        B <= '1';
        wait for 10 ns;

        -- Test case 3: A = 1, B = 0
        A <= '1';
        B <= '0';
        wait for 10 ns;

        -- Test case 4: A = 1, B = 1
        A <= '1';
        B <= '1';
        wait for 10 ns;

        -- End of simulation
        wait;
    end process;
end Behavioral;

Create a Makefile to automate the process:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# Description: Makefile for VHDLDemo
CIRCUIT = demo
TB = demo_tb
BUILD_DIR = build

# Ensure the build directory exists
$(BUILD_DIR):
	mkdir -p $(BUILD_DIR)

# Compilation: compile the design and testbench
ghdl_compile: $(BUILD_DIR)
	ghdl -a --workdir=$(BUILD_DIR) $(CIRCUIT).vhdl
	ghdl -a --workdir=$(BUILD_DIR) $(TB).vhdl

# Linking: Elaborate the design and testbench
ghdl_elab: ghdl_compile
	ghdl -e --workdir=$(BUILD_DIR) $(TB)

# Simulation: simulate the testbench
ghdl_simulate: ghdl_elab
	ghdl -r --workdir=$(BUILD_DIR) $(TB) --vcd=$(BUILD_DIR)/$(TB).vcd

### These cannot work for now##############################################
# # Synthesis: generate circuit structure configuration file (.json), you should have ghdl plugin installed for yosys, but I have error: "ERROR: No such command: ghdl" or "dyld[5264]: missing symbol called", possible solution could be to install yosys from source, but not sure
# YOSYS: $(CIRCUIT).vhdl | $(BUILD_DIR)
# 	yosys -p "ghdl $(CIRCUIT); prep -top $(CIRCUIT); write_json -compat-int $(BUILD_DIR)/$(CIRCUIT).json" $(CIRCUIT).vhdl

# # Visualization: generate human readable (.svg) from .json
# NETLISTSVG: $(BUILD_DIR)/$(CIRCUIT).json  | $(BUILD_DIR)
# 	netlistsvg $(BUILD_DIR)/$(CIRCUIT).json -o $(BUILD_DIR)/$(CIRCUIT).svg

# # Schematic diagram only: Synthesis then Visualization
# schematic: YOSYS NETLISTSVG

# # Run all steps
# run_all: ghdl_compile ghdl_elab ghdl_simulate YOSYS NETLISTSVG
### These cannot work for now##############################################

# Run compilation, linking and simulation
run_cls: ghdl_compile ghdl_elab ghdl_simulate

# Clean build directory
clean:
	rm -rf $(BUILD_DIR)
	rm -f $(TB)

# Experiment: Run testbench without the design file
run_tb_only: $(BUILD_DIR)
	ghdl -a --workdir=$(BUILD_DIR) $(TB).vhdl
	ghdl -r --workdir=$(BUILD_DIR) $(TB) --vcd=$(BUILD_DIR)/$(TB)_no_design.vcd

The running process is very clear. In the command line, execute:

1
2
make clean
make run_cls

This will complete the process.

If you want to see what happens if you skip compiling and linking the design file (demo.vhdl), run:

1
2
make clean # Cannot omitted!
make run_tb_only

You can compare the two .vcd files generated in VSCode or using GTKWave; they are different as expected.

No Synthesis and Visualization Plan

Note that this Makefile does not include steps to generate a schematic diagram because yosys requires a ghdl plugin. Currently, the integration is not very stable. You can refer to ghdl-yosys-plugin and building-ghdl for more details. However, the suggested methods have been tested on M2 Mac and result in errors:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
 /----------------------------------------------------------------------------\
 |  yosys -- Yosys Open SYnthesis Suite                                       |
 |  Copyright (C) 2012 - 2024  Claire Xenia Wolf <claire@yosyshq.com>         |
 |  Distributed under an ISC-like license, type "license" to see terms        |
 \----------------------------------------------------------------------------/
 Yosys 0.44 (git sha1 80ba43d26, clang++ 15.0.0 -fPIC -O3)

-- Running command `ghdl demo_tb.vhdl -e demo_tb; prep -top demo_tb; write_json demo.json' --

1. Executing GHDL.
dyld[5264]: missing symbol called
zsh: abort      yosys -m ghdl -p

This issue has also been mentioned in the Issues section of ghdl-yosys-plugin, but there is no solution yet.

Possible solutions might include compiling and installing yosys from source, ensuring the correct versions of yosys and ghdl, or checking if any component of the FPGA Toolchain is missing. Alternatively, you could try converting VHDL to Verilog using some tool (like GPT) and then synthesizing the schematics.

Licensed under CC BY-NC-SA 4.0
comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy