Tech News
← Back to articles

Show HN: E80: an 8-bit CPU in structural VHDL

read original related products more articles

E80 CPU

A simple CPU in VHDL, developed from scratch for my undergraduate thesis to provide all three characteristics of a Constructionist Microworld:

Low floor, as it depends purely on textbook-based, structural VHDL components, and offers a toolchain installer for one-click simulation.

High ceiling, as it supports all typical instructions found in Computer Architecture textbooks, including stack operations & subroutine calling.

Wide walls, as it was designed for compatibility with a variety of platforms, as seen below, and provides the complete source material (from the CFG grammar to EDA project files) for study and modification.

This makes it easy to use, capable of running pretty complex and realistic programs, and can be used in multiple lab or classroom scenarios.

Feature Description Dependencies ieee.std_logic_1164 (no arithmetic libraries) Execution Single-cycle Word Size 8-bit Buses 8-bit data, 8-bit address, 16-bit instruction Instruction size Variable (1 or 2 words) RAM Multiport (2R, 1R/W), addressable at 0x00-0xFE Register file Multiport (1R/W, 1R, 1W), 8x8-bit Registers 6 general purpose (R0-R5), Flags (R6), SP (R7) Stack Full descending (Stack Pointer init = 0xFF) Architecture Load/Store, register-register Addressing Immediate, direct, register, register-indirect Input 8-bit Memory Mapped at 0xFF (1x8 DIP switch) Output Flags, Registers, PC, Clock (3x8 LEDs) Assembly syntax Hybrid of ARM, x86, and textbook pseudocode Assembler ISO C99 (standard library, stdin I/O) Simulated on GHDL/GTKWave & ModelSim via one-click scripts Editor SciTE, with syntax coloring & one-click run Synthesized on Quartus Lite, Gowin Education, Vivado Standard Tested on Tang Primer 25K, Altera Cyclone IV

ISA cheatsheet

n : 8-bit immediate value or memory address. r,r1,r2 : 3-bit register address (R0 to R7), eg. MOV R3,R5 translates to 0b(00011000 0rrr0rrr) ≡ 0b(00011000 00110101) or 0x(18rr) ≡ 0x(1835). [x] : Memory at address x < 255, [255] = DIP input. PC : Program counter, initialized to 0 on reset. SP : Register R7, initialized to 255 on reset. --SP Decrease SP by 1, and then read it. SP++ Read SP, and then increase it by 1. Flags : Register R6 = [CZSVH---] (see ALU.vhd) C = Carry out (unsigned arithmetic) or shifted-out bit. Z = Zero, set to 1 when result is 0. S = Sign, set to the most significant bit of the result. V = Overflow (signed arithmetic), or sign bit flip in L/RSHIFT H = Halt flag, (freezes PC). +----------+----------+-------+---------------+-----------------------+-------+ | Instr1 | Instr2 | Hex | Mnemonic | Description | Flags | +----+----------+----------+-------+---------------+-----------------------+-------+ | 1 | 00000000 | | 00 | HLT | PC ← PC | H | | 2 | 00000001 | | 01 | NOP | | | | 3 | 00000010 | nnnnnnnn | 02 nn | JMP n | PC ← n | | | 4 | 00000011 | 00000rrr | 03 0r | JMP r | PC ← r | | | 5 | 00000100 | nnnnnnnn | 04 nn | JC n | if C=1, PC ← n | | | 6 | 00000101 | nnnnnnnn | 05 nn | JNC n | if C=0, PC ← n | | | 7 | 00000110 | nnnnnnnn | 06 nn | JZ n | if Z=1, PC ← n | | | 8 | 00000111 | nnnnnnnn | 07 nn | JNZ n | if Z=0, PC ← n | | | 9 | 00001010 | nnnnnnnn | 0A nn | JS n | if S=1, PC ← n | | | 10 | 00001011 | nnnnnnnn | 0B nn | JNS n | if S=0, PC ← n | | | 11 | 00001100 | nnnnnnnn | 0C nn | JV n | if V=1, PC ← n | | | 12 | 00001101 | nnnnnnnn | 0D nn | JNV n | if V=0, PC ← n | | | 13 | 00001110 | nnnnnnnn | 0E nn | CALL n | PC+2 → [--SP]; PC ← n | | | 14 | 00001111 | | 0F | RETURN | PC ← [SP++] | | | 15 | 00010rrr | nnnnnnnn | 1r nn | MOV r,n | r ← n | ZS | | 16 | 00011000 | 0rrr0rrr | 18 rr | MOV r1,r2 | r1 ← r2 | ZS | | 17 | 00100rrr | nnnnnnnn | 2r nn | ADD r,n | r ← r+n | CZSV | | 18 | 00101000 | 0rrr0rrr | 28 rr | ADD r1,r2 | r1 ← r1+r2 | CZSV | | 19 | 00110rrr | nnnnnnnn | 3r nn | SUB r,n | r ← r+(~n)+1 | CZSV | | 20 | 00111000 | 0rrr0rrr | 38 rr | SUB r1,r2 | r1 ← r1+(~r2)+1 | CZSV | | 21 | 01000rrr | nnnnnnnn | 4r nn | AND r,n | r ← r&n | ZS | | 22 | 01001000 | 0rrr0rrr | 48 rr | AND r1,r2 | r1 ← r1&r2 | ZS | | 23 | 01010rrr | nnnnnnnn | 5r nn | OR r,n | r ← r|n | ZS | | 24 | 01011000 | 0rrr0rrr | 58 rr | OR r1,r2 | r1 ← r1|r2 | ZS | | 25 | 01100rrr | nnnnnnnn | 6r nn | XOR r,n | r ← r^n | ZS | | 26 | 01101000 | 0rrr0rrr | 68 rr | XOR r1,r2 | r1 ← r1^r2 | ZS | | 27 | 01110rrr | nnnnnnnn | 7r nn | ROR r,n | r>>n (r<<8-n) | ZS | | 28 | 01111000 | 0rrr0rrr | 78 rr | ROR r1,r2 | r1>>r2 (r1<<8-r2) | ZS | | 29 | 10000rrr | nnnnnnnn | 8r nn | STORE r,[n] | r → [n] | | | 30 | 10001000 | 0rrr0rrr | 88 rr | STORE r1,[r2] | r1 → [r2] | | | 31 | 10010rrr | nnnnnnnn | 9r nn | LOAD r,[n] | r ← [n] | ZS | | 32 | 10011000 | 0rrr0rrr | 98 rr | LOAD r1,[r2] | r1 ← [r2] | ZS | | 33 | 10100rrr | | Ar | LSHIFT r | (C,r)<<1; V ← S flip | CZSV | | 34 | 10110rrr | nnnnnnnn | Br nn | CMP r,n | SUB, discard result | CZSV | | 35 | 10111000 | 0rrr0rrr | B8 rr | CMP r1,r2 | SUB, discard result | CZSV | | 36 | 11000rrr | nnnnnnnn | Cr nn | BIT r,n | AND, discard result | ZS | | 37 | 11010rrr | | Dr | RSHIFT r | (r,C)>>1; V ← S flip | CZSV | | 38 | 11100rrr | | Er | PUSH r | r → [--SP] | | | 39 | 11110rrr | | Fr | POP r | r ← [SP++] | | +----+----------+----------+-------+---------------+-----------------------+-------+

Notes

... continue reading