├── .editorconfig ├── .gitignore ├── README.md ├── computer_8bits.circ ├── images ├── 7-segments_display.png ├── SRAM_16-bytes.png ├── SRAM_256-bytes.png ├── address_decoder_4-bits.png ├── alu_8-bits.png ├── counter_8-bits.png ├── counting.gif ├── data_bus.png ├── decoder_8-bits_to_7-segments.png ├── full_adder.png ├── hand_button.png ├── instruction_decoder.png ├── processor.png ├── processor_social_img.png ├── programming_mode_selector.png ├── programming_mode_selector_on.png ├── register_8-bits.png └── reset_button.png ├── logisim-evolution-2.15.0-all.jar ├── programs ├── counter_up_down.asm ├── counter_up_down.raw ├── fibonacci.asm ├── fibonacci.raw ├── multiplication.asm └── multiplication.raw ├── roms ├── cpu_microcode.rom └── display_7_digits_decoder.rom ├── scripts ├── generate_8-bits_7-segments_hex_decoder.py ├── generate_cpu_microcode.py └── save_rom.py └── start.sh /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 4 6 | insert_final_newline = true 7 | trim_trailing_whitespace = true 8 | end_of_line = lf 9 | charset = utf-8 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | scripts/*.rom 2 | .vscode 3 | __pycache__ 4 | coverage -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Basic 8-bits computer simulation 2 | 3 | A basic 8-bits computer created with [LogiSim](http://www.cburch.com/logisim/pt/index.html) digital circuit simulator :computer:. 4 | 5 | - [Basic 8-bits computer simulation](#Basic-8-bits-computer-simulation) 6 | - [Project goal](#Project-goal) 7 | - [Acknowledgments](#Acknowledgments) 8 | - [The microcode / instruction set](#The-microcode--instruction-set) 9 | - [Instructions](#Instructions) 10 | - [Program examples](#Program-examples) 11 | - [How to load and run a program](#How-to-load-and-run-a-program) 12 | - [Multiplication](#Multiplication) 13 | - [Fibonacci](#Fibonacci) 14 | - [Circuits](#Circuits) 15 | - [The BUS](#The-BUS) 16 | - [The full adder](#The-full-adder) 17 | - [The 8-bits Arithmetic and Logic Unit (ALU)](#The-8-bits-Arithmetic-and-Logic-Unit-ALU) 18 | - [The 4-bits address decoder](#The-4-bits-address-decoder) 19 | - [The 8-bits registers](#The-8-bits-registers) 20 | - [The RAM](#The-RAM) 21 | - [The DRAM and SRAM](#The-DRAM-and-SRAM) 22 | - [The 16 bytes SRAM](#The-16-bytes-SRAM) 23 | - [The 256 bytes SRAM](#The-256-bytes-SRAM) 24 | - [The program counter (PC)](#The-program-counter-PC) 25 | - [The instruction decoder](#The-instruction-decoder) 26 | - [The 8-bits to 7-segments decoder](#The-8-bits-to-7-segments-decoder) 27 | 28 | ## Project goal 29 | 30 | This project goal is to build a basic 8-bits computer with a functional 8-bits processor using a digital circuit simulator (LogiSim). 31 | 32 | For future versions I will expand the circuits modules and functionalities creating a more complex processor, but for now, I'm trying to keep the circuits as simple as possible. 33 | 34 | This processor project is not focused on performance, instead I prioritized the simplicity creating circuits easy to understand. 35 | 36 | `Note`: There are two processor versions. The first one committed on the `master` branch that uses the DRAM memory created by me with registers and logic ports and the second one committed on the `logisim-native-ram` branch using the Logisim memory RAM component. 37 | 38 | ## Acknowledgments 39 | 40 | `Ben Eater` and his [YouTube channel](https://www.youtube.com/user/eaterbc) with great videos explaining about a processor architecture. 41 | 42 | ## The microcode / instruction set 43 | 44 | The *instruction set* is the basic list of instructions provided by the processor telling it what it needs to execute. This processor uses CISC (Complex Instruction Set Computers) instructions instead the more simple RISC (Reduced Instruction Set Computer) instructions. 45 | 46 | The script [generate_cpu_microcode.py](scripts/generate_cpu_microcode.py) generates the ROM content to be load in the instruction decoder circuit. 47 | 48 | ## Instructions 49 | 50 | | Instruction | OpCode | Description | 51 | | ----------- |:------: | ---------------- | 52 | | NOP | 0x00 | No operation. Fetches the next operation. | 53 | | HALT | 0x01 | Stops the computer clock. | 54 | | LDA NUM | 0x02 | Loads register A with the given value. | 55 | | LDA [ADDR] | 0x03 | Loads register A with the value stored in the given memory address. | 56 | | STA [ADDR] | 0x04 | Stores the register A value in the given memory address. | 57 | | LDB NUM | 0x05 | Loads register B with the given value. | 58 | | LDB [ADDR] | 0x06 | Loads register B with the value stored in the given memory address. | 59 | | STB [ADDR] | 0x07 | Stores the register B value in the given memory address. | 60 | | ADD NUM | 0x08 | Adds the given value with the value stored in register A and stores the sum result in register A. The given number will be stored in register B. | 61 | | ADD [ADDR] | 0x09 | Adds the value stored in the given memory address with the value stored in register A. Stores the sum result in register A. | 62 | | SUB NUM | 0x0A | Subtracts the given value with the value stored in register A and stores the subtraction result in register A. The given number will be stored in register B. | 63 | | SUB [ADDR] | 0x0B | Subtracts the value stored in the given memory address with the value stored in register A. Stores the subtraction result in register A. | 64 | | OUTA | 0x0C | Sets the Output register with the register A value. | 65 | | OUTB | 0x0D | Sets the Output register with the register B value. | 66 | | OUT NUM | 0x0E | Sets the Output register with the given value. | 67 | | OUT [ADDR] | 0x0F | Sets the Output register with the value stored in the given memory address. | 68 | | JP [ADDR] | 0x10 | Jumps to the given address. | 69 | | JPZ [ADDR] | 0x11 | Jumps to the given address if the zero flag is 1. | 70 | | JPC [ADDR] | 0x12 | Jumps to the given address if the carry flag is 1. | 71 | 72 | The spreadsheet [Instruction set](https://docs.google.com/spreadsheets/d/1Fneg8PanTtMlRC4RZEkOpCdoTKiEzFjZNxuiX3XXzDU/edit#gid=0) shows the instructions steps and control flags. 73 | 74 | ## Program examples 75 | 76 | ### How to load and run a program 77 | 78 | `Create your program:` 79 | 80 | 1. Write a program using the processor instructions. 81 | 2. Convert it to binary and save it using the format like the [multiplication.bin](programs/multiplication.raw) file (I didn't finish the compiler development yet :grimacing:). 82 | 3. Open the processor_8-bits.circ using LogiSim Evolution simulator. 83 | 84 | `Instructions for the master branch version:` 85 | 86 | 1. Click with the mouse right button on the Program ROM and click on Load image... 87 | 2. Choose you program raw file loading it in the Program ROM. 88 | 3. Click on the ![The hand button](images/hand_button.png) button. 89 | 4. Enable the programming mode clicking on ![The programming selector](images/programming_mode_selector.png) 90 | 5. Using the `Simulate` menu start the clock selecting the `Ticks Enable` menu entry. 91 | 6. Wait until all your program code is loaded to the RAM. You can track the program loading through the gray box shown inside the Program ROM. 92 | 7. Disable the programming mode clicking on ![The programming selector](images/programming_mode_selector_on.png). 93 | 8. Click on the ![The reset button](images/reset_button.png) button. 94 | 9. Now watch the magic happening :stuck_out_tongue_winking_eye:. 95 | 96 | `Instructions for the logisim-native-ram branch version:` 97 | 98 | 1. Click with the mouse right button on the RAM and click on Load image... 99 | 2. Choose you program raw file loading it in the RAM. 100 | 3. Click on the ![The hand button](images/hand_button.png) button. 101 | 4. Click on the ![The reset button](images/reset_button.png) button. 102 | 5. Using the `Simulate` menu start the clock selecting the `Ticks Enable` menu entry. 103 | 6. Now watch the magic happening :stuck_out_tongue_winking_eye:. 104 | 105 | ### Multiplication 106 | 107 | ```nasm 108 | INITIALIZATION: 109 | 0x00 LDA 4 # Initializes the factor loading it in register A. 110 | 0x02 STA [FACTOR] # Stores register A in the factor memory address. 111 | 0x04 OUTA # Output the factor. 112 | 113 | 0x05 LDA 0 # Initializes the result loading it in register A. 114 | 0x07 STA [RESULT] # Stores register A in the result memory address. 115 | 116 | 0x09 LDA 3 # Initializes the multiplicand loading it in register A. 117 | 0x0B STA [MULT] # Stores register A in the multiplicand memory address. 118 | 0x0D OUTA # Output the multiplicand. 119 | 120 | START: # 0x0E 121 | 0x0E JPZ [END] # If multiplicand equals zero goes to the end. 122 | 123 | 0x10 LDA [RESULT] # Loads the factor in register A. 124 | 0x12 ADD [FACTOR] # Adds the factor. 125 | 0x14 STA [RESULT] # Stores the result of adition in result. 126 | 127 | 0x16 LDA [MULT] # Loads the multiplicand in register A. 128 | 0x18 SUB 1 # Decrement the multiplicand. 129 | 0x1C STA [MULT] # Stores the multiplicand. 130 | 131 | 0x1E JP [START] # Jumps to start. 132 | 133 | END: # 0x20 134 | 0x20 OUT [RESULT] # Output the result. 135 | 0x22 HALT # Halts the program. 136 | 137 | # VARIABLES: 138 | # 0x23 FACTOR 139 | # 0x24 MULT 140 | # 0X25 RESULT 141 | ``` 142 | 143 | Binary representation: 144 | 145 | [multiplication.raw](programs/multiplication.raw) 146 | 147 | ### Fibonacci 148 | 149 | ```nasm 150 | INIT: # 0x00 151 | 0x00 LDA 0 # Initializes the number 1 loading it in register A. 152 | 0x02 STA [NUM1] # Stores register A in the number 1 memory address. 153 | 0x04 OUT [NUM1] # Output the number 1. 154 | 155 | 0x06 LDA 1 # Initializes the number 2 loading it in register A. 156 | 0x08 STA [NUM2] # Stores register A in the number 2 memory address. 157 | 158 | START: # 0x0A 159 | 0x0A OUT [NUM2] # Output the number 2. 160 | 0x0C LDA [NUM1] # Loads the number 1 in register A. 161 | 0x0E ADD [NUM2] # Adds the number 2. 162 | 0x10 STB [NUM1] # Stores number 2 in number 1. 163 | 0x12 STA [NUM2] # Stores the sum of number 1 and 2 in number 2. 164 | 165 | 0x14 JPC [INIT] # Jump on carry (restart). 166 | 0x16 JP [START] # Jumps to start. 167 | 168 | # VARIABLES: 169 | # 0x18 NUM1 170 | # 0x19 NUM2 171 | ``` 172 | 173 | Binary representation: 174 | 175 | [fibonacci.raw](programs/fibonacci.raw) 176 | 177 | 178 | ## Circuits 179 | 180 | ### The BUS 181 | 182 | The BUS is used to connect all processor modules allowing the components to communicate with each other. 183 | 184 | Normally there is more than 1 bus in a processor, like the data BUS, address BUS, control BUS, etc. For the first processor version I'm using only 2 BUS, one for data and one for control. 185 | 186 | The data bus: 187 | 188 | ![The data bus](images/data_bus.png) 189 | 190 | ### The full adder 191 | 192 | This is the circuit responsible for sum two numbers. It's a important ALU piece. 193 | 194 | ![The full adder](images/full_adder.png) 195 | 196 | ### The 8-bits Arithmetic and Logic Unit (ALU) 197 | 198 | The ALU executes the arithmetic (sum, subtract, multiplication, division) and logic (and, or, xor, not, comparison) operations inside the processor. In my processor, the ALU is directly connected to the registers A and B to use them as source to perform the operations. 199 | 200 | For this first processor version, I will only implement the sum and subtraction operations, reserving the other operations for a future version. 201 | 202 | ![The ALU](images/alu_8-bits.png) 203 | 204 | ### The 4-bits address decoder 205 | 206 | The address decoder is responsible for decode one binary address to a binary signal (1-bit). For each address the circuit will activated one different output. 207 | 208 | This circuit decodes each of the 4-bits address to a different output signal in a total of 16 outputs. 209 | 210 | ![The 4-bits address decoder](images/address_decoder_4-bits.png) 211 | 212 | ### The 8-bits registers 213 | 214 | A register is a processor piece that is responsible for storing information. In our case, the 8-bits register will store an 8-bits number. 215 | 216 | The register works using a D flip-flop for store a bit. Each 8-bits register uses 8 D flip-flop for store a byte (8-bits). 217 | 218 | This processor will use 6 registers: 219 | 220 | 1) Program counter register (PC) 221 | 2) Register A connected to the ALU 222 | 3) Register B connected to the ALU 223 | 4) Instruction register 224 | 5) Memory address register 225 | 6) Output register 226 | 227 | The RAM memory used in this computer also uses the 8-bits registry. 228 | 229 | This is the internal 8-bits register circuit: 230 | 231 | ![The 8-bits register circuit](images/register_8-bits.png) 232 | 233 | ### The RAM 234 | 235 | The RAM (Random Access Memory) is responsible for store values with 8-bits each (word size). This values will include the program binary and the program variables. 236 | 237 | #### The DRAM and SRAM 238 | 239 | There are different types of RAM. Dynamic RAM (DRAM) and Static RAM (SRAM) are usually found in our computers. 240 | 241 | DRAM is a memory based on capacitors, with less components compared with the SRAM memory, but with the necessity to refresh the capacitors many times per second for avoid data loss. 242 | 243 | SRAM is based on D flip-flop registers generating a more complex circuit to store a bit, but with no refresh circuits. 244 | 245 | This project is using SRAM memory type for the RAM circuit. 246 | 247 | #### The 16 bytes SRAM 248 | 249 | The 16 bytes SRAM uses 16 registers to store 1 byte each and a 4-bits length address to access the memory data. 250 | 251 | ![The 16 bytes SRAM](images/SRAM_16-bytes.png) 252 | 253 | #### The 256 bytes SRAM 254 | 255 | This computer uses a 256 bytes SRAM memory composed by 16 SRAM modules with 16 bytes each (16 x 16 bytes = 256 bytes). 256 | 257 | The image below is the 256 bytes SRAM memory circuit. For only 256 bytes we have this crazy complexity, remembering that each one of the 16 SRAM shown in the circuit is a [16 bytes SRAM](#the-16-bytes-sram), imagine a 16GB RAM memory! Wow! :flushed: 258 | 259 | ![The 256 bytes SRAM](images/SRAM_256-bytes.png) 260 | 261 | ### The program counter (PC) 262 | 263 | The program counter is a special register responsible for storing the address of the next instruction that will be processed when the current instruction processing finishes. This circuit is basically a binary counter that allows not only increment the counter value, but also to change the current value for a new one. This capability is used to create jump instructions. 264 | 265 | ![The Program counter](images/counter_8-bits.png) 266 | 267 | ### The instruction decoder 268 | 269 | This circuit is responsible for fetching instructions from the RAM, decoding it and changing the control flags in order for the processor to execute the instructions. The [Instruction set](#The-microcode--instruction-set) describes all instructions the decoder knows and which flags are enabled for each step during the instruction execution. 270 | 271 | This is the microcode used to decode the instructions: [cpu_microcode.rom](roms/cpu_microcode.rom) 272 | 273 | The microcode is generated by [generate_cpu_microcode.py](scripts/generate_cpu_microcode.py) script. 274 | 275 | ![The instruction decoder](images/instruction_decoder.png) 276 | 277 | ### The 8-bits to 7-segments decoder 278 | 279 | This circuit decodes a 8-bits number showing it in a base 10 number into a set of 3 7-segment displays. 280 | 281 | The 7-segments display uses segments from A to G plus decimal point segment to represent a number. 282 | 283 | ![7-segments display](images/7-segments_display.png) 284 | 285 | There are several ways to decode a number to show it into a 7-segment display. My approach was to use a ROM with the decoding codes. Using a 21-bits word (7-bits for which display) I constructed all decoding codes possibilities to show a number from 0 to 255 (8-bits). 286 | 287 | I created the script [generate_8-bits_7-segments_hex_decoder.py](https://github.com/leonicolas/computer-8bits/blob/master/scripts/generate_8-bits_7-segments_hex_decoder.py) to help me generate the entire ROM content. 288 | 289 | As an example, the code below decodes the number *123* from it 8-bits representation to the 7-segments format. 290 | 291 | | ROM address | Hundreds Segment | Tens Segment | Ones Segment | Hex | 292 | |:---------------:|:----------------:|:----------------:|:----------------:|:--------:| 293 | | Segments => | g f e d c b a | g f e d c b a | g f e d c b a | | 294 | | 123 = 0111 1011 | 0 0 0 0 1 1 0 | 1 0 1 1 0 1 1 | 1 0 0 1 1 1 1 | 0x01adcf | 295 | -------------------------------------------------------------------------------- /images/7-segments_display.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leonicolas/computer-8bits/08d8571bb7cc403a7e91e3b08dc2491943a90a6b/images/7-segments_display.png -------------------------------------------------------------------------------- /images/SRAM_16-bytes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leonicolas/computer-8bits/08d8571bb7cc403a7e91e3b08dc2491943a90a6b/images/SRAM_16-bytes.png -------------------------------------------------------------------------------- /images/SRAM_256-bytes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leonicolas/computer-8bits/08d8571bb7cc403a7e91e3b08dc2491943a90a6b/images/SRAM_256-bytes.png -------------------------------------------------------------------------------- /images/address_decoder_4-bits.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leonicolas/computer-8bits/08d8571bb7cc403a7e91e3b08dc2491943a90a6b/images/address_decoder_4-bits.png -------------------------------------------------------------------------------- /images/alu_8-bits.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leonicolas/computer-8bits/08d8571bb7cc403a7e91e3b08dc2491943a90a6b/images/alu_8-bits.png -------------------------------------------------------------------------------- /images/counter_8-bits.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leonicolas/computer-8bits/08d8571bb7cc403a7e91e3b08dc2491943a90a6b/images/counter_8-bits.png -------------------------------------------------------------------------------- /images/counting.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leonicolas/computer-8bits/08d8571bb7cc403a7e91e3b08dc2491943a90a6b/images/counting.gif -------------------------------------------------------------------------------- /images/data_bus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leonicolas/computer-8bits/08d8571bb7cc403a7e91e3b08dc2491943a90a6b/images/data_bus.png -------------------------------------------------------------------------------- /images/decoder_8-bits_to_7-segments.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leonicolas/computer-8bits/08d8571bb7cc403a7e91e3b08dc2491943a90a6b/images/decoder_8-bits_to_7-segments.png -------------------------------------------------------------------------------- /images/full_adder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leonicolas/computer-8bits/08d8571bb7cc403a7e91e3b08dc2491943a90a6b/images/full_adder.png -------------------------------------------------------------------------------- /images/hand_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leonicolas/computer-8bits/08d8571bb7cc403a7e91e3b08dc2491943a90a6b/images/hand_button.png -------------------------------------------------------------------------------- /images/instruction_decoder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leonicolas/computer-8bits/08d8571bb7cc403a7e91e3b08dc2491943a90a6b/images/instruction_decoder.png -------------------------------------------------------------------------------- /images/processor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leonicolas/computer-8bits/08d8571bb7cc403a7e91e3b08dc2491943a90a6b/images/processor.png -------------------------------------------------------------------------------- /images/processor_social_img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leonicolas/computer-8bits/08d8571bb7cc403a7e91e3b08dc2491943a90a6b/images/processor_social_img.png -------------------------------------------------------------------------------- /images/programming_mode_selector.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leonicolas/computer-8bits/08d8571bb7cc403a7e91e3b08dc2491943a90a6b/images/programming_mode_selector.png -------------------------------------------------------------------------------- /images/programming_mode_selector_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leonicolas/computer-8bits/08d8571bb7cc403a7e91e3b08dc2491943a90a6b/images/programming_mode_selector_on.png -------------------------------------------------------------------------------- /images/register_8-bits.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leonicolas/computer-8bits/08d8571bb7cc403a7e91e3b08dc2491943a90a6b/images/register_8-bits.png -------------------------------------------------------------------------------- /images/reset_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leonicolas/computer-8bits/08d8571bb7cc403a7e91e3b08dc2491943a90a6b/images/reset_button.png -------------------------------------------------------------------------------- /logisim-evolution-2.15.0-all.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leonicolas/computer-8bits/08d8571bb7cc403a7e91e3b08dc2491943a90a6b/logisim-evolution-2.15.0-all.jar -------------------------------------------------------------------------------- /programs/counter_up_down.asm: -------------------------------------------------------------------------------- 1 | INITIALIZATION: 2 | 0x04 LDA 0 # Initializes the counter with 0. 3 | 4 | START: # 0x08 5 | 0x08 OUTA 6 | 0x09 ADD [FACTOR] 7 | 0x00 JPZ [UP_DOWN_CONDITION] 8 | 0x0B JP [START] 9 | 10 | UP_DOWN_CONDITION: 11 | 0x00 JPC [SUB_FACTOR] 12 | 0x00 JP [ADD_FACTOR] 13 | 14 | ADD_FACTOR: 15 | 0x00 LDA 1 # Initializes the counter factor with 1. 16 | 0x02 STA [FACTOR] # Stores register A in the counter factor memory address. 17 | 0x00 JP [START] 18 | 19 | SUB_FACTOR: 20 | 0x00 LDA FE # Initializes the counter factor with -1. 21 | 0x02 STA [FACTOR] # Stores register A in the counter factor memory address. 22 | 0x00 JP [START] 23 | 24 | VARIABLES: 25 | # 0x25 FACTOR 26 | # 0X26 COUNTER 27 | -------------------------------------------------------------------------------- /programs/counter_up_down.raw: -------------------------------------------------------------------------------- 1 | v2.0 raw 2 | 02 FE 3 | 04 25 4 | 02 FF 5 | 08 01 6 | 7 | 0C 8 | 09 25 9 | 10 08 10 | -------------------------------------------------------------------------------- /programs/fibonacci.asm: -------------------------------------------------------------------------------- 1 | INIT: # 0x00 2 | 0x00 LDA 0 # Initializes the number 1 loading it in register A. 3 | 0x02 STA [NUM1] # Stores register A in the number 1 memory address. 4 | 0x04 OUT [NUM1] # Output the number 1. 5 | 6 | 0x06 LDA 1 # Initializes the number 2 loading it in register A. 7 | 0x08 STA [NUM2] # Stores register A in the number 2 memory address. 8 | 9 | START: # 0x0A 10 | 0x0A OUT [NUM2] # Output the number 2. 11 | 0x0C LDA [NUM1] # Loads the number 1 in register A. 12 | 0x0E ADD [NUM2] # Adds the number 2. 13 | 0x10 STB [NUM1] # Stores number 2 in number 1. 14 | 0x12 STA [NUM2] # Stores the sum of number 1 and 2 in number 2. 15 | 16 | 0x14 JPC [INIT] # Jump on carry (restart). 17 | 0x16 JP [START] # Jumps to start. 18 | 19 | # VARIABLES: 20 | # 0x18 NUM1 21 | # 0x19 NUM2 22 | -------------------------------------------------------------------------------- /programs/fibonacci.raw: -------------------------------------------------------------------------------- 1 | v2.0 raw 2 | 02 00 3 | 04 18 4 | 0F 18 5 | 6 | 02 01 7 | 04 19 8 | 9 | 10 | 0F 19 11 | 03 18 12 | 09 19 13 | 07 18 14 | 04 19 15 | 16 | 12 00 17 | 10 0A 18 | -------------------------------------------------------------------------------- /programs/multiplication.asm: -------------------------------------------------------------------------------- 1 | INITIALIZATION: 2 | 0x00 LDA 4 # Initializes the factor loading it in register A. 3 | 0x02 STA [FACTOR] # Stores register A in the factor memory address. 4 | 0x04 OUTA # Output the factor. 5 | 6 | 0x05 LDA 3 # Initializes the multiplicand loading it in register A. 7 | 0x07 STA [MULT] # Stores register A in the multiplicand memory address. 8 | 0x09 OUTA # Output the multiplicand. 9 | 10 | 0x0A LDA 0 # Initializes the result loading it in register A. 11 | 0x0C STA [RESULT] # Stores register A in the result memory address. 12 | 13 | START: # 0x0E 14 | 0x0E JPZ [END] # If multiplicand equals zero goes to the end. 15 | 16 | 0x10 LDA [RESULT] # Loads the factor in register A. 17 | 0x12 ADD [FACTOR] # Adds the factor. 18 | 0x14 STA [RESULT] # Stores the result of adition in result. 19 | 20 | 0x16 LDA [MULT] # Loads the multiplicand in register A. 21 | 0x18 SUB 1 # Decrement the multiplicand. 22 | 0x1C STA [MULT] # Stores the multiplicand. 23 | 24 | 0x1E JP [START] # Jumps to start. 25 | 26 | END: # 0x20 27 | 0x20 OUT [RESULT] # Output the result. 28 | 0x22 HALT # Halts the program. 29 | 30 | # VARIABLES: 31 | # 0x23 FACTOR 32 | # 0x24 MULT 33 | # 0X25 RESULT 34 | -------------------------------------------------------------------------------- /programs/multiplication.raw: -------------------------------------------------------------------------------- 1 | v2.0 raw 2 | 02 04 04 23 0C 02 03 04 3 | 24 0C 02 00 04 25 11 20 4 | 03 25 09 23 04 25 03 24 5 | 0A 01 11 20 04 24 10 10 6 | 0F 25 01 7 | -------------------------------------------------------------------------------- /roms/cpu_microcode.rom: -------------------------------------------------------------------------------- 1 | v2.0 raw 2 | 00104 00068 00010 00000 00000 00000 00000 00000 3 | 00104 00068 00010 00000 00000 00000 00000 00000 4 | 00104 00068 00010 00000 00000 00000 00000 00000 5 | 00104 00068 00010 00000 00000 00000 00000 00000 6 | 00104 00068 08000 00010 00000 00000 00000 00000 7 | 00104 00068 08000 00010 00000 00000 00000 00000 8 | 00104 00068 08000 00010 00000 00000 00000 00000 9 | 00104 00068 08000 00010 00000 00000 00000 00000 10 | 00104 00068 0010c 04040 00010 00000 00000 00000 11 | 00104 00068 0010c 04040 00010 00000 00000 00000 12 | 00104 00068 0010c 04040 00010 00000 00000 00000 13 | 00104 00068 0010c 04040 00010 00000 00000 00000 14 | 00104 00068 0010c 00140 04040 00010 00000 00000 15 | 00104 00068 0010c 00140 04040 00010 00000 00000 16 | 00104 00068 0010c 00140 04040 00010 00000 00000 17 | 00104 00068 0010c 00140 04040 00010 00000 00000 18 | 00104 00068 0010c 00140 02080 00010 00000 00000 19 | 00104 00068 0010c 00140 02080 00010 00000 00000 20 | 00104 00068 0010c 00140 02080 00010 00000 00000 21 | 00104 00068 0010c 00140 02080 00010 00000 00000 22 | 00104 00068 0010c 00440 00010 00000 00000 00000 23 | 00104 00068 0010c 00440 00010 00000 00000 00000 24 | 00104 00068 0010c 00440 00010 00000 00000 00000 25 | 00104 00068 0010c 00440 00010 00000 00000 00000 26 | 00104 00068 0010c 00140 00440 00010 00000 00000 27 | 00104 00068 0010c 00140 00440 00010 00000 00000 28 | 00104 00068 0010c 00140 00440 00010 00000 00000 29 | 00104 00068 0010c 00140 00440 00010 00000 00000 30 | 00104 00068 0010c 00140 00280 00010 00000 00000 31 | 00104 00068 0010c 00140 00280 00010 00000 00000 32 | 00104 00068 0010c 00140 00280 00010 00000 00000 33 | 00104 00068 0010c 00140 00280 00010 00000 00000 34 | 00104 00068 0010c 00440 15000 00010 00000 00000 35 | 00104 00068 0010c 00440 15000 00010 00000 00000 36 | 00104 00068 0010c 00440 15000 00010 00000 00000 37 | 00104 00068 0010c 00440 15000 00010 00000 00000 38 | 00104 00068 0010c 00140 00440 15000 00010 00000 39 | 00104 00068 0010c 00140 00440 15000 00010 00000 40 | 00104 00068 0010c 00140 00440 15000 00010 00000 41 | 00104 00068 0010c 00140 00440 15000 00010 00000 42 | 00104 00068 0010c 00c40 15800 00010 00000 00000 43 | 00104 00068 0010c 00c40 15800 00010 00000 00000 44 | 00104 00068 0010c 00c40 15800 00010 00000 00000 45 | 00104 00068 0010c 00c40 15800 00010 00000 00000 46 | 00104 00068 0010c 00140 00c40 15800 00010 00000 47 | 00104 00068 0010c 00140 00c40 15800 00010 00000 48 | 00104 00068 0010c 00140 00c40 15800 00010 00000 49 | 00104 00068 0010c 00140 00c40 15800 00010 00000 50 | 00104 00068 02001 00010 00000 00000 00000 00000 51 | 00104 00068 02001 00010 00000 00000 00000 00000 52 | 00104 00068 02001 00010 00000 00000 00000 00000 53 | 00104 00068 02001 00010 00000 00000 00000 00000 54 | 00104 00068 00201 00010 00000 00000 00000 00000 55 | 00104 00068 00201 00010 00000 00000 00000 00000 56 | 00104 00068 00201 00010 00000 00000 00000 00000 57 | 00104 00068 00201 00010 00000 00000 00000 00000 58 | 00104 00068 0010c 00041 00010 00000 00000 00000 59 | 00104 00068 0010c 00041 00010 00000 00000 00000 60 | 00104 00068 0010c 00041 00010 00000 00000 00000 61 | 00104 00068 0010c 00041 00010 00000 00000 00000 62 | 00104 00068 0010c 00140 00041 00010 00000 00000 63 | 00104 00068 0010c 00140 00041 00010 00000 00000 64 | 00104 00068 0010c 00140 00041 00010 00000 00000 65 | 00104 00068 0010c 00140 00041 00010 00000 00000 66 | 00104 00068 0010c 00042 00010 00000 00000 00000 67 | 00104 00068 0010c 00042 00010 00000 00000 00000 68 | 00104 00068 0010c 00042 00010 00000 00000 00000 69 | 00104 00068 0010c 00042 00010 00000 00000 00000 70 | 00104 00068 00008 00010 00000 00000 00000 00000 71 | 00104 00068 0010c 00042 00010 00000 00000 00000 72 | 00104 00068 00008 00010 00000 00000 00000 00000 73 | 00104 00068 0010c 00042 00010 00000 00000 00000 74 | 00104 00068 00008 00010 00000 00000 00000 00000 75 | 00104 00068 00008 00010 00000 00000 00000 00000 76 | 00104 00068 0010c 00042 00010 00000 00000 00000 77 | 00104 00068 0010c 00042 00010 -------------------------------------------------------------------------------- /roms/display_7_digits_decoder.rom: -------------------------------------------------------------------------------- 1 | v2.0 raw 2 | 00003f 000006 00005b 00004f 000066 00006d 00007d 000007 3 | 00007f 00006f 00033f 000306 00035b 00034f 000366 00036d 4 | 00037d 000307 00037f 00036f 002dbf 002d86 002ddb 002dcf 5 | 002de6 002ded 002dfd 002d87 002dff 002def 0027bf 002786 6 | 0027db 0027cf 0027e6 0027ed 0027fd 002787 0027ff 0027ef 7 | 00333f 003306 00335b 00334f 003366 00336d 00337d 003307 8 | 00337f 00336f 0036bf 003686 0036db 0036cf 0036e6 0036ed 9 | 0036fd 003687 0036ff 0036ef 003ebf 003e86 003edb 003ecf 10 | 003ee6 003eed 003efd 003e87 003eff 003eef 0003bf 000386 11 | 0003db 0003cf 0003e6 0003ed 0003fd 000387 0003ff 0003ef 12 | 003fbf 003f86 003fdb 003fcf 003fe6 003fed 003ffd 003f87 13 | 003fff 003fef 0037bf 003786 0037db 0037cf 0037e6 0037ed 14 | 0037fd 003787 0037ff 0037ef 019fbf 019f86 019fdb 019fcf 15 | 019fe6 019fed 019ffd 019f87 019fff 019fef 01833f 018306 16 | 01835b 01834f 018366 01836d 01837d 018307 01837f 01836f 17 | 01adbf 01ad86 01addb 01adcf 01ade6 01aded 01adfd 01ad87 18 | 01adff 01adef 01a7bf 01a786 01a7db 01a7cf 01a7e6 01a7ed 19 | 01a7fd 01a787 01a7ff 01a7ef 01b33f 01b306 01b35b 01b34f 20 | 01b366 01b36d 01b37d 01b307 01b37f 01b36f 01b6bf 01b686 21 | 01b6db 01b6cf 01b6e6 01b6ed 01b6fd 01b687 01b6ff 01b6ef 22 | 01bebf 01be86 01bedb 01becf 01bee6 01beed 01befd 01be87 23 | 01beff 01beef 0183bf 018386 0183db 0183cf 0183e6 0183ed 24 | 0183fd 018387 0183ff 0183ef 01bfbf 01bf86 01bfdb 01bfcf 25 | 01bfe6 01bfed 01bffd 01bf87 01bfff 01bfef 01b7bf 01b786 26 | 01b7db 01b7cf 01b7e6 01b7ed 01b7fd 01b787 01b7ff 01b7ef 27 | 16dfbf 16df86 16dfdb 16dfcf 16dfe6 16dfed 16dffd 16df87 28 | 16dfff 16dfef 16c33f 16c306 16c35b 16c34f 16c366 16c36d 29 | 16c37d 16c307 16c37f 16c36f 16edbf 16ed86 16eddb 16edcf 30 | 16ede6 16eded 16edfd 16ed87 16edff 16edef 16e7bf 16e786 31 | 16e7db 16e7cf 16e7e6 16e7ed 16e7fd 16e787 16e7ff 16e7ef 32 | 16f33f 16f306 16f35b 16f34f 16f366 16f36d 16f37d 16f307 33 | 16f37f 16f36f 16f6bf 16f686 16f6db 16f6cf 16f6e6 16f6ed 34 | -------------------------------------------------------------------------------- /scripts/generate_8-bits_7-segments_hex_decoder.py: -------------------------------------------------------------------------------- 1 | #!python3 2 | # This script generates the hex table used to decode 3 | # an 8-bits number to show it in a 7-segment display 4 | # in base 10 (0 to 255). 5 | # The hex table is write into a ROM chip in our 6 | # decoder circuit. 7 | 8 | import save_rom 9 | import sys 10 | 11 | def generate_codes(): 12 | # Codes for 0 to 9 decode - segments bits order g, f, e, d, c, b, a. 13 | decimal_codes = [0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f] 14 | 15 | # Ones (0 to 9) 16 | codes_table = list(decimal_codes) 17 | 18 | # Tens (10 to 99) 19 | tens_table = list() 20 | for num in range(0, 10): 21 | tens = decimal_codes[num] 22 | 23 | for code in decimal_codes: 24 | tens_code = (tens << 7) | code 25 | tens_table.append(tens_code) 26 | if(num > 0): 27 | codes_table.append(tens_code) 28 | 29 | # Hundreds (100 to 255) 30 | for num in range(1, 3): 31 | hundreds = decimal_codes[num] 32 | tens_num = 0 33 | 34 | for tens_code in tens_table: 35 | codes_table.append((hundreds << 14) | tens_code) 36 | if(num == 2 and tens_num >= 55): 37 | break 38 | tens_num += 1 39 | 40 | return codes_table 41 | 42 | # Validates the filename parameter. 43 | if(len(sys.argv) <= 1): 44 | print "Invalid file name." 45 | exit 1 46 | 47 | # Gets the file name. 48 | file_name = sys.argv[1] 49 | 50 | # Generates the codes table. 51 | codes_table = generate_codes() 52 | 53 | # Saves the code table in a ROM file. 54 | instruction_size = 24 # bytes 55 | save_rom.save_file(file_name, codes_table, instruction_size) 56 | -------------------------------------------------------------------------------- /scripts/generate_cpu_microcode.py: -------------------------------------------------------------------------------- 1 | #!python3 2 | 3 | import save_rom 4 | import sys 5 | 6 | # Fetch steps. Used for all instructions. 7 | fetch = [0x0104, 0x0068] 8 | 9 | # Finalizes the instruction execution. 10 | fin_inst = [0x0010] 11 | 12 | # The instruction set. 13 | # op_code = operation code. 14 | # af = address flag. When 1 indicates that the instruction argument is an address, otherwise 0. 15 | # cf = carry flag. 16 | # zf = zero flag. 17 | instruction_set = [ 18 | { 'name': 'nop', 19 | 'op_code': 0x00, 'cf': [0, 1], 'zf': [0, 1], 20 | 'flags': fetch + fin_inst 21 | }, 22 | { 'name': 'halt', 23 | 'op_code': 0x01, 'cf': [0, 1], 'zf': [0, 1], 24 | 'flags': fetch + [ 0x08000 ] + fin_inst 25 | }, 26 | { 'name': 'lda_num', 27 | 'op_code': 0x02, 'cf': [0, 1], 'zf': [0, 1], 28 | 'flags': fetch + [ 0x0010C, 0x04040 ] + fin_inst 29 | }, 30 | { 'name': 'lda_addr', 31 | 'op_code': 0x03, 'cf': [0, 1], 'zf': [0, 1], 32 | 'flags': fetch + [ 0x0010C, 0x00140, 0x04040 ] + fin_inst 33 | }, 34 | { 'name': 'sta_addr', 35 | 'op_code': 0x04, 'cf': [0, 1], 'zf': [0, 1], 36 | 'flags': fetch + [ 0x0010C, 0x00140, 0x02080 ] + fin_inst 37 | }, 38 | { 'name': 'ldb_num', 39 | 'op_code': 0x05, 'cf': [0, 1], 'zf': [0, 1], 40 | 'flags': fetch + [ 0x0010C, 0x00440 ] + fin_inst 41 | }, 42 | { 'name': 'ldb_addr', 43 | 'op_code': 0x06, 'cf': [0, 1], 'zf': [0, 1], 44 | 'flags': fetch + [ 0x0010C, 0x00140, 0x00440 ] + fin_inst 45 | }, 46 | { 'name': 'stb_addr', 47 | 'op_code': 0x07, 'cf': [0, 1], 'zf': [0, 1], 48 | 'flags': fetch + [ 0x0010C, 0x00140, 0x00280 ] + fin_inst 49 | }, 50 | { 'name': 'add_num', 51 | 'op_code': 0x08, 'cf': [0, 1], 'zf': [0, 1], 52 | 'flags': fetch + [ 0x0010C, 0x00440, 0x15000 ] + fin_inst 53 | }, 54 | { 'name': 'add_addr', 55 | 'op_code': 0x09, 'cf': [0, 1], 'zf': [0, 1], 56 | 'flags': fetch + [ 0x0010C, 0x00140, 0x00440, 0x15000 ] + fin_inst 57 | }, 58 | { 'name': 'sub_num', 59 | 'op_code': 0x0A, 'cf': [0, 1], 'zf': [0, 1], 60 | 'flags': fetch + [ 0x0010C, 0x00C40, 0x15800 ] + fin_inst 61 | }, 62 | { 'name': 'sub_addr', 63 | 'op_code': 0x0B, 'cf': [0, 1], 'zf': [0, 1], 64 | 'flags': fetch + [ 0x0010C, 0x00140, 0x00C40, 0x15800 ] + fin_inst 65 | }, 66 | { 'name': 'outa', 67 | 'op_code': 0x0C, 'cf': [0, 1], 'zf': [0, 1], 68 | 'flags': fetch + [ 0x02001 ] + fin_inst 69 | }, 70 | { 'name': 'outb', 71 | 'op_code': 0x0D, 'cf': [0, 1], 'zf': [0, 1], 72 | 'flags': fetch + [ 0x00201 ] + fin_inst 73 | }, 74 | { 'name': 'out_num', 75 | 'op_code': 0x0E, 'cf': [0, 1], 'zf': [0, 1], 76 | 'flags': fetch + [ 0x0010C, 0x00041 ] + fin_inst 77 | }, 78 | { 'name': 'out_addr', 79 | 'op_code': 0x0F, 'cf': [0, 1], 'zf': [0, 1], 80 | 'flags': fetch + [ 0x0010C, 0x00140, 0x00041 ] + fin_inst 81 | }, 82 | { 'name': 'jp_addr', 83 | 'op_code': 0x10, 'cf': [0, 1], 'zf': [0, 1], 84 | 'flags': fetch + [ 0x0010C, 0x00042 ] + fin_inst 85 | }, 86 | { 'name': 'jpz_addr_zf0', 87 | 'op_code': 0x11, 'cf': [0, 1], 'zf': 0, 88 | 'flags': fetch + [ 0x00008 ] + fin_inst 89 | }, 90 | { 'name': 'jpz_addr_zf1', 91 | 'op_code': 0x11, 'cf': [0, 1], 'zf': 1, 92 | 'flags': fetch + [ 0x0010C, 0x00042 ] + fin_inst 93 | }, 94 | { 'name': 'jpc_addr_cf0', 95 | 'op_code': 0x12, 'cf': 0, 'zf': [0, 1], 96 | 'flags': fetch + [ 0x00008 ] + fin_inst 97 | }, 98 | { 'name': 'jpc_addr_cf1', 99 | 'op_code': 0x12, 'cf': 1, 'zf': [0, 1], 100 | 'flags': fetch + [ 0x0010C, 0x00042 ] + fin_inst 101 | }, 102 | ] 103 | 104 | # Converts a value to an array if the value is not an array yet. 105 | def cast_array(value): 106 | return value if isinstance(value, list) else [value] 107 | 108 | # Print the microcode 109 | def print_microcode(microcode): 110 | for instruction in microcode: 111 | op_code = instruction['address'] >> 5 112 | cf = (instruction['address'] & 0x10) >> 4 113 | zf = (instruction['address'] & 0x08) >> 3 114 | step = instruction['address'] & 0x07 115 | print("{} - 0x{:04x} - {:05b} {:01b} {:01b} {:03b} - 0x{:05x}".format( 116 | instruction['name'].ljust(13), 117 | instruction['address'], 118 | op_code, cf, zf, step, 119 | instruction['flag'])) 120 | 121 | # Transforms an array of arrays in an single array. 122 | def flat_array(data): 123 | return [value for internal_data in data for value in internal_data] 124 | 125 | 126 | def create_instruction_microcode(instruction, cf, zf): 127 | step = 0 128 | instruction_steps = list() 129 | # Loop over flags 130 | for flag in cast_array(instruction['flags']): 131 | address = instruction['op_code'] << 5 | cf << 4 | zf << 3 | step 132 | instruction_microcode = { 133 | 'name': instruction['name'], 134 | 'address': address, 135 | 'flag': flag 136 | } 137 | instruction_steps.append(instruction_microcode) 138 | step += 1 139 | 140 | return instruction_steps 141 | 142 | # Generates the processor microcode based on the given instruction set 143 | def generate_microcode(fetch, instruction_set): 144 | microcode = list() 145 | 146 | # Loop over the instructions 147 | for instruction in instruction_set: 148 | instruction_steps = [ create_instruction_microcode(instruction, cf, zf) 149 | # Loop over the carry flag 150 | for cf in cast_array(instruction['cf']) 151 | # Loop over the zero flag 152 | for zf in cast_array(instruction['zf']) 153 | ] 154 | microcode += flat_array(instruction_steps) 155 | 156 | return microcode 157 | 158 | # Fills the microcode missing addresses with NOP (no operation) 159 | def fill_microcode_addresses(microcode): 160 | address = 0 161 | filled_microcode = list() 162 | microcode = sorted( 163 | microcode, 164 | key = lambda item: item["address"], 165 | reverse = False) 166 | 167 | # Loop over the microcode steps and complete the missing addresses. 168 | for instruction_step in microcode: 169 | while address < instruction_step['address']: 170 | filled_microcode.append({ 171 | 'name': 'nop', 172 | 'address': address, 173 | 'flag': 0 174 | }) 175 | address += 1 176 | filled_microcode.append(instruction_step) 177 | address += 1 178 | 179 | return filled_microcode 180 | 181 | # sys.argv.append("-v") 182 | # sys.argv.append("test") 183 | 184 | # Validates the arguments. 185 | arguments_num = len(sys.argv) 186 | if(arguments_num <= 1 or arguments_num > 3): 187 | print(" Invalid arguments.\n Ex.: generate_cpu_microcode.py [-v] your_filename.rom") 188 | print(" -v Verbose mode (optional)\n") 189 | exit(1) 190 | 191 | # Gets the arguments values. 192 | verbose = (arguments_num == 3 and sys.argv[1] == '-v') 193 | file_name = sys.argv[2 if arguments_num == 3 else 1] 194 | 195 | # Generates the codes table. 196 | microcode = generate_microcode(fetch, instruction_set) 197 | microcode = fill_microcode_addresses(microcode) 198 | if verbose: 199 | print_microcode(microcode) 200 | 201 | # Saves the code table in a ROM file. 202 | instruction_size = 20 # bytes 203 | save_rom.save_file( 204 | file_name, 205 | [instruction_step["flag"] for instruction_step in microcode], 206 | instruction_size) 207 | 208 | -------------------------------------------------------------------------------- /scripts/save_rom.py: -------------------------------------------------------------------------------- 1 | # Saves the codes table in a ROM file. 2 | # file_name: the ROM file name 3 | # codes_table: the code table to be saved into the ROM file 4 | # instruction_size: the instruction size in bytes 5 | # cols: the number of columns 6 | def save_file(file_name, codes_table, instruction_size, cols = 8): 7 | file = open(file_name, "w+", encoding="utf-8") 8 | file.write("v2.0 raw\n") 9 | col = 0 10 | instruction_size = int(instruction_size / 4) 11 | for code in codes_table: 12 | col += 1 13 | instruction = "{:0x}".format(code).rjust(instruction_size, "0") 14 | file.write("{} ".format(instruction)) 15 | if(col > cols - 1): 16 | col = 0 17 | file.write("\n") 18 | file.close() 19 | -------------------------------------------------------------------------------- /start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | java -jar logisim-evolution-2.15.0-all.jar computer_8bits.circ --------------------------------------------------------------------------------