-
Notifications
You must be signed in to change notification settings - Fork 14
Case Study: Sequential Circuits
Sequential circuits are circuits contain state elements, such as registers or memories. Before we describe how to design sequential circuits in PyHCL, we first want to describe more details about registers in PyHCL. As we have described in section 5, the registers in PyHCL is based on the clock. The clock in pre-defined in PyHCL's base class Module
. In PyHCL, there is no API similar to always
in Verilog. All operations on a register is based on the clock. For example:
counter = RegInit(U.w(16(0)))
counter <<= counter + U(1) # Increase in each clock cycle, positive edge
The addition to counter
would execute every clock cycle, we could found out in the result Verilog code:
always @(posedge clock) begin
if (reset) begin
counter <= 16'h0;
end else begin
counter <= _T[15:0]; // _T is the sum of counter and unsigned register value 1
end
end
In order that, when design a sequential circuit in PyHCL, users must have the idea of sequential model. Let's start with a simple example of a classic sequential circuits, a 4-bit shift register:
class ShiftReg(Module):
io = IO(
din=Input(U.w(1)),
dout=Output(U.w(4))
)
rarray = [RegInit(U.w(1)(0)) for _ in range(4)]
rarray[0] <<= io.din
for i in range(0, 3):
rarray[i+1] <<= rarray[i]
io.dout <<= CatBits(*rarray)
rarray
is an array which contain PyHCL registers. In this case, we use functional programming to define rarray
. rarray
initialize with four 1-bit unsigned integer registers. The input port din
is connected to the first register in rarray
. Then, the regsiters in rarray
are connected according to the order of the registers. We use built-in Python for
statement to do so. At last, we use CatBits
to concatenate all registers in rarray
. CatBits
is pre-defined util in PyHCL, and it is similar to Cat
in Chisel. We would describe CatBits
in next section about advanced topics.
The example of a 4-bit shift register shows the advantage of embedding the hardware construction language to Python. We could describe the circuits using advanced programming techniques such as functional programming. Now back to our topic about sequential circuits. It is common for designer to design a sequential circuit with specific clock informantions. For example, we may want to do something when specific register is overflow or in specific clock cycles. We could achieve this goal by using a counter to do so. The counter is a unsigned integer register, and would increase in every clock cycle. If we want to output true when counter is overflow, it is easy by using when
, elsewhen
and otherwise
statements:
counter = RegInit(U.w(16)(0))
counter <<= counter + U(1)
with when(counter == U.(2^16-1)):
io.signal <<= Bool(True)
with otherwise():
io.signal <<= Bool(False)
Statements when
, elsewhen
and otherwise
are PyHCL statements to implement the functions similar to mux. We call them PyHCL conditional statements. In fact, all PyHCL conditional staements could rewrite using Mux
or LookUpTable
in PyHCL. But they provide a more flexible way to write coditional choice logics. The conditional statements in PyHCL is implement using with
, a built-in Python feature. when
is similar to if
in Python, elsewhen
is similar to elif
and Otherwise
is similar to else
. When you writing a PyHCL conditional statements, you must insure that all braches of the conditional statement to be covered.
Now you have already learn all the basic material of PyHCL. You would be able to design a lot of circuit using PyHCL now, but it is more better to learn more about the advanced topics of PyHCL. In later sections, we would introduce several advanced topics abouht PyHCL.