The idea for this project came about during a week of freezing winter arctic event here in Austin, Texas, with a failed power grid as well as government, while keeping close to a gas fireplace, the only source of heat and light, for a couple of days. With a weak internet over a phone data line, I could only do some preliminary searches and mainly work out various details on a writing pad, growing a feeling that the project may be personally exciting and practically doable.
I will try to post my progress over the coming weeks.
How do calculators work?
You press a few buttons, a function, and you get your result back. But what is the technology and the algorithms at work behind its computation? For sure we can read about that, but to fully internalize all the tradeoffs and corner cases, we need to embark on designing one. To create one from scratch, and by that, I mean it - not using emulators and pre-existing ROMs, or even a powerful microcontroller, will provide us with that innate knowledge. We should start with a blank drawing pad onto which we would sketch our design from the very first gate and build on top of it.
Let's dive in.
We will have to make certain implementation decisions, many of which are exclusive, each one with its own tradeoff.
Internal number representation
The number format internally used for computation:
- BCD (binary-coded decimal), where each nibble stores one decimal digit of mantissa and exponent
- More cumbersome operations on individual digits.
- Floating point representation
- Needs conversion to and from decimal values.
- Suffers from conversion errors.
The drawbacks of BCD are more complex routines and slightly lower compactness; the advantage is the perfect representation of decimal magnitudes, as opposed to pure binary, that cannot represent exactly some of them; also that there are very refined algorithms for both normal arithmetic and transcendental functions.
Digits of precision
How many digits of precision do we want to carry? Here we need to be very careful not to show more digits than we can compute exactly (with the exception of the last, rounding, digit). A calculator that displays incorrect values is much worse than one that displays only a few, but correct, digits.
- BCD may need internally wider registers to compute trailing, rounding digit, so it uses more digits for computation that it shows in the result (ex. HP41:10 digits, 13 internally; HP71: 12 digits, 15 internally)
- Binary (floating point) may be off when rounding certain values that can't be represented exactly in a decimal system. This notation may follow a standard like IEEE 754 or implement it’s own partitioning of mantissa and exponent values
A major decision to be made is whether to use one of many rounding modes or simply truncate the result. Each rounding mode has its share of advantages and drawbacks, or it’s suitable for a particular use (financial, scientific, etc.)
- RPN (Reverse Polish Notation)
- Does not have parenthesis, uses stack, computes intermediate values immediately.
- Does not have "=" key but have "push to stack" key (often called "ENTER")
- Quicker, less keystrokes.
- Algebraic (or infix notation)
- Uses parenthesis and knows about operator precedence.
- In practice, requires more cognitive effort.
- Have "(", ")" and "=" keys
Programmable vs. fixed function
- Programmable calculators have larger non-volatile storage where they store user input sequence (a program) and provide additional functions for execution control (value testing, looping,...)
- More sophisticated machines are more akin to full-blown computers and have a high-level language interpreter (like BASIC)
Gates vs Microcode
How much is done in hardware (in gates) vs. in microcode (ROM)? Here, by gates, I mean strictly specialized digital logic dedicated to computing arithmetic functions.
- Everything is done in gates (no ROM) (early, or very simple, calculators).
- Very minimal basic operations in gates; most functions is in code (ex. using HP's Saturn CPU).
- Most is done in gates, only the most complex functions in code.
- Everything is done in code, minimal necessary functionality in gates (ex. some Z80-based calculators).
What algorithms are used to compute higher-level functions?
- Taylor series
- Chebyshev polynomials
- Other series and algorithms
Keypad, or keyboard, is the primary interface to the user.
Arguably the best keypads are those made by HP for their line of calculators. They use double molded plastic and a proprietary spring system.
On the other end of the keyboard technology are super-cheap membrane keypads, such are those used in budget home computers by Sinclair and many $1 calculators from China.
A small step up is the membrane sheets pushed by extruded rubber/molded keyboard overlays. They provide more tactile feedback. They are very common since they are inexpensive and provide a good balance of price vs how they feel. Your TV remote controls, thermostats, and most of the appliances around would have those.
Occasionally, a frequently used button, after being pressed harder and harder, would stop working. That happened to our thermostat: two buttons setting up the temperature up and down stopped responding to our increasingly frustrating attempts to set the temperature. The remedy was to open the box and scratch the back of a rubber contact, a small graphite pad called “the contact pill”, with a soft black drawing pencil. Since the pencil leaves graphite marks, those contacts are now fully conducive and will continue working.
Since we cannot make plastic molds easily (perhaps they could be 3d printed, but I don’t have a 3d printer), the membrane-style keypad looks to be the most promising alternative for our calculator. We need to have lettering on the actual keys (numbers “0” through “9” and major functions like “+” and “-“), and also text for secondary functions accessed by some kind of a shift key, and those are normally expected to be shown next to the primary functions (above or below). We could print those on a regular piece of paper (printing using a laser color printer for nicely colored labels if we want to get fancy), and then laminate that sheet. The lamination would add extra stiffness to the paper.
There are two kinds of actuators we could use underneath.
The first one could be traditional PCB-mounted push buttons. Since those have a certain thickness, we would make another PCB sheet, acting as a spacer, with round holes where the buttons are, providing that clearance. If the clearance is not sufficient, we could raise that board up with some spacers.
As you press a spot on a laminated sheet, it would press a switch; the intermediate board would keep it all flat and level.
Another option would be to use small, tactile dome switches. Their use is rather uncommon among hobbyists. Those switches are made of tiny pieces of domed conductive material (sometimes gold plated) which bend as you press to make contact in the middle. They make a quite satisfying tactile “click”. The domes should not be soldered to the board since that would stiffen their elasticity and would make them prone to failure, so they are either physically held by some template or they are glued on top (frequently they are sold with an adhesive sheet).
Surprisingly, although these cost only a fraction of a cent to manufacture, US electronics shops like Mouser sell them for 50 cents each! If you shop from Alibaba (China), you can get a bag of 500 for $10. If you are making a large order, you should not pay more than 0.4 cents per button! I am sure there are quality differences, but we are not building a nuclear reactor control panel, either. It’s ok if they are not perfect.
A variation of those dome switches has a hole in the middle, where you can PCB mount an LED behind it and, for example, have it lit as you press a switch, or show a latched state.
Although I’ve never used those dome switches before, I just ordered a bag from China and am planning to give it a try with this project. I hope they will work as visualized.
There is another kind of “switches”, or better, a lack of them. With the advent of microcontrollers and their special purpose IO blocks, many now offer touch detection which does not need anything else besides access to an open trace. The controller registers even the slightest capacitive touch of a finger. Since we are not using one of those MCUs, we won’t pursue that idea here.
Modes of Operation
When we are already making our own calculator, being engineers, we should plan to support several different number bases. Besides decimal, we should also have hex and binary, and we may as well throw in octal. We could, of course, architect it to support any arbitrary base, but I don’t see any practical use for something like that.
We want to follow conventions and call these modes DEC (decimal), HEX, OCT, and BIN.
Any number currently on the screen can be converted amongst these bases. Non-whole decimal numbers will be truncated to integers.
Consequently, we need a few additional keys: besides the standard “0”…”9” we also need “A”, “B”, “C”, “D”, “E”, and “F”. We also need to assign 4 mode functions to keys.
We should also add a couple of bitwise operations to go with these modes. At the very least, basic AND, OR, XOR, NOR, and SHIFT (left or right) operations come to mind.
The heart of our calculator will be a small micro-sequencer implemented in FPGA. We will try to implement IO as discrete blocks to make our life easier.
For example, keypad scanning could be a separate and independent module that takes care of debouncing and simply queues key codes to an internal FIFO.
Similarly, the LCD driver could also be a separate module that initializes the display and implements some simple protocol to control writing the characters.
The exact details should be more obvious once we start writing a concrete architectural document.
In this first article, I tried to provide an overview of various options we can select from, trying not to decide anything in particular. Other major things are still being left out (like the power source) because we are still wrapping our heads around the complete project. As I was writing, some things did start to crystalize in terms of dependency (“if you decide to implement it this way, then you can’t do that”) and feasibility. Still, anything is on the table.
- HP Saturn processor: HP Saturn - Wikipedia
- Multi-cycle sequencer: Appendix D Mapping Control to Hardware (tufts.edu)
- The Spectrum ROM Disassembly (Uses Chebyshev polynomials for trig functions):www.primrosebank.net/computers/zxspectrum/docs/CompleteSpectrumROMDisassemblyThe.pdf
- How HP calculates CORDIC: www.jacques-laporte.org/TheSecretOfTheAlgorithms.htm
- How CORDIC works: Cordic for Dummies (jacques-laporte.org)
- HP35 on Arduino (with source): www.jacques-laporte.org/TheSecretOfTheAlgorithms.htm
- Calculator forensic: Calculator Forensics (rskey.org)
This set of articles explains how HP calculators calculate various functions: