Fall 2019

Project 6: Stack-based Calculator

The purpose of this project is to make use of RAM to implement a stack-based four function calculator. The concepts of stacks and the use of memory will lead into the next project where you design a complete CPU.

Overview

A stack-based calculator uses a stack to hold the operands of an operation. The user first enters and pushes the operands, then selects an operation to execute that makes use of the top two operands on the stack.

If you imagine a calculator and its display, we're going to use a register [MBR] to represent the display, which is also the currently active number. We'll also use the MBR as the top of the stack for the purpose of operations.

To control our calculator, we're going to use three buttons to execute actions, two switches to select the mathematical operation (+, -, *, /), and eight switches to specify values. Button 2 will be the Capture button and will write the current value from the switches to the MBR. Button 3 will be the Enter button and will push the MBR onto the stack. Button 4 will be the Action button and will execute the operation specified by the two operation switches, using the MBR and the first value on the stack, putting the result back in the MBR.

As an example, consider that we want to add 4 plus 5. We would do this in the following steps.

1. Set the value switches to the binary value for 4.
2. Click the Capture button to move 4 into the MBR. A 4 should now show up on the 7-segment display.
3. Click the Enter button to push 4 onto the stack.
4. Set the value switches to the binary value for 5.
5. Click the Capture button to move 5 into the MBR. A 5 should now show up on the 7-segment display.
6. Set the operation switches to 00 for ADD.
7. Click the Action button to add the MBR to the top value of the stack. The result, 9, should end up in the MBR and on the display.

The value of the MBR will always be echoed in the two seven segment displays.

1. Setup

Make a new project for lab 6 in a new folder. If you are going to use a 7-segment display to show the contents of memory, then copy over your VHDL 7-segment display driver in to the new folder. I'll refer to the project and top-level circuit as calculator.

2. Create a 16 x 8 bit RAM

Using the Tools:MegaWizard Plug0in Manager, create a RAM that has 16 words of 8 bits each. Therefore, it should have 4 address bits and 8 data bits. I'll refer to this circuit as memram in the file memram.vhd, This step will create a VHDL file that you will include in your project.

3. Define the calculator entity

Create a top-level VHDL file with an entity that has the same name as the project (e.g. calculator). You will need the following input and output signals for the entity's port statement.

 clock: in std_logic clock signal reset: in std_logic reset signal b2: in std_logic button 2, capture input b3: in std_logic button 3, Enter b4: in std_logic button 4, Action op: in std_logic_vector(1 downto 0) Action switches (2) data: in std_logic_vector(7 downto 0) Input data switches (8) digit0: out std_logic_vector(6 downto 0) Output values for 7-segment display digit1: out std_logic_vector(6 downto 0) Output values for 7-segment display stackview: out std_logic_vector(3 downto 0) Stack debugging

4. Construct the RAM component statement

Create a component statement for the RAM in the architecture header. Be sure to include the VHDL memram file created by the Wizard in your project.

5. Define the internal signals

Create the internal signals you will need to build the state machine and access the RAM. You will need signals for the RAM input, RAM write enable, RAM output, stack pointer, memory buffer register, and state. You will also likely need a temporary register for holding an operand removed from the stack.

6. Design and implement the calculator state machine

Plan out a state machine that will implement the calculator. You can use the lab circuit as a model. Include your state machine diagram as part of your wiki report.

Note: multiplication requires a destination that has twice as many bits as the operands. When executing multiplication you can either assign the result to a 16-bit temporary register and then truncate it to 8-bits or you can limit multiplication to the low four bits of the two operands.

7. Port map the RAM and 7-segment display circuits

Port map the RAM and the seven-segment displays. The seven-segment circuits should take in the low 4 and high 4 bits of the MBR, and their outputs should connect to the digit0 and digit1 output signals. Connect the stack pointer to the stackview output signal of your entity.

If you built your 7-segment display as a BDF diagram, use the "create/update" option and create the VHDL file for your 7-segement display circuit, which you can then port map into your main circuit.

8. Assign pins and test your circuit

Assign pins and test your circuit on the board. Take some videos of it in action for all of the different operations.

You can design your own GHDL testbench instead of, or in addition to testing on the board. This is a good extension if you do both.

Extensions

• Expand the number of arithmetic operations.
• Write a test bench program in VHDL that you can use to test your circuit with GHDL.
• Put in checks so your stack will never go over or under value.
• Try fixed-point math.
• Expand the size of the data to 12-bit registers. If you go to 16 bits, it will require more care when entering data.