Skip to content

Case Study: Sequential Circuits

Sunny Chen edited this page Mar 2, 2020 · 2 revisions

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.