====== Register File ====== In this lab you will learn how to use sequential flip-flop circuits to build a 8x4 register file. ===== Learning Outcomes ===== * Create a sequential circuit using FDCE flip-flop primitives * Learn how to organize flip-flops into a register and register file ===== 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 create a 4-bit register and then combine several 4-bit registers to construct a collection of registers aka a **register file**. The FDCE flip-flop is available to you without any extra work required on your part, you merely need to instance them 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. {{ :tutorials: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(clock_enable), .CLR(1'b0), .D(ff_input)); The example shown above assigns a constant zero to the CLR input for the common case when you never apply an asynchronous clear. Create a waveform for the signal **Q** on an FDCE element using the waveform provided below. {{ :tutorials:fdce_waveform.png?nolink&680 |}} ===== Exercises ===== ==== Exercise #1 - 4-Bit Register ==== For this exercise you will create a 4-bit register. Begin this exercise by creating an empty SystemVerilog module with the following name and ports. ^ Module Name: register4 ^^^^ ^ Port Name ^ Direction ^ Width ^ Function ^ | clk | Input | 1 | Clock input | | reset | Input | 1 | Reset input | | datain | Input | 4 | Data to be loaded into register | | we | Input | 1 | Write enable | | dataout | Output | 4 | Register output | For the body of this module, instance four FDCE flip-flops and complete the following steps. * Attach the clock of each flip flop, **C**, to the 4-bit register module's **clk** signal. * Attach the asynchronous clear of each flip flop, **CLR**, to the 4-bit register module's **reset** signal. * Attach the 4-bit register's **we** signal to the **ce** input of each flip-flop. * Attach a different bit of **datain** to the **D** input of each FDCE flip-flop. * Attach the **Q** output of each flip-flop to a corresponding **dataout** bit. /* * The FDCE's asynchronous clear input **clr** is not going to be used in this lab; assign a constant ''1'b0'' to this input on each flip-flop.*/ After creating your 4-bit 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 # add oscillating clock input add_force clk {0 0} {1 5ns} -repeat_every 10ns # clear value add_force reset 1 run 10 ns add_force reset 0 # initialize signals add_force we 0 add_force datain 0000 run 10 ns # Prepare for a write add_force datain 1101 add_force we 1 run 10 ns add_force datain 0110 add_force we 0 run 10 ns **Exercise 1 Pass-off:** Show a TA your code for your register4 module and your simulation waveform.\\ \\ ==== Exercise #2 - 8x4 Register File ==== In this exercise, you will create a 8x4 register file (eight registers of 4 bits each). In particular, you will be creating a **triple-ported** register file or a register file that has one write port and two read ports. The register file you will construct is loosely based on Figure 19.3 in your textbook. Begin your register file module by creating the module declaration and the input and output ports as follows: ^ Module Name: register_file_8x4 ^^^^ ^ Port Name ^ Direction ^ Width ^ Function ^ | clk | Input | 1 | Clock input | | reset | Input | 1 | Active-high reset, clears all registers | | datain | Input | 4 | Data to be loaded into register file | | we | Input | 1 | Write enable | | waddr | Input | 3 | Write address | | raddr1 | Input | 3 | Read address for port 1 | | raddr2 | Input | 3 | Read address for port 2 | | dataout1 | Output | 4 | Data out for port 1 | | dataout2 | Output | 4 | Data out for port 2 | After creating the module interface, construct your register file by including each of the following components that are shown in Figure 19.3. - Create the **Write Decoder** that generates a unique register write signal for each of the eight registers. As described in the reading, this decoder will decode write address (**waddr**) and use the **we** signal to generate a write enable for each register. - Instance eight of the 4-bit registers that you created in the previous exercise. These eight registers form the core of the register file module. - Attach the clock and reset inputs to all eight registers and the **datain** signal to the input to each register. - Create two 8:1 multiplixers for the read ports. After creating your register file and removing all syntax errors, simulate your register file by creating a TCL script. In this script, make sure you perform the following tests. - Perform a write to several different address locations. - Read these addresses and make sure the data was properly loaded. - Perform reads on both ports simultaneously with different addresses to demonstrate the ability to read two different locations at the same time. 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 register8x4 module and your simulation waveform. Show that your tcl file meets the requirements listed above.\\ \\ ==== Exercise #3 - Top-level design and Testbench ==== For this final exercise you will create a top-level module that instances your register file. This top-level module will include other circuitry to interface the Nexys4 board with your register file. Begin this exercise by creating a module with the following top-level ports. ^ Module Name: register_top ^^^^ ^ Port Name ^ Direction ^ Width ^ Function ^ | clk | Input | 1 | Clock input | | CPU_RESETN | Input | 1 | Active-low reset, clears all registers | | sw | Input | 10 | Switches for address input and data input | | btnc | Input | 1 | Write to register file | | btnr | Input | 1 | Display the value of data2 | | btnu | Input | 1 | Display the value of data1+data2 | | btnd | Input | 1 | Display the value of data1-data2 | | btnl | Input | 1 | Display the value of data1&data2 | | segment | Output | 8 | Cathode signals for seven segment display | | anode | Output | 8 | Anode signals for each of the eight digits | Instance your register_file_8x4 module you created in the previous exercise and complete the following. * Attach the top-level clock input to the clock port of the register file. * Attach the top-level reset input (CPU_RESETN) to the ''reset'' port of the register file. Note: The CPU_RESETN button is active-low (0 when pressed), so you will want to connect the inverted signal (~CPU_RESETN) to the register file. * Attach the **btnc** input to the **we** input of the register file (the center button will be used to write new values into the register file). * Attach **sw[3:0]** to the **datain** input of the register file. The lower four switches will be used to set the data that is written into the register file. * Attach **sw[6:4]** to the **waddr** and **raddr** input ports of the register file. These three switches will be used for the write address and first read address. * Attach **sw[9:7]** to the **raddr2** input port of the register file. These three switches will be used for the second read address. After connecting your register file, add a seven segment decoder. You can instance your module from the seven segment decoder lab or you can use the dataflow code from lab 6. In either case, you should only turn on the right most segment of the display and do not turn on any of the digit points. Create a dataflow circuit that displays register values on the seven segment display based on the buttons as follows, from highest to lowest precedence. * When **btnr** is pressed, display the value from the second read port ''dataout2''. * When **btnu** is pressed, display the sum of the two read port values ''dataout1+dataout2''. * When **btnd** is pressed, display the difference of the read port values ''dataout1-dataout2''. * When **btnl** is pressed, display the bitwise AND of the two read port values ''dataout1&dataout2''. * If none of the buttons listed above are pressed (btnd, btnu, or btnr), display the value of the first register ''dataout1''. Once you have completed your top-level design, simulate it with the following {{ :labs:tb_registerfile.v |testbench}} file. Continue to debug your code until your top-level design passes the testbench with no errors. Copy the console output for your testbench simulation and add it to your laboratory report. **Exercise 3 Pass-off:** Show a TA your code for your top level module and your testbench output.\\ \\ ==== Exercise #4 - Synthesis, Implementation, and Download ==== When your design has passed the testbench, create an XDC file for your design to declare the pin number for each top-level port of the design. For the first time you will be attaching a clock signal. You will also need a **create_clock** command to declare the frequency of the clock. 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}]; Perform the steps of Synthesis, Implementation, and Bitstream Generation. Download your design and experiment with several cases on the board to be sure that it is working properly. Provide a summary of your synthesis warnings. Summarize the size of your circuit (LUTs and FFs). You'll find the number of FFs used in the same place you find the number LUTs used. ===== Final Pass Off ===== Pass off your laboratory by demonstrating the following to the TA: * Pass offs for Exercises 1, 2, and 3 * Your working circuit on the Nexys4 board How many hours did you work on the lab? Provide any suggestions for improving this lab in the future. Submit your 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: * Experiment with a different sized register file. * Create additional functionality for your top-level circuit. * Explore the internals of the FPGA design and see how the register file is mapped onto the FPGA. Describe your personal exploration activities. /* ===== Lab Report ===== * **Header** * Class * Lab * Name * Section * **Preliminary** * Q waveform * **Exercise 1** * Simulation screenshot * 4-bit register Verilog * **Exercise 2** * TCL script * Register file Verilog * **Exercise 3** * Top-level Verilog * **Exercise 4** * Synthesis warnings * Number of LUTs and FFs * Personal exploration description * Hours spent on lab * Feedback */ ---- [[labs:ta:registerfile|TA Notes and Feedback]]