User Tools


This is an old revision of the document!


Under Development: Fun With Registers

In this lab you will do some experimentation with flip flops to learn how they operate. You will create a single-bit loadable register, a 4-bit loadable register, and a counter.

Learning Outcomes

  • Create a sequential circuit using FDCE flip-flop primitives
  • Learn how to organize multiple flip-flops into a register
  • Create a clearable counter

Preliminary

The Artix-7 FPGA we are using has built-in flip-flops that you can use to make sequential circuits. You will use FDCE flip-flop primitives to construct a few simple register-type circuits. The FDCE flip-flop is available to you without any extra work required on your part, you merely need to instance it into your design the same way you instance your own modules into your designs. Read the following pdf file to learn about the FDCE module, its ports, and how to instance the module in your SystemVerilog.

fdce.pdf

The SystemVerilog example below demonstrates how to instance a single FDCE flip-flop into a design:

FDCE my_ff (.Q(ff_output), .C(clk), .CE(1'b1), .CLR(1'b0), .D(ff_input));

The example shown above assigns a constant zero to the CLR input and a constant one to the clock_enable since we will not use those functions. As a result, what you are getting is basically a flip flop with a D input, a clock input (C), and a Q output. NOTE: this is a rising edge triggered flip flop.

Exercises

Exercise #1 - 1-Bit Register

For this exercise you will create a 1-bit register. It is exactly the circuit in Figure 16.4 in the textbook. Begin this exercise by creating an empty SystemVerilog module with the following name and ports.

Module Name: blinky
Port Name Direction Width Function
clk Input 1 Clock input
D Input 1 Data to be loaded into register
LOAD Input 1 Control signal to cause register to load
Q Output 1 Register output

Note that in Figure 16.4 there is an unlabelled signal — it is the output of the MUX (which is also the input to the flip flop). So, declare a logic signal for that wire. Then, instance one FDCE flip-flop as shown above. Then, add either a single dataflow statement or an always_comb block to implement the MUX logic. You should now have logic which implements the MUX and have the MUX wired to the ports on the FDCE. This is called a “loadable register”. On each rising edge of clk, If LOAD is high, then the flip flop will load what is on its D input. On the other hand, if LOAD is low, then the flip flop will load its old value.

SANITY CHECK: your code should have approximately 5 lines. If it has a lot more you are likely on the wrong track…

After creating your register, simulate your register with a TCL script. The following set of TCL commands demonstrates a simple test for your register file. You can use this script and add to or modify it to test your register as you like.

Make sure that your TCL file includes a run 100ns at the beginning. For the first 100ns, the FDCE primitive resets itself. During this time it won't operate at all, so wait for this time to be over.

restart
# run for 100ns so the FDCE can properly reset
run 100 ns
 
# set inputs low
add_force LOAD 0
add_force D 0
 
# add oscillating clock input with 10ns period
add_force clk {0 0} {1 5ns} -repeat_every 10ns
 
# run 2ns so that input changes below are not
# coincident with clock edges.  Otherwise, the 
# waveforms are hard to understand
run 2ns
 
# run 3 cycles before loading anything
run 30 ns
 
# load a 0
add_force LOAD 1
run 20ns
add_force LOAD 0
 
# change D and run some time
# notice that the register doesn't
# load this new value because
# the load signal is low
add_force D 1
run 20ns
 
# now let's load the register
add_force LOAD 1
run 10ns
add_force LOAD 0
add_force D 0
run 10ns
 
# now we will apply various
# data input values and watch 
# the register load them
# on succeeding clock edges
add_force D 1
run 10ns
add_force LOAD 1
run 10ns
add_force D 0
run 10ns
run 10ns
run 10ns
add_force D 1
run 10ns
run 10ns
add_force D 0

Exercise 1 Pass-off: No need to pass off this. Just make sure it works in simulation before you proceed.

Exercise #2 - 4-bit Register File

In this exercise, you will modify your register to be 4 bits wide as shown in Figure 16.5 of the textbook. To do this the changes to your code are minimal: (a) make the D and Q signals 4 bits wide in your module definition and (b) instance a total of 4 FDCE flip flops and wire them up like the one in Exercise #1. If you have used a ?: operator or an if-then-else statement to describe your MUX you probably shouldn't even have to change the MUX code.

After creating your register, simulate it by modifying your original TCL script. The only changes that you should have to make are to change the 1 and 0 values you drive into D to be more interesting numbers between 0000 and 1111.

Provide a copy of your TCL script you used to simulate the register file.

Exercise 2 Pass-off: Show a TA your code for your 4-bit register and your simulation waveform. Show that your register loads 4-bit values from D when LOAD=1 and keeps its old value otherwise.

Exercise 3

We are now going to modify your 4-bit register to create a counter and use the counter to blink some lights.

In addition to making registers to hold values, another good use of registers is to create counters. Figure 16.7 from the textbook shows such a counter. It can be cleared and it can be incremented under control of the signals CLR and INC.

Module Name: blinky
Port Name Direction Width Function
clk Input 1 Clock input
CLR Input 1 Clear control signal
INC Input 1 Increment control signal
Q Output 4 4 bits of counter's register

Modify your module definition to now reflect this (erase the old stuff). That is, do the following:

  • Change your module definition to reflect the signals in the table above.
  • Create combinational logic using a ?: assignment which implements the MUX of Figure 16.7 in the textbook.
  • Wire the MUX up to the register's input and output wires.

Modify your TCL script from above to exercise the counter. First, clear the counter and then increment for a few cycles. Then, clear it again and then increment it 20 or so cycles. Raise and lower INC as you do this to observe that it only counts on rising clock edges where INC is true. Finally, increment it enough times so that it then rolls back over to 0.

Exercise 3 Pass-off: Show a TA your code for your 4-bit counter and your simulation waveform. Show that your counter works as desired.

Exercise #4: Synthesize, Implement, and Test in Hardware

You are almost ready to synthesize, implement, and test in hardware. However, before doing so there is one more thing that must be done. In simulation it was easy to raise INC high for one clock cycle and then lower it again to get the counter to increment by just one. When you download your circuit to the board and then push the INC button you will end up holding it down for millions of clock cycles. Thus, each time you push the button in real life it will increment many many times. To fix this, we need to condition the signal.

The figure below shows what we want. Notice that each time the INC button signal goes from high to low, the CleanInc signal pulses for exactly one clock cycle. This is what we want. However, you don't know enough to design the circuit to do this and so one has been made available to you. It has the following interface:

Module Name: clean
Port Name Direction Width Function
clk Input 1 Clock input
b Input 1 The button signal
bo Output 1 The cleaned up button signal (CleanInc in the waveform above)
Q Output 4 4 bits of counter's register

You can get the file here. Add it to your project.

Now, instance it like this:

clean C0(.clk(clk), .b(INC), .bo(CleanInc));

Finally, you need to replace where you directly wired the INC signal up above to the MUX select line with the CleanInc signal. The resulting circuit should look like this:

Note that in this step we will NOT create a top-level module. What you just created IS your top level module. So now create an XDC file for your design to declare the pin numbers for each top-level port of the design.

This lab is the first time you will be attaching a clock signal. You will need a create_clock command to declare the frequency of the clock (this is so the tools know what they are dealing with and ensure that the circuitry they produce can run at that rate). These commands are available in the master XDC file and can be used by uncommenting it in your project-specific XDC file.

set_property -dict { PACKAGE_PIN E3    IOSTANDARD LVCMOS33 } [get_ports { clk }]; #IO_L12P_T1_MRCC_35 Sch=clk100mhz
create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports {clk}];

In addition, tie the CLR and INC signals to two different push buttons and tie the Q output bits to leds 3-0. From previous labs you should know how to do this.

Perform the steps of Synthesis, Implementation, and Bitstream Generation. Download your design and demonstrate that it is working properly. When you push CLR the count should go to 0. When you push INC the counter should increment once. Experiment with your counter long enough to convince yourself it really works.

AWESOME! You have designed your first sequential circuit.

Final Pass Off

Pass off your laboratory by demonstrating the following to the TA:

  • Pass off Exercise 3 (and show it working on the board)

How many hours did you work on the lab?

Provide any suggestions for improving this lab in the future.

Submit your final SystemVerilog modules using the code submission on Learning Suite. (Make sure your SystemVerilog conforms to the lab SystemVerilog coding standards).

Personal Exploration

Here are some ideas for personal exploration in this laboratory:

  • Make your counter wider and wire up to additional LEDs.
  • Wire in a copy of your 7-segment decoder from last week and have the 4-bit counter value displayed on the 7-segment display. By the way, this is way cooler than just making your counter wider…

Describe your personal exploration activities.


TA Notes and Feedback