Annotated view of MiniBit version 2 (December 2016)
Architecture Overview
I've been curious about computers and technology for as long as I can remember. When I started out, I was learning high level languages like LOGO and Java and most of the underlying mechanics were hidden from me. Recently, I started to get interested in low level system programming and assembly code and learned C and x86 assembly. I wanted to really understand how a computer could take x86 assembly and actually perform the instructions but I found that writing and assembling x86 on a modern processor was too complex to fully understand.
Then I got the idea to design and build my own RISC architecture. I had some experience with digital electronics and building small circuits to do things like add binary numbers but I had no idea how a CPU worked.
This is my second try at building a working cpu and I currently have a mostly functional prototype built on 13 breadboards. I've sketched out a full schematic in KiCad and I've also replicated the entire thing in System Verilog in order to simulate it at the logic gate level (this has been invaluable for debugging).
I wanted to use only simple integrated circuits in my design. Therefore, if I had the time and money I could theoretically build the entire thing out of discrete transistors.
At the current stage, there is no display and input is performed with a dip switch panel. I have plans to add I/O capabilities which could eventually be extended to work with a modified display or keyboard.
MiniBit is an 8-bit processor. Components are connected to an 8-bit data bus or a 2-bit control bus.
There are 8 registers of which 2 are general purpose. However only 4 are readable and only 4 are writeable therefore you only need 2 bits to identify registers in operands.
There are 23 unique instructions. Opcodes are either one or two bytes long depending on whether the operation takes an 8-bit immediate.
All instructions take 6 clock cycles to execute. The clock itself, can be incremented manually for debugging or set to run automatically. Speed is controlled with a potentiometer. I haven't yet tested the maximum processor speed.
Currently, RAM addresses are 8-bit and therefore there are 256 bytes of addressable memory. However, I have plans to expand to 16-bit addresses and therefore 64 KB of memory.
There is no ROM so all data is lost when powered off.
Here are a list of registers along with their function:
A
- general purpose register, can read/write to data bus, first operand for the ALU
B
- general purpose register, can read/write to data bus, second operand for the ALU
O
(output) - output of ALU operations, can write to data bus
FL
(flag) - written to by ALU operations, used in sequencer and ALU operation, stores the following bit flags:
CARRY
- set if an operation overflows
LT
(less than) - set if the most significant bit is set on output
NZ
(not zero) - set if output of ALU is not zero
IP
(instruction pointer) - holds the current instruction address, updated automatically by sequencer, writes to RAM address selector
M
(memory) - holds custom data address, can read from data bus, writes to RAM address selector
INT
(instruction) - holds currently executing instruction, set automatically in fetch-execute cycle, used as opcode reference
VAL
(value) - holds optional second byte of opcode, can write to data bus
For the registers that can be programmed to interact with the data bus, the following two bit identifiers are used in opcodes:
Write (reg -> bus) (aa
)
00
- A
01
- B
10
- O
11
- VAL
Read (bus -> reg) (bb
)
00
- A
01
- B
10
- IP
11
- M
The ALU performs basic, 8-bit arithmetic operations on either one or both A
and B
registers and stores the output in O
.
Additionally, it stores operation flags in FL
that can be used in further instructions.
For instance, it is possible to use the carry flag to perform arithmetic operations on values of any size.
All ALU opcodes are of the type 111xxxxx
and the lowest 5 bits are passed directly to the ALU as a secondary opcode.
The following operations are supported:
ADD
- (A + B)
CADD
- (A + B), use carry flag
SUB
- (A - B)
CSUB
- (A - B), use carry flag
INC
- (A + 1)
NAND
- (A NAND B)
BTL
- (A << 1)
CBTL
- (A << 1), use carry flag
BTR
- (A >> 1)
CBTR
- (A >> 1), use carry flag
The following instructions can be used to move data around:
Note: the symbols aa
and bb
represent the two bit register identifiers.
MOV aa, bb
- moves the contents of aa to bb
STORE aa
- stores the contents of aa in RAM at address M
FETCH bb
- fetches the contents of RAM at address M into bb
LOAD bb, [val]
(2 bytes) - loads an 8-bit value into bb
SAVE, [val]
(2 bytes) - saves an 8-bit value into RAM at address M
INCM
- increment the M register
DECM
- decrement the M register
DISP aa
- display contents of aa on the bus until control signal is recieved
READ bb
- read contents of bus into bb when control signal is recieved
HLT
- halt until control signal is recieved
JMP, [val]
(2 bytes) - unconditional jump to val
JLT, [val]
(2 bytes) - jump to val if LT flag is set
JNZ, [val]
(2 bytes) - jump to val if NZ flag is set
More info coming soon...