# A pocket calculator on FPGA

``````One potato two potatoes
Three potatoes, four!
Five potatoes, six potatoes
Seven potatoes, more!
``````

As a follow up to one of my first FPGA projects Adventures in hardware, part 3 - display and a calculator I wanted to implement a more useful calculator that behaves like the common pocket calculators - you enter a number, choose an operator, enter another number, press another operator or = and see the result.

As my board only features three digit display, it will be slightly impractical and work on numbers from 0 to 999, but this time I wanted to operate it through a 4x4 keypad.

I’ve been stuck on how to properly read the keypad for quite some time - this was planned to be titled `Hardware Adventures 5`, not `9`, after all.

I had to relabel some keys with a surgical tape and a marker.

## The calculator architecture

The main calculator logic is implemented by a state machine with a few registers:

• `RESULT` holding the intermediate result
• `ARG` holding the currently
• `DISPLAY` holding whatever needs to be displayed on the LCD screen
• `OPERATOR` holding the previously entered operator (`+-*/`)

A simplified calculator state machine

Notes on state transitions and register updates:

• When a digit gets pressed, `ARG <= ARG * 10 + digit`
• When an operator gets pressed, `OPERATOR` becomes one of `+-*/`
• on `Calculate` state:
• `RESULT <= RESULT OPERATOR ARG`
• `OPERATOR <= OPERATOR_NEXT`
• `DISPLAY` register gets updated as required after states display_result and digit_pressed

### Required modules

To support the main state machine work we’ll need several other components:

• keypad poller to debounce the keys
• binary to bcd encoder to convert the internal binary representation for display
• seven segment encoder to encode a BCD digit to segments
• seven segment driver to multiplex the three decimal digits over the shared wires
• integer divider to implement division

In a 4x4 matrix keypad the key switches are connected by a grid of wires arranged in 4 columns and 4 rows. To determine what button is pressed, we need to scanning the crossings of the rows and columns by activating each column one at a time and read back the status of the rows. There are several articles that elaborate on this topic, if you’re interested.

Using this information we can write a module that encodes a set of 4-bit row and column pins into a hexadecimal keycode.

`````` 1 2 3 A
4 5 6 B
7 8 9 C
* 0 # D
``````

I decided to encode the * and # keys as 0xE and 0xF.

As I wanted to use this for a calculator, I’ve repurposed the C key for “Clear”, then applied a surgical tape to label the `+-*/` keys.

We also need to enable builtin pull-down resistors on the row pins in order to ensure a known state (logical zero) when a button is not pressed instead of a floating input.

## Entering multiple digits and displaying the number

Let’s represent the number internally as binary and just convert to the display using a BCD encoder.

The reading of the keys will be handled by the calculator state machine within its `state_read_digit` and `state_digit_pressed` states.

We can limit reading numbers larger than 999 by using a simple condition in the `state_digit_pressed` state:

``````if(reg_arg < 16'd100)
begin
reg_arg <= reg_arg * 10 + keypad_out;
end
``````

To display the `DISPLAY` register we initially convert the 10-digit number to BCD, then encode each digit (ones, tens, hundreds) into bits for the seven-segment display and finally multiplex them to the display.

A common algorithm for binary to BCD conversion is Double dabble and I’ve adapted a Verilog single-clock implementation into a 10-bit version .

Although I’ve found multiple descriptions for a single button debouncer, I didn’t understand how to do it over multiple possible columns that we scan and I attempted to insert some kind of debounce circuit running at a lower frequency after the keypad decoder, hoping it would settle on a decoded number - somehow it didn’t.

What finally helped was this assignment from a Tampere University that described the key poller and debouncer for the students. It describes an algorithm that probes the column successively, and for each column it waits for an input.

I could make the wait and hold times configurable, so it can be tuned to a specific keypad.

This is quite straightforward Verilog implementation, with nested `case` statements, that produces a 4-bit hex scancode for every row/column combination.

## The calculator state machine

Now we just need to implement the top module implementing the state machine mentioned earlier in the article and connecting all the other modules.

We can implement the basic operations using straightforward Verilog, which will get synthesized into adders and a hardware multiplier, therefore implementing the operations in a single clock cycle.

``````if(reg_operator == OP_PLUS) begin
reg_result <= reg_result + reg_arg;
state <= state_display_result;
end else if(reg_operator == OP_MINUS) begin
reg_result <= reg_result - reg_arg;
state <= state_display_result;
end else if(reg_operator == OP_MULTIPLY) begin
reg_result <= reg_result * reg_arg;
state <= state_display_result;
``````

### Division

My FPGA tools won’t synthesize the `/` operator, as a single-clock division by a variable number would be impractical to implement. I needed to implement a division module and wire it into the project.

The simplest algorithm of all is division by repeated subtraction :

``````while N = D do
N := N - D
Q := Q + 1
end
R := N
return (Q,R)
``````

This translates to a straightforward Verilog implementation .

#### Integrating the divider module

As the division will run for a various number of clocks, we need to signal the parent module somehow that the division is completed:

We assign the divider inputs, signal it to `start` and transition into a waiting state:

``````end else begin //OP_DIVIDE
divider_start <= 1'b1;
numerator <= reg_result;
denominator <= reg_arg;
state <= state_dividing;
end
``````

Then we continuously poll the `done` signal. If it’s asserted, we move over to the common display result state.

``````state_dividing:
begin
divider_start <= 1'b0;
if(divider_done)
begin
reg_result <= quotient;
state <= state_display_result;
end
end
``````

In the real world one would probably use Long division as it’s completes in much less clock cycles than a simplistic division by subtraction.

### Stupid errors I made along the way

• I forgot again to connect a top module input to a pin. This will produce a cryptic message in Xilinx ISE and took some time to hunt down.

• An earlier iteration of the keypad decoder couldn’t distinguish zero from a non-key press. I had to add `key_pressed` signal.

• Xilinx ISE doesn’t tell you when you make a typo in wire name, when you wire a module to something that doesn’t exist, for example `IO_P4_ROW` as `IO_DP4_ROW`.

• An earlier iteration of the keypad scanner used a clock that was driven by a counter. This is considered a very bad practice and can result in glitches , results in creating new clock domains (which I don’t really understand yet). The solution is to run the slow logic on the same (fast) clock as everything else, but use a slow enable signal or use a PLL circuitry for clock division.