-
Notifications
You must be signed in to change notification settings - Fork 14
A Simple Example
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"))