Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Digital Design & Verification (Verilog, SystemVerilog, VLSI)  Module 14 – Reading VHDL and other hardware languages

Chisel, Amaranth, Bluespec and HLS

See how Chisel, Amaranth and Bluespec generate Verilog, read and lint what they write, and learn what high-level synthesis does with C++ code.

  • Advanced
  • 20 minutes
  • Examples run with Python 3.14.8 and Pyodide 314.0.7
  • By MySmartCoPilot
Free core, Pro depth: 7 of 20 minutes free
Free: A program in another language builds the hardware, then writes Verilog · High-level synthesis schedules C++ into clock cycles. With a pass: 3 in-depth parts and 3 interview answers, about 13 minutes.

What you will learn

  • Describe how embedded hardware languages generate Verilog
  • Read and lint the Verilog that a hardware generator writes
  • Explain what high-level synthesis does and where it fits
  • Decide when an alternative hardware language helps a project

Before you start

The counter of this module took 11 lines of Python in Amaranth and became 55 lines of Verilog, and the reading lesson’s SystemVerilog testbench printed done: q=2 wraps=1 errors=0 for it, as for the hand-written counter. The alternative hardware languages end where every flow starts: in Verilog.

Here you see how Chisel, Amaranth and Bluespec turn a program into Verilog, how high-level synthesis turns C++ into clock cycles, how to read and lint what they write, and when one of them helps a project.

A program in another language builds the hardware, then writes Verilog

amaranth_counter.py describes the counter as a Python class. Running it prints the Verilog that Amaranth 0.5.10 makes from the class, through Yosys, and Icarus Verilog runs that Verilog under the testbench:

An Amaranth counter, its Verilog and the testbench

hdl/amaranth_counter.py

"""The 4-bit counter of this module written in Amaranth 0.5, a hardware language embedded in Python.

Running the file prints the Verilog that Amaranth generates for it, through Yosys. The counter has the ports of
counter.sv: q goes up by one at every rising edge of clk at which en is 1 and wraps from 15 to 0; rst is synchronous
and wins over en; wrap is 1 for the one cycle after q went from 15 to 0.
"""
from amaranth import Module
from amaranth.back import verilog
from amaranth.lib import wiring
from amaranth.lib.wiring import In, Out


class Counter(wiring.Component):
    en: In(1)
    q: Out(4)
    wrap: Out(1)

    def elaborate(self, platform):
        m = Module()
        with m.If(self.en):
            m.d.sync += self.q.eq(self.q + 1)
        m.d.sync += self.wrap.eq(self.en & (self.q == 15))
        return m


if __name__ == "__main__":
    print(verilog.convert(Counter(), name="counter"))

Commands · hdl/amaranth_session.py

from session import run

# The Amaranth counter becomes Verilog through Yosys, then the reading lesson's SystemVerilog testbench runs it on
# Icarus Verilog. grep counts the lines of the generated file and shows its module line and its registers.
run("""
python amaranth_counter.py > counter_am.v
grep -c "" counter_am.v
grep -E "^module|always @|reg \\[3:0\\] q" counter_am.v
iverilog -g2012 -Wall -o am.vvp tb_counter.sv counter_am.v
vvp -n am.vvp
""", packages=("amaranth",), simulators=("yosys",))

Output

# Python 3.14.8 · amaranth 0.5.10 · Icarus Verilog 13.0 (stable) · Yosys 0.69
$ python amaranth_counter.py > counter_am.v
$ grep -c "" counter_am.v
55
$ grep -E "^module|always @|reg \[3:0\] q" counter_am.v
module counter(clk, rst, q, wrap, en);
  reg [3:0] q = 4'h0;
  always @(posedge clk)
  always @(posedge clk)
  always @* begin
  always @* begin
$ iverilog -g2012 -Wall -o am.vvp tb_counter.sv counter_am.v
$ vvp -n am.vvp
done: q=2 wraps=1 errors=0
tb_counter.sv:29: $finish called at 240 (1s)

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 amaranth_session.py

An embedded HDL: A hardware description language built as a library of a programming language, its host, such as Chisel in Scala or Amaranth in Python. A program builds the design, and a compiler writes it out as Verilog. is a library of a programming language, its host. The program runs once, builds a description of registers and logic in memory, and a compiler writes it out as Verilog. The host’s loops, functions and classes therefore decide what hardware exists, which is what these languages offer over SystemVerilog’s generate blocks. What they describe is still register-transfer level: the code says what each register takes at each clock edge. Step through the counter’s path:

Interactive · stage by stage The Amaranth counter, from a Python program to a simulation Step through amaranth_session.py. Each stage reads what the stage above produced.
The Amaranth counter, from a Python program to a simulation, step 6 of 6. Showing amaranth_counter.py, Python runs elaborate(), RTLIL, Yosys write_verilog, counter_am.v, Icarus Verilog. In focus: Icarus Verilog.amaranth_counter.pya Python class, CounterPython runs elaborate()builds the design in memoryRTLILYosys's form of a designYosys write_verilogthe Verilog back endcounter_am.v55 lines of VerilogIcarus Verilogwith tb_counter.sv

The drawing shows the whole scene; its 6 steps are listed below.

Every step as text
  1. A Python class. Counter is a Python class with three ports declared as members, en, q and wrap. Its elaborate method says what happens at each clock edge, with m.d.sync for the clocked logic.
  2. The program builds the hardware. Running the file calls elaborate. The Python code runs once, like a generator of hardware, and leaves a description of registers and logic in memory; a Python loop or if here would decide what hardware exists.
  3. Into Yosys's form. Amaranth hands the design to Yosys as RTLIL, the form every Yosys pass reads and writes.
  4. Verilog out. Yosys's write_verilog turns the RTLIL into Verilog. The clock and the reset, clk and rst, appear as ports that the Python never declared, because Amaranth's sync domain brings them.
  5. A Verilog file like any other. counter_am.v has 55 lines, with names such as $1 and $4 for the values the Python computed and src attributes that point back to lines of amaranth_counter.py.
  6. The same testbench. The reading lesson's SystemVerilog testbench runs it on Icarus Verilog and prints done, q=2, wraps=1, errors=0, as for the hand-written counter.

The languages differ in their host and in the compiler that writes the HDL:

Six languages and the tool that turns each into Verilog, SystemVerilog or VHDL: Yosys, firtool, BSC, SpinalHDL, Veryl and an HLS tool.Amaranth (Python), YosysChisel (Scala), firtoolBluespec BSV, BSCSpinalHDL (Scala)Veryl, its transpilerC or C++, an HLS toolVerilog, SystemVerilog or VHDL

How each language reaches the HDL that every flow reads

Text description of the diagram

Each box on the left names a language and the tool that turns it into Verilog, SystemVerilog or VHDL, on the right.

  1. Amaranth is written in Python; the program builds the design and hands it to Yosys as RTLIL, and Yosys writes Verilog.
  2. Chisel is written in Scala; the program produces FIRRTL, and firtool, from the CIRCT project, writes Verilog.
  3. Bluespec SystemVerilog has its own compiler, BSC, which writes Verilog.
  4. SpinalHDL is written in Scala too, and its own generator writes VHDL or Verilog.
  5. Veryl is a language of its own, close to SystemVerilog, and its transpiler writes SystemVerilog.
  6. High-level synthesis starts from C or C++: an HLS tool schedules the operations into clock cycles, binds them to units and writes RTL in Verilog or VHDL.

Whatever the language, the result is ordinary HDL, so lint, simulation, formal checks and synthesis treat it as they treat hand-written RTL.

  • Amaranth is a Python library for register-transfer modelling, under BSD-2-Clause. It hands the design to Yosys, which wrote the 55 lines above, and it has its own simulator, written in Python.
  • Chisel is a hardware design language whose designs are Scala programs, under Apache-2.0. A Chisel program produces FIRRTL, and firtool, from the CIRCT project, writes the Verilog; Chisel manages the firtool version it needs.
  • Bluespec describes modules by their methods and by rules, guarded atomic actions that the compiler schedules. Its compiler, BSC, takes two syntaxes, BSV and Bluespec Haskell, and emits standard Verilog.
  • SpinalHDL is embedded in Scala too, and its generator writes VHDL or Verilog.
  • Veryl is a language of its own, close to SystemVerilog, whose transpiler writes readable SystemVerilog.

Checkpoint

Check: How an embedded HDL becomes Verilog

  1. Question 1 of 2 When does the Python code in amaranth_counter.py run?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: Once, when the program runs, to build the design that is then written out as Verilog

    An embedded HDL's host program runs at elaboration time; its loops and branches decide what hardware exists.

  2. Question 2 of 2 A designer says that with Chisel or Amaranth they no longer need to think about registers and clock cycles. What is wrong with that?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: Both still describe register-transfer level; the program generates the hardware, but it states what each register takes at each edge

    The gain of an embedded HDL is generation, not abstraction from cycles.

High-level synthesis schedules C++ into clock cycles

high-level synthesis (HLS): Turning a C or C++ function into RTL with a tool that chooses the clock cycle of every operation and the unit that runs it, then writes a state machine and a datapath in Verilog or VHDL. starts from a C or C++ function instead of registers. The tool decides what RTL would make you decide: in which clock cycle each operation runs, its scheduling (HLS): The step of high-level synthesis that gives each operation of the C or C++ code a clock cycle to start in, within the units available and after the operations whose results it reads., and which unit runs it. For y = a*b + c*d with one pipelined multiplier, the products cannot start together:

Interactive · step by step Scheduling y = a*b + c*d on one multiplier Step through the cycles. The left column holds the three operations; the right column the two units a tool may use.
Scheduling y = a*b + c*d on one multiplier, step 6 of 6. Showing a*b, c*d, y = a*b + c*d, Multiplier (a*b ready, c*d inside), Adder (y ready after 4 cycles).a*bneeds a multiplierc*dneeds a multipliery = a*b + c*dneeds an adderMultipliera*b ready, c*d insideAddery ready after 4 cycles

The drawing shows the whole scene; its 6 steps are listed below.

Every step as text
  1. Three operations, two units. The C line y = a*b + c*d has two multiplications and one addition. The tool has one multiplier and one adder to put them on, and must give each operation a start cycle.
  2. Cycle 0. a*b has its inputs ready, so it starts on the multiplier at cycle 0. c*d is ready too, but the only multiplier is taken this cycle.
  3. Cycle 1. The multiplier is pipelined, so it takes a new pair one cycle later, while a*b is still inside it. c*d starts at cycle 1.
  4. Cycle 2. a*b is ready at the end of its 2 cycles, but y needs both products, and c*d is not ready yet. The adder waits.
  5. Cycle 3. c*d is ready, so y starts on the adder at cycle 3.
  6. The latency. y is ready after 4 cycles. With a second multiplier both products start at cycle 0 and y after 3 cycles, one cycle faster for one more multiplier. That trade is the decision a tool makes for you.

The program below makes the same decisions, the way Bambu, an open-source HLS tool, schedules by default: each cycle it starts every operation whose inputs are ready, while a unit of its kind is idle. Change MULTIPLIERS and run it again:

List-scheduling y = a*b + c*d on one and two multipliers Python · model/schedule_two.py
"""What high-level synthesis does with y = a*b + c*d: it gives every operation a clock cycle and a unit to run on.

A multiplier takes 2 cycles and accepts a new pair every cycle (it is pipelined); an adder takes 1. The program lists,
cycle by cycle, which operation each unit starts, with one multiplier and with two, and prints the latency: the
cycles from the first operation starting to y being ready. Change MULTIPLIERS to try other numbers.
"""

MULTIPLIERS = (1, 2)
LATENCY = {"mul": 2, "add": 1}
# The operations, the kind of unit each needs and the operations whose results it reads.
OPS = {
    "a*b": ("mul", []),
    "c*d": ("mul", []),
    "y": ("add", ["a*b", "c*d"]),
}


def schedule(units):
    """List scheduling: each cycle, start every operation whose inputs are ready, while units of its kind are free."""
    done_at = {}
    start = {}
    cycle = 0
    while len(start) < len(OPS):
        free = dict(units)
        for name, (kind, inputs) in OPS.items():
            ready = all(i in done_at and done_at[i] <= cycle for i in inputs)
            if name not in start and ready and free[kind] > 0:
                start[name] = cycle
                done_at[name] = cycle + LATENCY[kind]
                free[kind] -= 1
        cycle += 1
    return start, max(done_at.values())


for count in MULTIPLIERS:
    start, latency = schedule({"mul": count, "add": 1})
    print(f"{count} multiplier(s), 1 adder:")
    for name, cycle in sorted(start.items(), key=lambda item: item[1]):
        print(f"  cycle {cycle}: start {name} on the {OPS[name][0]} unit")
    print(f"  y is ready after {latency} cycles")

Output

1 multiplier(s), 1 adder:
  cycle 0: start a*b on the mul unit
  cycle 1: start c*d on the mul unit
  cycle 3: start y on the add unit
  y is ready after 4 cycles
2 multiplier(s), 1 adder:
  cycle 0: start a*b on the mul unit
  cycle 0: start c*d on the mul unit
  cycle 2: start y on the add unit
  y is ready after 3 cycles

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 schedule_two.py

One multiplier gave a latency of 4 cycles and two gave 3: the tool trades units for cycles, a trade that RTL makes you write by hand. HLS fits algorithms on data, such as filters, codecs and transforms, which are easier to state in C++ than as a pipeline. It fits control logic badly, because a protocol fixes the cycle of each action, and the tool picks cycles itself. Its RTL is verified like any other, and AMD’s guide to Vitis HLS has a section on C/RTL co-simulation, which runs the C++ test against the generated design.

Checkpoint

Check: What high-level synthesis decides

  1. Question 1 of 2 What does a high-level synthesis tool decide that an RTL designer writes by hand?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: The clock cycle in which each operation runs, and the unit that runs it

    Scheduling and binding are the tool's work; the result is RTL with a state machine and a datapath.

  2. Question 2 of 2 Two pipelined multipliers that take 2 cycles and one adder that takes 1 compute y = a*b + c*d. After how many cycles is y ready?

    Type a number.

    Show the answer: Question 2 of 2

    Answer: 3 cycles

    Both products start at cycle 0 and are ready at cycle 2, the addition runs in cycle 2, and y is ready after 3 cycles, one fewer than with one multiplier.

Reading and linting generated Verilog, measured on two generators Pro: opens with a Pro, Premium or Ultimate pass

Generated Verilog enters the same lint, simulation and synthesis as hand-written RTL, and it looks different there. This part lints Amaranth’s output, reads what BSC writes, and lists what to check before trusting either.

In this part:

  • Amaranth’s Verilog under lint: four warnings, none of them bugs
  • What BSC writes: methods become ports, and registers start at 4’hA

1 runnable example (Commands, Counter.bsv, counter_bsv.sv) · about 4 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

HLS by numbers: latency and initiation interval of a filter Pro: opens with a Pro, Premium or Ultimate pass

A tool’s schedule decides two different numbers, how long one result takes and how often a new one can start. This part schedules a 4-tap filter with five sets of units and shows which unit limits the rate in each. It ends with the directives that reach the same points in a real tool: pipelining a loop, unrolling it into copies and partitioning an array into several memories.

In this part:

  • Five sets of units for one filter
  • What the directives of a real tool change

1 runnable example (Python) · about 3 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Choosing a language for a block, with your answers Pro: opens with a Pro, Premium or Ultimate pass

None of these languages is better in general; each fits some blocks and some teams. This part turns the lesson’s measurements into a decision table that takes your answers, then works four projects through it.

In this part:

  • The decision table
  • Four projects worked through

about 8 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Practise: write the list scheduler

The exercise is the scheduler of schedule_two.py made general: any operations, any units and any latencies. Its sample tests include a chain that a second multiplier cannot speed up.

Exercise · Medium · Python

Schedule operations onto units, as an HLS tool does

Write schedule(ops, units, latency), the list scheduler of schedule_two.py made general.

  • ops maps each operation's name to a pair: the kind of unit it needs, such as "mul", and the list of operations whose results it reads. The order of ops is the priority order.
  • units maps each kind to how many units of it there are. Every unit is pipelined: it can start one new operation in every cycle.
  • latency maps each kind to the cycles its operations take.

Go cycle by cycle from 0. In each cycle, walk through the operations in order and start every one that has not started, whose inputs have all finished by this cycle, and for which a unit of its kind is still free in this cycle. An operation started at cycle c finishes at c + latency[kind].

Return a pair: a dictionary of each operation's start cycle, and the cycle at which the last one finishes. If an operation needs a kind that has no units, raise ValueError.

Starter code · schedule.py

def schedule(ops, units, latency):
    """List-schedules ops onto pipelined units; returns ({name: start cycle}, last finish cycle)."""
    return {}, 0
The sample tests · test_schedule.py
from schedule import schedule

LATENCY = {"mul": 2, "add": 1}
TWO_PRODUCTS = {"a*b": ("mul", []), "c*d": ("mul", []), "y": ("add", ["a*b", "c*d"])}


def test_one_multiplier():
    """schedules y = a*b + c*d on one multiplier: y starts at cycle 3 and is ready after 4"""
    assert schedule(TWO_PRODUCTS, {"mul": 1, "add": 1}, LATENCY) == ({"a*b": 0, "c*d": 1, "y": 3}, 4)


def test_two_multipliers():
    """with two multipliers both products start at cycle 0 and y is ready after 3"""
    assert schedule(TWO_PRODUCTS, {"mul": 2, "add": 1}, LATENCY) == ({"a*b": 0, "c*d": 0, "y": 2}, 3)


def test_chain_ignores_extra_units():
    """a chain of two multiplies needs 4 cycles however many multipliers there are"""
    chain = {"p": ("mul", []), "q": ("mul", ["p"])}
    assert schedule(chain, {"mul": 2}, LATENCY) == ({"p": 0, "q": 2}, 4)


def test_three_products_on_two():
    """three independent products on two multipliers start at cycles 0, 0 and 1"""
    ops = {"m0": ("mul", []), "m1": ("mul", []), "m2": ("mul", [])}
    assert schedule(ops, {"mul": 2}, LATENCY) == ({"m0": 0, "m1": 0, "m2": 1}, 3)


def test_missing_unit():
    """refuses an operation whose kind has no units"""
    try:
        schedule(TWO_PRODUCTS, {"mul": 1}, LATENCY)
    except ValueError:
        return
    raise AssertionError("no ValueError when there is no adder")
A hint

Keep two dictionaries, the start cycle and the finish cycle of each operation started so far. In each cycle, copy units into a dictionary of free units and take one away for every operation you start.

The sample tests run on this device, in your browser (Pyodide): nothing is sent to mysmartcopilot.com. The first run downloads Python (about 13.5 MB), which is kept for the next runs. A check in your browser is feedback for you, not proof that the code is right for every input.

Practice that adapts to you

Practise this lesson

6 questions about 5 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 6 Which tool writes the Verilog of an Amaranth design?

    Choose one answer.

    Show the answer: Question 1 of 6

    Answer: Yosys, from the RTLIL that Amaranth hands it

    Amaranth through Yosys, Chisel through firtool, Bluespec through BSC.

  2. Question 2 of 6 Which language pairs are right?

    Choose one answer.

    Show the answer: Question 2 of 6

    Answer: Amaranth with Python, Chisel and SpinalHDL with Scala

    The host language decides what a team must learn, and what its generators can use.

  3. Question 3 of 6 You need twelve variants of a block whose sizes come from a formula and a table of settings. Why is an embedded HDL a good fit?

    Choose one answer.

    Show the answer: Question 3 of 6

    Answer: The host program can compute each variant with ordinary loops, functions and data, then build it

    SystemVerilog's parameters and generate blocks cover simple cases; a whole programming language covers the rest.

  4. Question 4 of 6 Which block suits high-level synthesis best?

    Choose one answer.

    Show the answer: Question 4 of 6

    Answer: An image filter whose C model already exists

    HLS fits algorithms on data; control logic that a protocol times fits RTL.

  5. Question 5 of 6 p = a*b, then q = p*c, on two pipelined multipliers that take 2 cycles. After how many cycles is q ready?

    Type a number.

    Show the answer: Question 5 of 6

    Answer: 4 cycles

    q needs p, which is ready at cycle 2, so q runs from cycle 2 and is ready at 4; the second multiplier cannot help a chain.

  6. Question 6 of 6 An HLS tool reports success and the C++ test passes. What is still unverified?

    Choose one answer.

    Show the answer: Question 6 of 6

    Answer: The generated RTL itself, which a C/RTL co-simulation and the usual RTL checks must test

    Treat HLS output as RTL from another designer: co-simulate it against the C++ test, then lint, simulate and time it.

Interview questions

Warm-up (2 to 5 years): what is an embedded HDL, and what does it generate?

It is a hardware description language built as a library of a programming language, such as Chisel in Scala or Amaranth in Python. A program in that language runs once, builds the design in memory and hands it to a compiler that writes Verilog, so the host’s loops, functions and classes decide what hardware exists. The result is ordinary RTL: this lesson’s 11-line Amaranth counter became 55 lines of Verilog that passed the same testbench as the hand-written counter.

  1. Mid to senior

    A block written in an embedded HDL fails one test in the SoC simulation. The waveform shows a signal called $27 going wrong one cycle after reset, and the designer who wrote the block has left. How do you find the cause, and what would you put in place so the next failure is quicker to trace?

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  2. Mid to senior

    A 16-tap FIR filter must process 50 million samples a second on a 200 MHz clock. The algorithm exists as a C model. Do you write it in RTL or use high-level synthesis? Size the multipliers and adders either way, and say what you would verify.

    Model answer, Pro. First step and follow-ups

  3. Senior to staff

    Your team of ten writes SystemVerilog and UVM. A new hire proposes moving new blocks to Chisel, and another to Amaranth. How do you decide, what would you try first, and what must stay true of the team's flow whatever language wins?

    Model answer, Pro. First step and follow-ups

Flashcards · 8 cards

Recall it, then check

Say the answer to yourself before you look: recalling it is what makes it stick.

  1. What is an embedded HDL?

    A hardware description language built as a library of a programming language, its host. The program runs once, builds the design in memory, and a compiler writes it out as Verilog.

  2. What does each of Amaranth, Chisel and Bluespec hand its design to?

    Amaranth, a Python library, hands it to Yosys; Chisel, written as Scala programs, produces FIRRTL that firtool from the CIRCT project writes as Verilog; Bluespec's compiler, BSC, takes BSV or Bluespec Haskell and emits Verilog.

  3. Do embedded HDLs describe hardware above register-transfer level?

    No: the code still says what each register takes at each clock edge. What they add over generate blocks is that the host's loops, functions and classes decide what hardware exists.

  4. What is a Bluespec rule?

    A guarded atomic action, which the compiler schedules; Bluespec describes modules by their methods and by rules.

  5. What does high-level synthesis decide that RTL makes you decide?

    In which clock cycle each operation of a C or C++ function runs, its schedule, and which unit runs it.

  6. How did a second multiplier change the schedule of y = a*b + c*d?

    The latency fell from 4 cycles with one pipelined multiplier to 3 with two: the tool trades units for cycles.

  7. Which designs suit high-level synthesis, and which do not?

    Algorithms on data, such as filters, codecs and transforms, which are easier to state in C++. Control logic suits it badly, because a protocol fixes the cycle of each action while the tool picks cycles itself.

  8. How is the RTL that HLS generates checked?

    Like any other RTL. AMD's Vitis HLS guide describes C/RTL co-simulation, in which the C++ test drives the RTL the tool generated.

Key takeaways

  • An embedded HDL is a program in Python or Scala that builds the hardware and hands it to a compiler that writes Verilog: Amaranth through Yosys, Chisel through firtool; Bluespec has its own compiler, BSC.
  • What they describe is still register-transfer level, and Amaranth’s Verilog passed the same testbench as the hand-written counter.
  • High-level synthesis schedules a C or C++ function into clock cycles and units: one more multiplier cut y = a*b + c*d from 4 cycles to 3. It suits algorithms on data, not protocols.

Terms in this lesson

embedded HDL
A hardware description language built as a library of a programming language, its host, such as Chisel in Scala or Amaranth in Python. A program builds the design, and a compiler writes it out as Verilog.
high-level synthesis (HLS)
Turning a C or C++ function into RTL with a tool that chooses the clock cycle of every operation and the unit that runs it, then writes a state machine and a datapath in Verilog or VHDL.
scheduling (HLS)
The step of high-level synthesis that gives each operation of the C or C++ code a clock cycle to start in, within the units available and after the operations whose results it reads.

References

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.