Skip to content

Lab 4: TinyRV1 Processor
Part D: FPGA Prototype V2

Lab 4 will give you experience designing, implementing, testing, and prototyping a single-cycle processor microarchitecture. The processor will implement the TinyRV1 instruction set. The instruction set manual is located here:

The lab will continue to leverage concepts from Topic 2: Combinational Logic, Topic 3: Boolean Algebra, Topic 4: Combinational Building Blocks, Topic 6: Sequential Logic, Topic 7: Finite-State Machines, and Topic 8: Sequential Building Blocks. The lab will also leverage concepts from Topic 9: Instruction Set Architecture and Topic 10: Single-Cycle Processors The lab will continue to provide opportunities to leverage the three key abstraction principles: modularity, hierarchy, and regularity.

The lab includes six parts:

See canvas calendar or course schedule for all due dates.

  • Part A: Processor Components

  • Part B: TinyRV1 Processor

  • Part C: FPGA Prototype v1

    • Due the 1st FPGA week of Lab 4 during assigned lab section
    • This part will focus on prototyping the code developed in Part A+B
    • Even though completed with a partner, every student must turn in their own paper check-off sheet in their lab section!
  • Part D: FPGA Prototype v2

    • Due the 2nd FPGA week of Lab 4 during assigned lab section
    • This part will focus on prototyping the code developed in Part A+B
    • Even though completed with a partner, every student must turn in their own paper check-off sheet in their lab section!
  • Part E: TinyRV1 Assembly

    • Submit via GitHub by 11:59 PM
    • This part will include all of the assembly developed during Part C+D
  • Part F: Report

    • Due on the last day of classes at 11:59pm for all groups!
    • Post-lab survey on Canvas is due at the same time as the report

This handout assumes that you have read and understand the course tutorials and that you have attended the discussion sections. This handout assumes you have successfully completed Parts A and B meaning your processor, memory bus, and SPI are all working in simulation.

What do we do if Parts A and B is not done?

If Parts A and B are not done then you cannot get started on this part. You must focus on getting your processor, memory bus, and SPI working before you can complete anything in this part.

Here are the steps to get started:

  • Step 1. Find your lab partner
  • Step 2. Find a free workstation
  • Step 3. Ask the TAs for a lab check-off sheet (each student needs their own check-off sheet)

For each lab report task you must take some notes, save a screenshot, and/or record some data for your lab report. The lab report is not due until the last day of classes.

For each lab check-off task you must raise your hand and have a TA come to check-off your work. The TA will ask you the questions included as part of the lab check-off task and the assess your understanding using the following rubric: mastery; accomplished; emerging; beginning. If the TA and students together feel the students have not mastered the lab check-off task, the students are encouraged to take a few minutes and try again.

The Final Lab

This is the final lab of the semester. It will require students to leverage all they have learned throughout the semester. Students will need to:

  • use iverilog to simulate various designs on ecelinux;
  • use Quartus to integrate, analyze, synthesize, and configure an FPGA prototype;
  • write, assemble, and load assembly programs for their TinyRV1 processor;
  • wire various electrical components on a breadboard; and
  • use the oscilloscope to visualize electrical signals.

If students have not mastered these skills, they might need to revisit material from previous lab assignments. Students must maintain a sense of urgency and leverage all of they learned in order to complete the lab assignment. There are no extensions and students cannot complete this part at any other time except during their assigned lab section.

Lab Check-Off Task 1: Setup Lab Kit

The TAs will pass out an ECE 2300 Lab Kit to each group. The TAs will record the kit number on your check-off sheet. For this lab, you will receive the FPGA board, a USB-B cable, a USB-C cable, and a component box with some jumper wires, a piezo buzzer, a digital distance sensor, and a USB flash drive. Use the USB-B cable to plug the FPGA board into the workstation.

1. Simulate the Single-Cycle TinyRV1 Processor

Before starting to work on an FPGA prototype, you must make sure you have a working Verilog hardware design that has been thoroughly tested in simulation. We will be rerunning the same test simulations and using the same interactive simulators as last week. One student should start VS Code on the workstation, log into the ecelinux servers, source the setup script, and make sure their group repository is up to date.

% source setup-ece2300.sh
% cd ${HOME}/ece2300/groupXX
% git pull
% tree

Where XX is your group number.

1.1. Verify All Four Labs

Now run all of the tests from a clean build to ensure your design is fully functional.

% cd ${HOME}/ece2300/groupXX
% trash build
% mkdir build
% cd build
% ../configure
% make check

Lab Check-Off Task 2: Verify All Four Labs

Show a TA that your hardware designs are passing all of your tests. You must pass all of the tests from Lab 1, Lab 2, and Lab 3. You must also pass all of the Lab 4 Part A and B tests.

1.2. Copying Files to Workstation

We now need to get the files for your design from ecelinux onto the workstation. This requires multiple steps.

  • Step 1. Click Microsoft Edge on the desktop to open a web-browser on the workstation to log into GitHub and then find your repository

  • Step 2. Start PowerShell by clicking the Start menu then searching for Windows PowerShell

  • Step 3. Use the following command to change to your home directory on the workstation in the lab (where netid is your Cornell NetID)

% cd C:\Users\netid
  • Step 4. Clone your repo onto the workstation by using this command in PowerShell (where netid is your Cornell NetID, notice we are using https!):
% git clone https://github.com/cornell-ece2300/groupXX
  • Step 5. In the Connect to GitHub pop-up, click Sign in with your browser

  • Step 6. You may be asked for your GitHub username again and you may be asked to authorize the Git Credential Manager; click authorize git-ecosystem

  • Step 7. Verify that you have successfully cloned your repo by changing into your repo and using tree on the workstation:

% cd groupXX
% tree

2. Setup Quartus Project

Click Quartus (Quartus Prime 18.1) on the desktop to start Quartus. Important: Ensure that the Quartus Version is 18.1 and not 23.1. Then, click Run the Quartus Prime software. You might need to try starting Quartus twice. Setup a new Quartus project using the New Project Wizard:

  • Directory, Name, Top-Level Entity
    • You must enter the working directory as follows with your NetID!
    • Working directory: C:\Users\netid\lab4d
    • Name of this project: lab4d
    • Name of top-level design entity: lab4d
    • Click Next
  • Directory does not exist. Do you want to create it?
    • Click yes
  • Project Type
    • Choose Empty Project
    • Click Next
  • Add Files
    • Click User Libraries...
    • Click triple dots to the right of Project library name
    • Click on This PC, then navigate to your cloned repo by choosing Windows (C:) > Users > netid > groupXX where XX is your group number
    • Click Select Folder
    • Click Add
    • Click OK
    • Click triple dots to right of File name
    • Click on This PC, then navigate to your cloned repo by choosing Windows (C:) > Users > netid > groupXX > lab4 where XX is your group number
    • Shift-click on every Verilog hardware design file (do not include any files in the test or sim subdirectories)
    • Click Open
    • Click Next
  • Family, Device, and Board Settings
    • Click Board tab
    • Family: Cyclone V
    • Select DE0-CV Development Board
    • Make sure Create top-level design file is checked
    • Click Next
  • EDA Tool Settings
    • Click Next
  • Summary
    • Click Finish

As in previous labs, you must use the following steps to ensure Quartus knows your design includes RTL modeling:

  • Choose Assignments > Settings from the menu
  • Select the category Compiler Settings > Verilog HDL Input
  • Under Verilog version click SystemVerilog
  • Click OK

3. TinyRV1 Processor FPGA Prototype

We will now integrate your TinyRV1 single-cycle processor into a complete embedded system, synthesize the design, and configure the FPGA so we can run machine programs on the real prototype. We will use the TinyRV1 processor FPGA prototype to implement a door monitoring embedded system.

3.1. Integrate

We want to implement a TinyRV1 processor FPGA prototype with the following specification:

  • Input to clock divider is connected to the 50MHz clock on the FPGA board
  • rst (ACTIVE LOW!) is connected to the reset button on the board using a synchronizer
  • The left most push button will be the go button (see below)
  • The left five switches are in0
  • The right five switches are in1
  • The right three push buttons are the three least significant bits of in2 (ACTIVE LOW!)
  • The two seven-segment displays on the left are out0
  • The two seven-segment displays in the middle are out1
  • The two seven-segment displays on the right are out2
  • The left most LED shows the go bit
  • The right eight LEDs are for out3
  • The general-purpose pins will be used to connect to the SPI
    • SCLK connects to GPIO_1[1] which connects to D0 on USB-to-SPI adapter
    • MOSI connects to GPIO_1[3] which connects to D1 on USB-to-SPI adapter
    • MISO connects to GPIO_1[5] which connects to D2 on USB-to-SPI adapter
    • CS connects to GPIO_1[7] which connects to D3 on USB-to-SPI adapter
  • The general-purpose pins will also be used with the oscilloscope and two new external I/O devices
    • The least significant bit of out3 connects to GPIO_1[11] which will be probed by the oscilloscope
    • The distance sensor connects to GPIO_1[13]
    • The output of the multi-note player connects to GPIO_1[15]

Here is a block diagram and annotated FPGA board and breadboard diagram illustrating the system we will be prototyping for Part E.

The differences between this system and what you implemented in the previous lab are highlighted in red on the block diagram and include two new external I/O devices.

Distance Sensor

We will be using a digital distance sensor in our door monitoring embedded system. The digital distance sensor looks like this:

The sensor uses light detection and ranging (LIDAR) to measure distance by emitting laser pulses and measuring the time it takes for them to bounce back. You can read more about the sensor here:

The sensor has three pins:

  • Ground marked with a negative (-) sign
  • Vdd marked with a plus (+) sign
  • Output marked as out

You will need to connect the Vdd and ground pins appropriately on the breadboard, and connect the output to the correct general-purpose I/O pin. Make sure to point the LIDAR towards the edge of the breadboard and that no wires obstruct the LIDAR.

The sensor is preconfigured to detect objects within 100cm. This makes it a digital distance sensor meaning the output with be either one or zero based on whether or not the sensor detects an object. The sensor is ACTIVE LOW so the output is one when there is no object detected within 100cm and the output is zero when there is an object detected within 100cm.

Multi-Note Player

We will be integrating your multi-note player from Lab 3 as an external output device for our door monitoring embedded system. The note output from the multi-note player will be connected to a piezo buzzer using a general-purpose I/O pin just as in Lab 3. The play_note_rdy signal is connected back to the play_note_val through a DFFR. This means the multi-note player will continuously play whatever note is specified using play_note_num. The play_note_num input is connected to out3, so to play a note from an assembly program we can simply store the desired note to the appropriate memory-mapped I/O address. For example, the following assembly fragment plays the note 3:

addi x1, x0, 3
sw   x1, 0x20c(x0)

Here is a template you can use for your top-level design.

//----------------------------------------------------------------------
// Clock Divider
//----------------------------------------------------------------------
// You need to connect the ports to the appropriate top-level ports.

logic clk;

ClockDiv_RTL clock_div
(
  .clk_in     (/* fill this in */),
  .divide_sel (1),
  .clk_out    (clk)
);

//----------------------------------------------------------------------
// Reset Synchronizer
//----------------------------------------------------------------------
// You need to connect the ports to the appropriate top-level ports.

logic rst;

Synchronizer_RTL reset_sync
(
  .clk (clk),
  .d   (/* fill this in */), // REMEMBER: Reset port is active low!
  .q   (rst)
);

//----------------------------------------------------------------------
// DFFRE for go bit
//----------------------------------------------------------------------
// You need to connect the ports to the appropriate top-level ports.

logic go;

DFFRE_RTL go_reg
(
  .clk (clk),
  .rst (rst),
  .d   (1'b1),
  .en  (/* fill this in */), // REMEMBER: Push buttons are active low!
  .q   (go)
);

assign /* fill this in */ = go;

//----------------------------------------------------------------------
// Processor
//----------------------------------------------------------------------

logic        imem_val;
logic        imem_wait;
logic [31:0] imem_addr;
logic [31:0] imem_rdata;

logic        dmem_val;
logic        dmem_wait;
logic        dmem_type;
logic [31:0] dmem_addr;
logic [31:0] dmem_wdata;
logic [31:0] dmem_rdata;

logic        trace_val;
logic [31:0] trace_addr;
logic [31:0] trace_data;
logic        trace_wen;
logic [4:0]  trace_wreg;
logic [31:0] trace_wdata;

ProcScycle proc
(
  .imem_wait (~go),
  .dmem_wait (~go),
  .*
);

//----------------------------------------------------------------------
// Memory Bus
//----------------------------------------------------------------------

logic        hmem_val;
logic [31:0] hmem_addr;
logic [31:0] hmem_wdata;

logic        mem0_val;
logic        mem0_wait;
logic        mem0_type;
logic [31:0] mem0_wdata;
logic [31:0] mem0_addr;
logic [31:0] mem0_rdata;

logic        mem1_val;
logic        mem1_type;
logic [31:0] mem1_addr;
logic [31:0] mem1_wdata;
logic [31:0] mem1_rdata;
logic        mem1_wait;

logic [31:0] in0, in1, in2, in3;
logic [31:0] out0, out1, out2, out3;

MemoryBus_RTL memory_bus
(
  .*
);

//----------------------------------------------------------------------
// Physical Memory
//----------------------------------------------------------------------

Memory physical_memory
(
  .*
);

//----------------------------------------------------------------------
// SPI
//----------------------------------------------------------------------
// You need to connect sclk, mosi, miso, and cs to the appropriate
// top-level ports.

logic sclk;
logic mosi;
logic miso;
logic cs;

assign sclk = /* fill this in */;
assign mosi = /* fill this in */;
assign miso = /* fill this in */;
assign cs   = /* fill this in */;

SPI_RTL minion
(
  .*
);

//----------------------------------------------------------------------
// External Inputs
//----------------------------------------------------------------------
// You need to connect the ports to the appropriate top-level ports.

assign in0 = { 27'b0, /* fill this in */ };
assign in1 = { 27'b0, /* fill this in */ };

// REMEMBER: The push buttons are active low!
assign in2 = { 29'b0, /* fill this in */ };

// REMEMBER: The distance sensor is active low!
assign in3 = { 31'b0, /* fill this in */ };

//----------------------------------------------------------------------
// External Outputs
//----------------------------------------------------------------------
// You need to connect the ports to the appropriate top-level ports.

DisplayOpt_GL display_out0
(
  .in       (out0[4:0]),
  .seg_tens (/* fill this in */),
  .seg_ones (/* fill this in */)
);

DisplayOpt_GL display_out1
(
  .in       (out1[4:0]),
  .seg_tens (/* fill this in */),
  .seg_ones (/* fill this in */)
);

DisplayOpt_GL display_out2
(
  .in       (out2[4:0]),
  .seg_tens (/* fill this in */),
  .seg_ones (/* fill this in */)
);

assign /* fill this in */ = out3[7:0];
assign /* fill this in */ = out3[0];

//----------------------------------------------------------------------
// Multi-Note Player Clock Divider
//----------------------------------------------------------------------
// You need to connect the ports to the appropriate top-level ports.

logic mnp_clk;

ClockDiv_RTL mnp_clock_div
(
  .clk_in     (/* fill this in */),
  .divide_sel (9),
  .clk_out    (mnp_clk)
);

//----------------------------------------------------------------------
// Instantiate the multi-note player
//----------------------------------------------------------------------
// You need to connect the ports to the appropriate top-level ports.

logic play_note_val;
logic play_note_rdy;

DFFR_RTL mnp_val_reg
(
  .clk (clk),
  .rst (rst),
  .d   (play_note_rdy),
  .q   (play_note_val)
);

logic [2:0] note_sel;
logic note;

MultiNotePlayer_RTL player
(
  .clk           (mnp_clk),
  .rst           (rst),

  .note_duration (16'd512),
  .note1_period  (8'd123),
  .note2_period  (8'd109),
  .note3_period  (8'd97),
  .note4_period  (8'd91),
  .note5_period  (8'd81),
  .note6_period  (8'd72),
  .note7_period  (8'd68),

  .play_note_val (play_note_val),
  .play_note_rdy (play_note_rdy),
  .play_note_num (out3[2:0]),


  .note_sel      (note_sel),
  .note          (note)
);

assign /* fill this in */ = note;

You will need to also include the following modules.

`include "lab1/DisplayOpt_GL.v"
`include "lab3/DFFRE_RTL.v"
`include "lab3/DFFR_RTL.v"
`include "lab3/ClockDiv_RTL.v"
`include "lab3/MultiNotePlayer_RTL.v"
`include "lab4/Synchronizer_RTL.v"
`include "lab4/ProcScycle.v"
`include "lab4/MemoryBus_RTL.v"
`include "lab4/SPI_RTL.v"
`include "lab4/Memory.v"

Use the following steps when you are ready to integrate the counter.

  • Double-click on DE0_CV_golden_top
  • Instantiate the template shown above
  • Fill in the connections to the top-level ports
  • Be sure to include all the required modules at the top
  • Choose File > Save from the menu

Then make sure to hook up the SPI interface on the breadboard as mentioned above.

  • SCLK connects to GPIO_1[1] which connects to D0 on USB-to-SPI adapter
  • MOSI connects to GPIO_1[3] which connects to D1 on USB-to-SPI adapter
  • MISO connects to GPIO_1[5] which connects to D2 on USB-to-SPI adapter
  • CS connects to GPIO_1[7] which connects to D3 on USB-to-SPI adapter

Connect the oscilloscope probe to GPIO_1[11]. Make sure your distance sensor is connected to GPIO_1[13] and the piezo buzzer is connected to GPIO_1[15]. There is a red LED on the back of the distance sensor which will go on and off when it detects an obstacle; test it out to make sure it is working.

Lab Check-Off Task 3: Discuss TinyRV1 Processor Integration

Show a TA your breadboard wiring and your top-level integration. Discuss how the connections provided in the template implement the specification. Confirm with the TA that you have correctly accounted for the fact that reset, all push-buttons, and the distance sensor are active low! Show how you have connected GPIO_1[11] to the oscilloscope. Make sure the red LED on the back of the distance sensor goes on and off when it detects an obstacle. Take your time and double check all connections! Synthesizing the processor takes 10 minutes so get your connections right the first time!

3.2. Synthesize

You will need to use the following timing constraint file:

set_max_delay -from [all_inputs] -to [all_outputs] 20
set_min_delay -from [all_inputs] -to [all_outputs] 0

create_clock -name CLOCK_50 -period 20 [get_ports {CLOCK_50}]
create_generated_clock -name clk -divide_by 4 -source CLOCK_50 \
  [get_nets {clock_div|counter_reg|q[1]}]
create_generated_clock -name mnp_clk -divide_by 1024 -source CLOCK_50 \
  [get_nets {mnp_clock_div|counter_reg|q[9]}]

set_output_delay -add_delay -clock clk -max 0 [all_outputs]
set_output_delay -add_delay -clock clk -min 0 [all_outputs]

set_input_delay  -add_delay -clock clk -max 0 [all_inputs]
set_input_delay  -add_delay -clock clk -min 0 [all_inputs]

We are now using two different clock dividers, one for the processor and one for the multi-note player, so we must specify two different generated clocks.

Now use the following steps to synthesize your design.

  • Choose Processing > Start Compilation from the menu
  • Wait ten minutes for synthesis to complete
  • While you are waiting go ahead and start reading the next section and you can even start working on your door monitoring assembly program!

How do I fix "can't open Verilog Design File" errors?

This probably means you did not setup the user library correctly, so Quartus cannot find the files you are including using the include Verilog preprocessor directive. You can use the following steps to fix this:

  • Choose Assignments > Settings from the menu
  • Select the category Libraries
  • Click triple dots to the right of Project library name
  • Click on This PC, then navigate to your cloned repo by choosing Windows (C:) > Users > netid > groupXX where XX is your group number
  • Click Select Folder
  • Click Add
  • Click OK
  • Choose Processing > Start Compilation from the menu to see if this fixes the issue

How do I fix "Verilog HDL syntax" errors?

This might be because you did not configure Quartus to use SystemVerilog! You can use the following steps to ensure Quartus knows your design includes RTL modeling:

  • Choose Assignments > Settings from the menu
  • Select the category Compiler Settings > Verilog HDL Input
  • Under Verilog version click SystemVerilog
  • Click OK

Once your design is fully synthesized, let's use the RTL viewer to appreciate how far we have come this semester.

  • RTL Viewer
    • Choose Tools > Netlist Viewer > RTL Viewer from the menu
    • Use the Netlist Navigator to gradually drill down in the hierarchy as follows:
      • ProcScycle
      • ProcScycleDpath
      • ALU_32b
      • Adder_32b_GL
      • AdderCarrySelect_16b_GL
      • AdderRippleCarry_8b_GL
      • FullAdder_GL
    • Take a screenshot of the entire RTL viewer window; it must clearly show the Netlist Navigator with the full hierarchy from the top to the full adder on the left and the gate-level implementation of the full adder on the right.
    • Choose File > Close from menu to close the RTL viewer

Lab Report Task 1: Collect Data for Single-Cycle Processor

Save the screenshot of the entire RTL viewer window for your lab report.

3.3. Configure

Now we are finally ready to configure the FPGA for TinyRV1 single-cycle processor prototype.

  • Choose Tools > Programmer from the menu
  • Click Hardware Setup
  • Currently selected hardware: USB-Blaster [USB-0]
  • Click Close
  • Click Start

Start by testing out the default assembly program as in the last lab. Then use PowerShell on the workstation to assemble the assembly test programs and load them into the physical memory in our FPGA prototype over SPI. These commands should be done on the workstation not on ecelinux!

% cd C:\Users\netid\groupXX
% mkdir build
% cd build
% python ..\scripts\tinyrv1-assemble -o test1.bin ..\lab4\asm\test1.asm
% python ..\scripts\tinyrv1-load test1.bin

Remember to first reset the processor, then load the program, then press the go button. Then try assembling and loading both test1.asm and test2.asm and confirm the perform as expected. Then take a look at test3.asm.

loop:
  lw   x1, 0x208(x0)
  sw   x1, 0x21c(x0)
  jal  x0, loop

This test program simply reads the push buttons and outputs the result to out3 which is connected to the oscilloscope, LEDs, and the multi-note player. Try pressing the right most push button and confirm that you can hear a note and that you can see a signal on the oscilloscope.

Lab Check-Off Task 4: Demonstrate TinyRV1 Processor Prototype

Show a TA your processor running test3.asm. Show pressing the right most push button and demonstrate you can hear a note and can see a signal on the oscilloscope.

4. Door Monitoring Embedded System

The final culminating design is to implement both the software and hardware for a door monitoring embedded system which leverages all you have learned throughout the semester. The hardware is based on the TinyRV1 embedded system you implemented on the FPGA in the previous parts which includes the two new external I/O devices: a distance sensor and a multi-note player. It should be no surprise by now that we will be taking an incremental approach.

  • Step 1: Implement and test distance sensor
  • Step 2: Implement and test sensor and counter
  • Step 3: Implement and test sensor, counter, and alarm
  • Step 4: Implement and test sensor, counter, and beep

For each step, we recommend first writing out some pseudo-code. Then you can either develop the assembly program on ecelinux and use the ISA and single-cycle processor simulator first to verify its correctness or just go ahead and try developing the program directly on the FPGA prototype. If you are more confident in your mastery of both the software and hardware in your embedded system feel free to try directly developing on the FPGA prototype, or consider using the simulator for just some of the steps.

5.1. Step 1: Distance Sensor

Implement an assembly program in door-monitor-step1.asm that reads the distance sensor and outputs the result on the seven-segment displays using out0. If the system does not detect an object, then it should display a zero. If the system does detect an object it should display a one.

5.2. Step 2: Sensor and Counter

Implement an assembly program in door-monitor-step2.asm that adds a traffic counter to the door monitor embedded system. If the system detects a person walking by it should increment the traffic counter by one. The traffic counter should be displayed on the seven-segment displays using out0.

Note that you cannot simply increment the counter whenever the distance sensor is one. Whenever a person walks by, the distance sensor will output one for many, many cycles. You need to instead wait for the distance sensor to be one, then wait for the distance sensor to go back to zero, and then increment the counter.

5.3. Step 3: Sensor, Counter, and Alarm

Implement an assembly program in door-monitor-step3.asm that adds an alarm to the door monitoring embedded system.

If the system detects a person walking by it should increment the traffic counter by one. The traffic counter should be displayed on the seven-segment displays using out0.

In addition, the system should play a note using the multi-note player whenever a person walks by. You can play the note when the sensor first goes high, or when the sensor goes low. For this step, the system should just start playing a note when it detects the first person and then never stop playing the note. You can reset the system to turn off the alarm.

5.4. Step 4: Sensor, Counter, and Beep

Implement an assembly program in door-monitor-step4.asm that turns the alarm into a beep for the door monitoring embedded system.

If the system detects a person walking by it should increment the traffic counter by one. The traffic counter should be displayed on the seven-segment displays using out0.

In addition, the system should play a beep using the multi-note player whenever a person walks by. You can play the beep when the sensor first goes high, or when the sensor goes low. To play a beep, first play a note using the multi-note player, then add a delay, then play note zero to turn off the multi-note player. To add a delay simply create a loop that does nothing except iterates for maybe 500ms. With a clock period of 40ns, waiting 500ms might require several million iterations. You can initialize a register with a large immediate value (which will then serve as the loop counter) by loading the large number from memory like this:

  # load the value 1000000 into x1
  lw x1, 0x100(x0)
  ...

  .data
  .word 1000000

When you are finished with this step your door monitoring embedded system should sense whenever anyone walks by, increment the traffic counter, and make a small beep.

Take a minute to appreciate all you have accomplished! You have now created all of the hardware and software for a complete (albeit simple) embedded system including:

  • GL implementation of a five-digit numeric display
  • GL implementation of a 32-bit ALU including an adder and equality comparator
  • RTL implementation of a multi-note player including various structural datapaths and a FSM-based control unit
  • GL and RTL implementation of a TinyRV1 single-cycle processor
  • RTL implementation of a memory bus and SPI
  • Integrating all of this into the hardware for a door monitoring embedded system with many different memory-mapped external I/O devices
  • Bread boarding the SPI adapter, distance sensor, and piezo buzzer
  • Developing a software door monitor program with 30+ assembly instructions

This has required implementing over 50 hardware modules using over 5000 lines of both gate-level and register-transfer level Verilog modeling. Even more importantly, you have verified these modules with hundreds of test cases. You have also manually implemented eight software programs with a total of almost 100 assembly instructions. You should be very proud of this tremendous accomplishment!

Lab Check-Off Task 5: Demonstrate the Door Monitoring Embedded System

Show a TA your door monitoring embedded system in action! You do not need to show the door monitoring system in simulation; just show the TA everything working on the real prototype.

Lab Check-Off Task 6: Turn in Lab Kit

When you are finished with your demo, pack up your ECE 2300 Lab Kit. Put the jumper wires, a piezo buzzer, a digital distance center, and a USB flash drive back in the component box. Return the FPGA board, USB cables, and component box to a TA who will then record the kit number on your check-off sheet, initial the final check-off, and then collect your check-off sheet.

5. Optional Extension: Advanced Door Monitoring Embedded System

This section is an optional extension to the main lab and is meant for students who have already completed all of the above tasks. Students might consider adding one of several more advanced features to their door monitoring embedded system:

  • Play a few notes instead of just beeping every time a person passes by.

  • Use the switches to set a "room capacity limit" which should be displayed on the seven-segment displays; when the room reaches capacity an alarm should go off indicating that the room is now full.

  • Use a switch to configure the door monitoring embedded system into one of two modes: in "day mode" should function exactly as above; in "night mode" instead of counting traffic, the system should sound an alarm if someone passes by

  • Use switches to enable a secret alarm passcode to turn off the alarm in night mode.

  • Use a second distance sensor to see if you can detect which way a person is passing; increment the counter when a person walks one way and decrement the counter when a person walks the opposite way