Calcutron-33: A Decimal Based RISC Microprocessor
An imaginary CPU with a decimal number system instead of a binary number system to make teaching and learning how a CPU works easier.

I have talked about the Little Man Computer LMC before, which is a really simplified CPU intended for teaching children or beginners the principles of assembly programming.
The LMC microprocessor uses a decimal number system which simplifies teaching. You can explain the basics of assembly coding without also introducing the binary number system.
However LMC has a number of shortcomings. One of them is that implementing realistic multiplication and division is very hard.
The LMC is also has a very CISC like design. One can operate directly on memory cells to a large degree. RISC processors have a load/store architecture, which means operations are only carried out on the contents of CPU registers.
As an alternative I have come up with an imaginary RISC like CPU I call the Calcutron-33. I have made an assembler and simulator as a Julia package called Calcutron-33.jl. This is still very much work in progress. But here I would like to discuss a bit of the goals and inspiration.
While obviously inspired by LMC, I have also been inspired by reading about a far more realistic CPU instruction set, the RISC-V instruction set architecture (ISA). RISC-V has a number of goals which I don’t share, such all the important parts of a modern high performance RISC CPU, as well as designing and instruction set which can be used to make real CPUs. That is not my goal.
However RISC-V does have a number of interesting properties I have learned from. Most instructions follow a very standardized format, which I find very useful.
RISC-V also partitions the instruction set into extensions. So you can make RISC-V CPUs of different complexity and capability. It also simplifies teaching as you have a very basic but complete instruction set you can begin teaching.

Architecture
We try to keep many of the ideas of LMC. So the computer memory addresses are specified with two decimal digits. In principle that gives us 100 memory locations. However we will reserve the last 10 locations for Input and Output. Thus 0–89 are valid memory locations.
We will use one digit to specify register, which in principle gives us 10 registers. However the first register x0
will be treated as always zero. Hence we get registers from x1
to x9
which we can actually use.
Like a RISC CPU it has a load/store architecture. This means arithmetic operations and shift can only be done on registers. Only the store and load instructions can access memory. These are used to pull values into the registers.
Specification of Machine Code Format
- Every instruction is 4 decimal digits.
- The first digit is the opcode, which says what the instruction does such as add, subtract or load.
- The second digit is a register operand. Usually the destination register for whatever operation is performed.
- The last two digits will vary in meaning depending on opcode. For arithmetic operations, they will usually be two registers, used as input. The last one may be an immediate value from 0 to 9. For branches, store and load instructions , the last two digits will be a memory address.
Assembly Instruction Set
Here is description of the instruction set. It shows how each instruction is encoded as 4 decimal digits. E.g. for the first assembly code we have the encoding 1dst
. That means the first digit must be a 1 for this to be an add. The letters indicate digits one is free to chose. d
means the destination register rd
is a single digit. So it can be from 1-9. The two source registers s
and t
are one digit each as well.
Sometimes the instruction will set aside multiple digits for one argument such as in the case of the load instruction. Here 8daa
means the destination register rd
is specified with one digit, but the address aa
uses two digits.
- ADD rd, rs, rt
1dst
add registerrs
andrt
and store inrd
.rd ← rs + rt
- SUB rd, rs, rt
2dst
subtract registerrt
fromrs
and store inrd
.rd ← rs + rt
- SUBI rd, rs, k
3dsk
subtract valuek
from registerrs
and store in registerrd
.rd ← rs - k
- LSH rd, rs, k
4dsk
shift registerrs
leftk
digits and store inrd
- RSH rd, rs, k
5dsk
shift registerrs
rightk
digits and store inrd
- BRZ rd, aa
6daa
jump to addressaa
if registerrd
is zero. - BGT rd, aa
7daa
jump to addressaa
if registerrd
> 0 (positive). - LD rd, aa
8daa
load registerrd
with contents of memory at addressaa
. - ST rs, aa
9saa
store registerrs
in memory at addressaa
. - HLT
0000
stop program
Pseudo Assembly Instructions
This is a list of instructions which are just practical variations of the ones defined above. They are not new instructions per say. E.g. INP
is really just the same at the LD
instruction but applied to memory location 90.
MOV
is a move instruction accomplished by adding 0 to the source register and storing the result in the destination register. That has the practical outcome of causing a move.
- INP rd
8d90
load registerrd
with number from input. - OUT rs
9s91
store registerrs
to output. - MOV rd, rs
1d0s
moves content of registerrs
to registerrd
- CLR rd
1d00
clears content of registerrd
.rd ← 0
- DEC rd
3dd1
subtract 1 from registerrd
.rd ← rd + 1
. - BRA aa
60aa
jump to locationaa
in program.
Example Progams
Here is a simple program which fetches two numbers from the input and multiplies them, writing the result back to output.
INP x2 // first number to multiply. This will get added
INP x3 // second number. Treated as counter
CLR x1 // accumulator for result. Clear it out.
nextdigit:
RSH x4, x3, 1 // Push right most digit of x3 into x4
multiply:
ADD x1, x1, x2 // Add first input to accumulator
DEC x4 // Decrement counter for number of additions
BGT x4, multiply // Repeat while x4 > 0
LSH x2, x2, 1 // Left shift. x2 made 10x larger
BGT x3, nextdigit // check if all digits have been processed
OUT x1
This next story covers more code examples. The idea is to have a number of simple code examples useful to teach principles of assembly coding to beginners.
Final Remarks
This is really a form of thinking out aloud. I have not implemented this pretend CPU yet.