Project 5: Programmable Lights II
Due Monday 6 April 2026
Purpose: The purpose of this project is to build a more sophisticated programmable light display. The machine language for this project includes both a conditional and an unconditional branch, enabling you to implement loops in your program.
Programmable Circuit Design
The new programmable light display will be a state machine with three states that can execute four types of instructions. Each instruction will be 10 bits long. The state machine has two data registers, the light register [LR] and the accumulator [ACC], both of which hold 8-bits. The instruction set is given below.
| Opcode | Format | Description |
|---|---|---|
| 00 | [C1 C0] [Dest1 Dest0] [Src1 Src0] [Val3 Val2 Val1 Val0] | Move from SRC to DEST |
| Dest10: 00 = ACC, 01 = LR, 10 = ACC low 4 bits, 11 = ACC high 4 bits | ||
| Src10: 00 = ACC, 01 = LR, 10 = IR low 4 bits sign extended, 11 = all 1s | ||
| 01 | [C1 C0] [Op2 Op1 Op0] [Src1 Src0] [Dest0] [Val1 Val0] | Binary operator DEST = DEST op SRC |
| Op210: 000 = add, 001 = sub, 010 = shift left, 011 = shift right maintain sign bit | ||
| Op210: 100 = xor, 101 = and, 110 = rotate left, 111 = rotate right | ||
| Src10: 00 = ACC, 01 = LR, 10 = IR low 2 bits sign extended, 11 = all 1s | ||
| Dest0: 0 = ACC, 1 = LR | ||
| 10 | [C1 C0] [U3 U2 U1 U0] [Addr3 Addr2 Addr1 Addr0] | Branch to ADDR |
| 11 | [C1 C0] [Src0] [U2 U1 U0] [Addr3 Addr2 Addr1 Addr0] | Branch to ADDR if SRC is 0 |
| Src0: 0 = ACC, 1 = LR |
There are four types of instructions: MOVE (00), BINARY (01), BRANCH (10), CONDITIONAL BRANCH (11). Move instructions copy data from the source location to the destination. Binary instructions execute some type of binary operation on the destination and source and store the result in the destination (note that shift/rotate are just really unary operations that shift/rotate the source by 1 bit). Branch instructions uncondtionally branch to the address given in the instruction. Conditional branch instructions go to the address in the instruction only if the source register is equal to zero.
Tasks
- Setup
Use the Quartus new project wizard to create a new directory and new Quartus project named pld2 (for Programmable Lights Display 2). There will be 3 VHDL files (and no BDF files) in the project.
- pld2.vhd: this is the file that implements the circuit shown in the lab page. It uses the pldrom as a component.
- pldrom.vhd: this is the file that holds the ROM
- pldbench.vhd: this is the testbench file that defines the inputs to pld2. You will download it.
- Create a ROM to hold the program
Create a simple read-only memory [ROM] using VHDL. You can use last week's ROM as a starting point. Call it pldrom.
The pldrom should take one input signal addr that should be a 4-bit std_logic_vector. It should have one output signal data that should be a 10-bit std_logic_vector.
The content of your ROM architecture should be a single conditional signal assignment. You will use the following for your first test (it tests branching and some of the other operations). Later, you will test with an additional program and then write two of your own program. The 10-bit values stored at each address location are the program.
data <= "0001100000" when addr = "0000" else -- move 0s to LR 00000000/00000000 "0001110000" when addr = "0001" else -- move 1s to LR 11111111/00000000 "0001101010" when addr = "0010" else -- move 1010 to LR 11111010/00000000 "0010101000" when addr = "0011" else -- move 8 to ACC 11111010/00001000 "0101001100" when addr = "0100" else -- shift LR left "0100011000" when addr = "0101" else -- add -1 to ACC "1100001000" when addr = "0110" else -- branch if zero "1000000100" when addr = "0111" else -- branch "0001110000" when addr = "1000" else -- set LR to 1s 11111111/00000000 "1000000000" when addr = "1001" else -- branch to zero 11111111/00000000 "0101010101" when addr = "1010" else -- garbage "1010101010" when addr = "1011" else -- garbage "1100110011" when addr = "1100" else -- garbage "0011001100" when addr = "1101" else -- garbage "0000000000" when addr = "1110" else -- garbage "1111111111"; -- garbageNote about file organization: The code here contains the first program you will use to test your programmable light display. When you write additional programs, it will be easiest to test them if they are also in a file/entity named pldrom. I have found the easiest way to change from program to program is to keep a separate file for each, then copy-paste whichever program you want to run into pldrom.vhd, recompile, and rerun the program.
- Start the main design
Make a new VHDL file. Name the entity pld2. You can use your VHDL code from the prior project as a starting point, if you wish (but you can also start over from scratch). Make the following quick modifications.
- Update the IR, ROMvalue, and pldrom component statement to use 10 bits for the instructions.
- The state_type will need three states: sFetch, sExecute1, and sExecute2.
- Add two new internal signals ACC and SRC that are 8 bit UNSIGNED type.
- Update the reset case so you are assigning 10 bits to the IR.
- Update the sFetch case so the next state is sExecute1.
- Delete all of the current code under state sExecute. Then set up cases for when sExecute1 and when sExecute2.
Note to board users: If you used the slowclock process, you should keep it in your code, because you will run this on the board.
- Define the Execute 1 actions
In state sExecute1, the move and binary operation instructions should assign the appropriate value to the SRC signal. The move instruction uses IR(5 downto 4) and the binary instruction uses IR(4 downto 3).
The two branch instructions should assign the appropriate value to the PC. In the case of the conditional branch, it should assign a new address to the PC only if the specified register (ACC or LR) is equal to 0.
- Define the Execute 2 actions
In state sExecute2 the move instruction should assign the correct bits of SRC to the correct destination as specified by IR(7 downto 6). Note that if the destination is the lower or upper 4 bits of the ACC, you should use the lower 4 bits of the source.
The binary instruction should assign to either the ACC or LR--depending upon IR(2)--the result of the specified binary operation as given in IR(7 downto 5).
The two branch instructions should do nothing in execute 2.
- Test the circuit
Test your system using this test bench file. Note that you may need to rename the circuit in the pldbench.vhd file to match your top level entity.
Note to board users: If you still are using a slowclock signal, assign slowclock <= clk; for the simulation. Then set it back when you run this on the board.
If you run the program listed above, you should get the output below. (Click on the image to make it bigger.)
ghdl -a pldbench.vhd pld2.vhd pldrom.vhd ghdl -e pldbench ghdl -r pldbench --vcd=pldbench.vcd gtkwave pldbench.vcd &
- Test the circuit again
Save your pldrom.vdh into another file, e.g. pldrom_test1.vhd so that you can use it again, if needed. Then, update pldrom.vhd's code to use this program, which tests each operator
data <= "0001110000" when addr = "0000" else -- move 11111111 to the LR "0011100000" when addr = "0001" else -- move 0000 from the IR to the high 4 bits of the ACC "0010100010" when addr = "0010" else -- move 0010 from the IR to the low 4 bits of the ACC "0100000100" when addr = "0011" else -- Add ACC to LR and put it back into the LR "0100000100" when addr = "0100" else -- Add ACC to LR and put it back into the LR "0100100100" when addr = "0101" else -- Subtract ACC from LR and put it back into the LR "0101001100" when addr = "0110" else -- Shift the LR left and write it back to the LR "0101101100" when addr = "0111" else -- Shift the LR right and write it back to the LR "0111101100" when addr = "1000" else -- Rotate the LR right and write it back to the LR "0101101100" when addr = "1001" else -- Shift the LR right and write it back to the LR "0110011100" when addr = "1010" else -- XOR the LR with all 1s and write it back to the LR (bit inversion) "0110110101" when addr = "1011" else -- AND the LR with 01 (sign-extended) "0100010110" when addr = "1100" else -- ADD the LR with 10 (sign-extended) "1111111111"; -- garbageIf you run the program listed above, you should get the output below. (Click on the image to make it bigger.)
ghdl -a pldbench.vhd pld2.vhd pldrom.vhd ghdl -e pldbench ghdl -r pldbench --vcd=pldbench.vcd gtkwave pldbench.vcd &
- Write a specific program
Write a program that loads 16 into the light register and has it count down to 0. Then it should flash between all 1s and all 0s 8 times and repeat from the beginning. For every instruction, be sure to include a comment indicating what that instruction does.
- Write one more program
Write one more program. It must include at least one branch instruction (don't use the one from the lab). In your report (instructions below), describe your goals for the program (what should it do?) and how it does it. For every instruction, be sure to include a comment indicating what that instruction does.
- Demonstrate both programs
For each of the two programs, make a movie demonstrating it in action. If you are using the board, program the board and take a movie. If you are not using the board, add a detailed explanation of your simulation output and how you can tell it is correct..
Extensions
- Make longer programs (make the ROM bigger).
- Write more programs.
- Write a simple assembler (in python, for example) that converts instructions from a simple, human readable language, into the set of machine instructions for your pldrom.
- If you are using the board, add a hold/freeze button to the display.
- If you are using the board, add one or more switches/buttons that let you speed up or slow down the clock.
- Add instructions to the instruction set. You can add variations on the branch instuctions without adding more bits to the instruction length by making use of their unused bits. For example, you could add branch conditions like > 0, < 0 or make comparisons between the values in the two registers.
- Be creative.
Report
Create a Word/Pages/etc document for your report. For each task, write a short description of the task, in your own words.
- Include a description (image or text) of your top-level design about how these different components work together.
- Include a gtkwave for each of the two given testing programs, showing that your circuit works correctly.
- Include a description of the two programs you wrote, talking about the goal of each program (what each program does), have a comment for each instruction indicating what that instruction does in your program (like the given testing programs), including a screenshot of each of your programs in the report.
- For each of the two programs you wrote, include a link to your moive to demonstrate it works (DE0 moive or Python simulation movie). You can either include the links to your moives (make sure you grant access to everyone who has the link) or indicate in your report that the moives are included in the submission folder and specify the movie name for each program.
- Indicate all your extensions. For each extension, include a description of the extension, how you achieve it, and testing results(movies or gtkwave) demonstrating it works.
- Include an Acknowledgements section in which you list any resources you con sulted. These could be on-line (movies or web pages) or people (peers, TA's, professors). This is your opportunity to celebrate the community you were able to plug into.
Please note that all these report requirements are reflected on your project 5 feedback spreadsheet. Remember to include all required elements in your report.
Handin
Put your vhd and write-up files in a folder called Project5_<username>, zip it up (so its name will be Project5_<username>), and upload the zip file to the Google classroom assignment for this project.
Spring 2026