Skip to content

A Simple Example

Sunny Chen edited this page Feb 19, 2020 · 2 revisions

Let's start with a simple example of PyHCL. Considering a 1-bit full adder:

class Adder(Module):
    io = IO(
        a=Input(U.w(1)),
        b=Input(U.w(1)),
        cin=Input(U.w(1)),
        s=Output(U.w(1)),
        cout=Output(U.w(1))
    )

    io.s <<= io.a ^ io.b ^ io.cin
    io.cout <<= io.a & io.b | io.a & io.cin | io.b & io.cin

In PyHCL, all circuit components could be written as Module. Module is a base class implemented in PyHCL library, it is a little bit similar to the module in Verilog, but it supports more advanced features. All circuits must inherit Module in PyHCL. But now, you only just need to know that Module is a class which is used to define a circuit component. As the example above, we define a class Adder inherited Module. For simplicity, we call a class that inherited Module a module.

A module must have I/O ports to interact with other components. When we define a module, we must define I/O ports for it. In PyHCL, we defined I/O ports using IO. IO is also a base class implemented in PyHCL library. We could define a series I/O ports using IO. The parameters list of IO are the I/O ports of the module, such as a, b, cin, s, and cout in the example above. All I/O ports must have a direction, either input or output. We simply using Input and Output to define the direction. Input and Output are also base classes implemented in PyHCL library. They require a parameter which indicate the datatype of the I/O port. Such as U in the example above, which means unsigned integers. We using the method w of class U to indicate the width of the unsigned integer. U.w(1) means the datatype is a 1 bit unsigned integer. We would describe the details of PyHCL's datatypes in the next section.

After the definition of I/O ports, the rest part of the module is implementation of circuit logic. In our 1-bit full adder, it is simple that we just need to define the output(s, cout). <<= is a connect operator, which is similar to := in Chisel. <<= means wire between the right expression and the left expression. Notice that in actual circuits, all <<= operations execute concurrently. Operator ^, &, and | are logic operators. We would describe the details of PyHCL's built-in operators in section 4.

The last question is how we generate the FIRRTL code and the Verilog code of the 1-bit full adder given above. We could simply call function compile_to_firrtl to generate FIRRTL code:

compile_to_firrtl(Adder, "Adder.fir")

In order to compile the FIRRTL code, you only need to call the FIRRTL compiler:

firrtl -i Adder.fir

After that, you could found the FIRRTL code and Verilog code in the same directory.

In previous version of PyHCL, generating the FIRRTL and Verilog code could be done by several functions of emitter:

Emitter.dumpVerilog(Emitter.dump(Emitter.emit(Adder()), "Adder.fir"))

<<Prev(Introduction) >>Next(Datatypes)