├── .gitignore ├── CPU.qpf ├── CPU.vhd ├── LICENSE ├── README.md ├── alu.vhd ├── alu_register.vhd ├── alu_register_tb.vhd ├── alu_tb.vhd ├── bin2bcd_8bit.vhd ├── bin2bcd_8bit_tb.vhd ├── clock.vhd ├── clock_tb.vhd ├── debounce.vhd ├── debugger_led.vhd ├── debugger_led_tb.vhd ├── display_7_segment.vhd ├── display_7_segment_tb.vhd ├── flags_reg.vhd ├── flags_reg_tb.vhd ├── instruction_decoder.vhd ├── instruction_decoder_tb.vhd ├── instruction_reg.vhd ├── instruction_reg_tb.vhd ├── memory_addr_reg.vhd ├── memory_addr_reg_tb.vhd ├── prog_counter.vhd ├── prog_counter_tb.vhd ├── simulation ├── alu.bmp ├── alu_reg.bmp ├── bin_to_bcd.bmp ├── clock.bmp ├── debug_leds.bmp ├── flags.bmp ├── inst_decoder.bmp ├── instruction_regis.bmp ├── mem_addr_reg.bmp ├── out_7_seg.bmp ├── prog_counter.bmp ├── ram.bmp └── test_cpu_add_example.bmp ├── single_port_ram.vhd ├── single_port_ram_tb.vhd ├── test_cpu.vhd └── test_cpu_tb.vhd /.gitignore: -------------------------------------------------------------------------------- 1 | # Files to ignore 2 | **.bak 3 | **.ddb 4 | **.qsf 5 | **.qws 6 | **.mti 7 | **.mpf 8 | **.wlf 9 | 10 | # Directories to ignore 11 | /db/ 12 | /incremental_db/ 13 | /output_files/ 14 | **/work/ -------------------------------------------------------------------------------- /CPU.qpf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------- # 2 | # 3 | # Copyright (C) 1991-2013 Altera Corporation 4 | # Your use of Altera Corporation's design tools, logic functions 5 | # and other software and tools, and its AMPP partner logic 6 | # functions, and any output files from any of the foregoing 7 | # (including device programming or simulation files), and any 8 | # associated documentation or information are expressly subject 9 | # to the terms and conditions of the Altera Program License 10 | # Subscription Agreement, Altera MegaCore Function License 11 | # Agreement, or other applicable license agreement, including, 12 | # without limitation, that your use is for the sole purpose of 13 | # programming logic devices manufactured by Altera and sold by 14 | # Altera or its authorized distributors. Please refer to the 15 | # applicable agreement for further details. 16 | # 17 | # -------------------------------------------------------------------------- # 18 | # 19 | # Quartus II 64-Bit 20 | # Version 13.0.1 Build 232 06/12/2013 Service Pack 1 SJ Web Edition 21 | # Date created = 15:20:16 January 20, 2019 22 | # 23 | # -------------------------------------------------------------------------- # 24 | 25 | QUARTUS_VERSION = "13.0" 26 | DATE = "15:20:16 January 20, 2019" 27 | 28 | # Revisions 29 | 30 | PROJECT_REVISION = "CPU" 31 | -------------------------------------------------------------------------------- /CPU.vhd: -------------------------------------------------------------------------------- 1 | --ALTERA EP4CE6E22C8N 2 | --Configuration device EPCS16N 3 | --Requires POF format file for Active Serial programming 4 | 5 | library ieee; 6 | use ieee.std_logic_1164.all; 7 | use ieee.numeric_std.all; 8 | 9 | entity CPU is 10 | port( 11 | i_master_clk : in std_logic; 12 | i_master_reset : in std_logic; 13 | i_manual_step : in std_logic; 14 | i_clk_select : in std_logic; 15 | i_clk_freq_select : in std_logic_vector(1 downto 0); 16 | o_clk_freq_select_dbg : out std_logic_vector(1 downto 0); 17 | o_clk_led : out std_logic; 18 | o_inv_clk_led : out std_logic; 19 | o_digit : out std_logic_vector(3 downto 0); 20 | o_segments : out std_logic_vector(7 downto 0); 21 | o_dbg_led_bus : out std_logic_vector(7 downto 0); 22 | o_activate_dbg_leds : out std_logic_vector(11 downto 0) 23 | ); 24 | end CPU; 25 | 26 | architecture rtl of cpu is 27 | 28 | --CPU Clock 29 | signal w_CLK_1HZ : std_logic; 30 | signal w_HLT : std_logic; 31 | signal w_CLK_FREQ_DBG_LED : std_logic_vector(1 downto 0); 32 | 33 | --Master reset for the entire CPU 34 | signal w_RESET : std_logic; 35 | 36 | --Data bus connections 37 | signal w_DATA_BUS_IN : std_logic_vector(7 downto 0); 38 | signal w_DATA_BUS_OUT_PC : std_logic_vector(7 downto 0); 39 | signal w_DATA_BUS_OUT_INR : std_logic_vector(7 downto 0); 40 | 41 | --Memory address register controls and output 42 | signal w_MI : std_logic; --Memory address register in 43 | signal w_ADDR : std_logic_vector(3 downto 0); --Address to be put into RAM 44 | 45 | --RAM control and outputs 46 | signal w_RI : std_logic; 47 | signal w_RO : std_logic; 48 | signal w_DATA_BUS_OUT_RAM : std_logic_vector(7 downto 0); 49 | signal w_RAM_DBG_LED : std_logic_vector(7 downto 0); 50 | 51 | --Program counter controls and output 52 | signal w_CO : std_logic; --Counter out 53 | signal w_CE : std_logic; --Counter enable (Increments) 54 | signal w_J : std_logic; --Jump 55 | signal w_PC_DBG_LED : std_logic_vector(3 downto 0); 56 | 57 | --Register A and B for the ALU (A is the accumulator) 58 | signal w_AI : std_logic; 59 | signal w_AO : std_logic; 60 | signal w_DATA_BUS_OUT_A : std_logic_vector(7 downto 0); 61 | signal w_ALU_REG_OUT_A : std_logic_vector(7 downto 0); 62 | signal w_REG_DBG_LED_A : std_logic_vector(7 downto 0); 63 | 64 | signal w_BI : std_logic; 65 | signal w_BO : std_logic; 66 | signal w_DATA_BUS_OUT_B : std_logic_vector(7 downto 0); 67 | signal w_ALU_REG_OUT_B : std_logic_vector(7 downto 0); 68 | signal w_REG_DBG_LED_B : std_logic_vector(7 downto 0); 69 | 70 | --ALU 71 | signal w_EO : std_logic; 72 | signal w_SU : std_logic; 73 | signal w_CY : std_logic; 74 | signal w_ZR : std_logic; 75 | signal w_DATA_BUS_OUT_ALU : std_logic_vector(7 downto 0); 76 | signal w_ALU_DBG_LED : std_logic_vector(7 downto 0); 77 | 78 | --Flags register 79 | signal w_FI : std_logic; 80 | signal w_FLAGS : std_logic_vector(1 downto 0); 81 | signal w_FLAGS_DBG_LED : std_logic_vector(1 downto 0); 82 | 83 | --Instruction register controls and output 84 | signal w_II : std_logic; 85 | signal w_IO : std_logic; 86 | signal w_INSTRUCTION : std_logic_vector(3 downto 0); 87 | signal w_INSTREG_DBG_LED : std_logic_vector(7 downto 0); 88 | 89 | --Instruction decoder 90 | signal w_INV_CLK : std_logic; 91 | signal w_INST_STEP_DBG_LED : std_logic_vector(2 downto 0); 92 | signal w_CTRL_WORD_DBG_LED : std_logic_vector(15 downto 0); 93 | signal w_CTRL_WORD_DBG_LED_INV : std_logic_vector(15 downto 0); 94 | 95 | --Output register 96 | signal w_OI : std_logic; 97 | 98 | component clock 99 | port( 100 | i_clkin : in std_logic; 101 | i_man_clk : in std_logic; 102 | i_select : in std_logic; 103 | i_sel_clk_freq : in std_logic_vector(1 downto 0); 104 | i_halt : in std_logic; 105 | o_clkout : out std_logic; 106 | o_clk_freq_dbg_led : out std_logic_vector(1 downto 0) 107 | ); 108 | end component clock; 109 | 110 | component debounce 111 | port( 112 | i_clk : in std_logic; 113 | i_switch : in std_logic; 114 | o_switch : out std_logic 115 | ); 116 | end component debounce; 117 | 118 | component memory_addr_reg 119 | port( 120 | i_clkin : in std_logic; 121 | i_reset : in std_logic; 122 | i_mi : in std_logic; --Signal to take in the 4 LSB and put it into the register (Active LOW) 123 | i_data_bus_in : in std_logic_vector(7 downto 0); 124 | o_addr : out std_logic_vector(3 downto 0) --Outputs the 4 LSB stored in the memory address register 125 | ); 126 | end component memory_addr_reg; 127 | 128 | component single_port_ram 129 | port( 130 | i_clkin : in std_logic; 131 | i_we : in std_logic; --Active LOW 132 | i_oe : in std_logic; --Active LOW 133 | i_addr : in std_logic_vector(3 downto 0); 134 | i_data_bus_in : in std_logic_vector(7 downto 0); 135 | o_data_bus_out : out std_logic_vector(7 downto 0); 136 | o_ram_dbg_led : out std_logic_vector(7 downto 0) 137 | ); 138 | end component single_port_ram; 139 | 140 | component prog_counter 141 | port( 142 | i_clkin : in std_logic; 143 | i_reset : in std_logic; 144 | i_ce : in std_logic; --Counter enable (Active LOW) 145 | i_co : in std_logic; --Counter output to bus (Active LOW) 146 | i_j : in std_logic; --Set the counter to a specfic value by reading in the 4 LSB of the bus (Used in jump instruction) (Active LOW) 147 | i_data_bus_in : in std_logic_vector(7 downto 0); --All th 8 bits are used but only the 4 LSB are considered 148 | o_data_bus_out : out std_logic_vector(7 downto 0); 149 | o_pc_dbg_led : out std_logic_vector(3 downto 0) 150 | ); 151 | end component prog_counter; 152 | 153 | component alu_register 154 | port( 155 | i_clkin : in std_logic; 156 | i_reset : in std_logic; 157 | i_we : in std_logic; --Load enable (Active low) 158 | i_oe : in std_logic; --Write enable (Active low) 159 | i_data_bus_in: in std_logic_vector (7 downto 0); --For internal buses seperate buses are used for data in/out 160 | o_data_bus_out : out std_logic_vector (7 downto 0); --No tri-state logic internally available on at IO pins 161 | o_alu_reg_out : out std_logic_vector (7 downto 0); --This is connected to the ALU directly (Always outputs) 162 | o_reg_dbg_led : out std_logic_vector (7 downto 0) 163 | ); 164 | end component alu_register; 165 | 166 | component alu 167 | port( 168 | i_eo : in std_logic; --Output the result (Active low) 169 | i_su : in std_logic; --Subtraction when high and addition when low 170 | i_a : in std_logic_vector (7 downto 0); 171 | i_b : in std_logic_vector (7 downto 0); 172 | o_cy : out std_logic; 173 | o_zr : out std_logic; 174 | o_alu_bus_out : out std_logic_vector (7 downto 0); 175 | o_alu_dbg_led : out std_logic_vector(7 downto 0) 176 | ); 177 | end component alu; 178 | 179 | component flags_reg 180 | port( 181 | i_clkin : in std_logic; 182 | i_reset : in std_logic; 183 | i_cb : in std_logic; --Carry bit 184 | i_zb : in std_logic; --Zero bit 185 | i_we : in std_logic; --Write to flags register(Active LOW) 186 | o_flags : out std_logic_vector(1 downto 0); 187 | o_flags_dbg_led : out std_logic_vector(1 downto 0) 188 | ); 189 | end component flags_reg; 190 | 191 | component instruction_reg 192 | port( 193 | i_clkin : in std_logic; 194 | i_reset : in std_logic; 195 | i_we : in std_logic; --Instruction register in (Active LOW) 196 | i_oe : in std_logic; --Instruction register output (Active LOW) 197 | i_data_bus_in : in std_logic_vector(7 downto 0); 198 | o_data_bus_out : out std_logic_vector(7 downto 0); 199 | o_instuction : out std_logic_vector(3 downto 0); 200 | o_instreg_dbg_led : out std_logic_vector(7 downto 0) 201 | ); 202 | end component instruction_reg; 203 | 204 | component instruction_decoder 205 | port( 206 | i_clkin : in std_logic; 207 | i_reset : in std_logic; 208 | i_instruction : in std_logic_vector(3 downto 0); 209 | i_flags : in std_logic_vector(1 downto 0); 210 | o_hlt : out std_logic; 211 | o_mi : out std_logic; 212 | o_ri : out std_logic; 213 | o_ro : out std_logic; 214 | o_io : out std_logic; 215 | o_ii : out std_logic; 216 | o_ai : out std_logic; 217 | o_ao : out std_logic; 218 | o_eps : out std_logic; 219 | o_su : out std_logic; 220 | o_bi : out std_logic; 221 | o_bo : out std_logic; 222 | o_oi : out std_logic; 223 | o_ce : out std_logic; 224 | o_co : out std_logic; 225 | o_j : out std_logic; 226 | o_fi : out std_logic; 227 | o_inv_clk : out std_logic; 228 | o_inst_step_dbg_led : out std_logic_vector(2 downto 0); 229 | o_ctrl_word_dbg_led : out std_logic_vector(15 downto 0) 230 | ); 231 | end component instruction_decoder; 232 | 233 | component display_7_segment 234 | port( 235 | i_mclk : in std_logic; 236 | i_clkin : in std_logic; 237 | i_reset : in std_logic; 238 | i_we : in std_logic; 239 | i_display_signed : in std_logic; 240 | i_data_bus_in : in std_logic_vector(7 downto 0); 241 | o_dig : out std_logic_vector(3 downto 0); 242 | o_segment_drive : out std_logic_vector(7 downto 0) 243 | ); 244 | end component display_7_segment; 245 | 246 | component debugger_led is 247 | port( 248 | i_mclk : in std_logic; 249 | i_pc_dbg : in std_logic_vector(3 downto 0); 250 | i_a_reg_dbg : in std_logic_vector(7 downto 0); 251 | i_alu_reg_dbg : in std_logic_vector(7 downto 0); 252 | i_flags_reg_dbg : in std_logic_vector(1 downto 0); 253 | i_b_reg_dbg : in std_logic_vector(7 downto 0); 254 | i_mem_addr_dbg : in std_logic_vector(3 downto 0); 255 | i_ram_content_dbg : in std_logic_vector(7 downto 0); 256 | i_inst_reg_dbg : in std_logic_vector(7 downto 0); 257 | i_inst_step_dbg : in std_logic_vector(2 downto 0); 258 | i_ctrl_word_dbg : in std_logic_vector(15 downto 0); 259 | i_bus_dbg : in std_logic_vector(7 downto 0); 260 | o_muxed_dbg_led_bus : out std_logic_vector(7 downto 0) := (others => '0'); 261 | o_act_led_bus : out std_logic_vector(11 downto 0) := (others => '0') 262 | ); 263 | end component debugger_led; 264 | 265 | begin 266 | 267 | --Bus connections 268 | w_DATA_BUS_IN <= w_DATA_BUS_OUT_PC when(w_CO = '0') else 269 | w_DATA_BUS_OUT_A when(w_AO = '0') else 270 | w_DATA_BUS_OUT_ALU when(w_EO = '0') else 271 | w_DATA_BUS_OUT_B when(w_BO = '0') else 272 | w_DATA_BUS_OUT_RAM when(w_RO = '0') else 273 | w_DATA_BUS_OUT_INR when(w_IO = '0') else 274 | (others => '0'); 275 | 276 | cpu_clk : clock 277 | port map( 278 | i_clkin => i_master_clk, 279 | i_man_clk => i_manual_step, 280 | i_select => i_clk_select, 281 | i_sel_clk_freq => i_clk_freq_select, 282 | i_halt => w_HLT, 283 | o_clkout => w_CLK_1HZ, 284 | o_clk_freq_dbg_led => w_CLK_FREQ_DBG_LED 285 | ); 286 | 287 | reset_debounce : debounce 288 | port map( 289 | i_clk => i_master_clk, 290 | i_switch => i_master_reset, 291 | o_switch => w_RESET 292 | ); 293 | 294 | pc : prog_counter 295 | port map( 296 | i_clkin => w_CLK_1HZ, 297 | i_reset => w_RESET, 298 | i_ce => w_CE, 299 | i_co => w_CO, 300 | i_j => w_J, 301 | i_data_bus_in => w_DATA_BUS_IN, 302 | o_data_bus_out => w_DATA_BUS_OUT_PC, 303 | o_pc_dbg_led => w_PC_DBG_LED 304 | ); 305 | 306 | a_reg : alu_register 307 | port map( 308 | i_clkin => w_CLK_1HZ, 309 | i_reset => w_RESET, 310 | i_we => w_AI, 311 | i_oe => w_AO, 312 | i_data_bus_in => w_DATA_BUS_IN, 313 | o_data_bus_out => w_DATA_BUS_OUT_A, 314 | o_alu_reg_out => w_ALU_REG_OUT_A, 315 | o_reg_dbg_led => w_REG_DBG_LED_A 316 | ); 317 | 318 | arith_logic_unit : alu 319 | port map( 320 | i_eo => w_EO, 321 | i_su => w_SU, 322 | i_a => w_ALU_REG_OUT_A, 323 | i_b => w_ALU_REG_OUT_B, 324 | o_cy => w_CY, 325 | o_zr => w_ZR, 326 | o_alu_bus_out => w_DATA_BUS_OUT_ALU, 327 | o_alu_dbg_led => w_ALU_DBG_LED 328 | ); 329 | 330 | flags_register : flags_reg 331 | port map( 332 | i_clkin => w_CLK_1HZ, 333 | i_reset => w_RESET, 334 | i_cb => w_CY, 335 | i_zb => w_ZR, 336 | i_we => w_FI, 337 | o_flags => w_FLAGS, 338 | o_flags_dbg_led => w_FLAGS_DBG_LED 339 | ); 340 | 341 | b_reg : alu_register 342 | port map( 343 | i_clkin => w_CLK_1HZ, 344 | i_reset => w_RESET, 345 | i_we => w_BI, 346 | i_oe => w_BO, 347 | i_data_bus_in => w_DATA_BUS_IN, 348 | o_data_bus_out => w_DATA_BUS_OUT_B, 349 | o_alu_reg_out => w_ALU_REG_OUT_B, 350 | o_reg_dbg_led => w_REG_DBG_LED_B 351 | ); 352 | 353 | mem_addr_reg : memory_addr_reg 354 | port map( 355 | i_clkin => w_CLK_1HZ, 356 | i_reset => w_RESET, 357 | i_mi => w_MI, 358 | i_data_bus_in => w_DATA_BUS_IN, 359 | o_addr => w_ADDR 360 | ); 361 | 362 | ram : single_port_ram 363 | port map( 364 | i_clkin => w_CLK_1HZ, 365 | i_we => w_RI, 366 | i_oe => w_RO, 367 | i_addr => w_ADDR, 368 | i_data_bus_in => w_DATA_BUS_IN, 369 | o_data_bus_out => w_DATA_BUS_OUT_RAM, 370 | o_ram_dbg_led => w_RAM_DBG_LED 371 | ); 372 | 373 | inst_reg : instruction_reg 374 | port map( 375 | i_clkin => w_CLK_1HZ, 376 | i_reset => w_RESET, 377 | i_we => w_II, 378 | i_oe => w_IO, 379 | i_data_bus_in => w_DATA_BUS_IN, 380 | o_data_bus_out => w_DATA_BUS_OUT_INR, 381 | o_instuction => w_INSTRUCTION, 382 | o_instreg_dbg_led => w_INSTREG_DBG_LED 383 | ); 384 | 385 | inst_decode : instruction_decoder 386 | port map( 387 | i_clkin => w_CLK_1HZ, 388 | i_reset => w_RESET, 389 | i_instruction => w_INSTRUCTION, 390 | i_flags => w_FLAGS, 391 | o_hlt => w_HLT, 392 | o_mi => w_MI, 393 | o_ri => w_RI, 394 | o_ro => w_RO, 395 | o_io => w_IO, 396 | o_ii => w_II, 397 | o_ai => w_AI, 398 | o_ao => w_AO, 399 | o_eps => w_EO, 400 | o_su => w_SU, 401 | o_bi => w_BI, 402 | o_bo => w_BO, 403 | o_oi => w_OI, 404 | o_ce => w_CE, 405 | o_co => w_CO, 406 | o_j => w_J, 407 | o_fi => w_FI, 408 | o_inv_clk => w_INV_CLK, 409 | o_inst_step_dbg_led => w_INST_STEP_DBG_LED, 410 | o_ctrl_word_dbg_led => w_CTRL_WORD_DBG_LED 411 | ); 412 | 413 | output_disp : display_7_segment 414 | port map( 415 | i_mclk => i_master_clk, 416 | i_clkin => w_CLK_1HZ, 417 | i_reset => w_RESET, 418 | i_we => w_OI, 419 | i_display_signed => '1', 420 | i_data_bus_in => w_DATA_BUS_IN, 421 | o_dig => o_digit, 422 | o_segment_drive => o_segments 423 | ); 424 | 425 | debug_led : debugger_led 426 | port map( 427 | i_mclk => i_master_clk, 428 | i_pc_dbg => w_PC_DBG_LED, 429 | i_a_reg_dbg => w_REG_DBG_LED_A, 430 | i_alu_reg_dbg => w_ALU_DBG_LED, 431 | i_flags_reg_dbg => w_FLAGS_DBG_LED, 432 | i_b_reg_dbg => w_REG_DBG_LED_B, 433 | i_mem_addr_dbg => w_ADDR, --The address itself is used for debug 434 | i_ram_content_dbg => w_RAM_DBG_LED, 435 | i_inst_reg_dbg => w_INSTREG_DBG_LED, 436 | i_inst_step_dbg => w_INST_STEP_DBG_LED, 437 | i_ctrl_word_dbg => w_CTRL_WORD_DBG_LED_INV, 438 | i_bus_dbg => w_DATA_BUS_IN, 439 | o_muxed_dbg_led_bus => o_dbg_led_bus, 440 | o_act_led_bus => o_activate_dbg_leds 441 | ); 442 | 443 | o_clk_led <= w_CLK_1HZ; 444 | o_inv_clk_led <= w_INV_CLK; 445 | o_clk_freq_select_dbg <= w_CLK_FREQ_DBG_LED; 446 | 447 | w_CTRL_WORD_DBG_LED_INV <= not w_CTRL_WORD_DBG_LED; 448 | 449 | end rtl; 450 | 451 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Ajith Thomas 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # **FPGA 8-Bit CPU** 2 | This CPU design is based on Ben Eater's tutorial on [building an 8-Bit breadboard computer][BenEaterTut]. The CPU is implemented in an FPGA using VHDL and follows the same architecture as described in the tutorial. 3 | 4 | ## Motivation 5 | This small project was done to get familiar with FPGAs, digital circuit design and how a CPU works. The CPU use both combinational (Does not require a clock) and sequential logic (Requires a clock). FPGA needs simulation 6 | to debug hardware problems and therefore testbenches are required. Testbenches for most of the modules are provided. 7 | 8 | ## 8-Bit FPGA CPU Specification 9 | The FPGA used is an Altera Cyclone IV EP4CE6E22C8N. 10 | 11 | * #### The CPU design is very basic and contains the following parts: 12 | * 8-Bit ALU 13 | * Carry Flag (CF) and Zero Flag (ZF) bits for the flags register 14 | * 8-Bit ALU registers A and B (A is used as the accumulator) 15 | * Instruction register (4-Bit opcode and 4-Bit operand) 16 | * Instruction decoder with 16 control line outputs 17 | * 4-Bit memory address register 18 | * 16 Bytes of RAM 19 | * 4-Bit program counter 20 | * 8-Bit wide bus for both data and addressing (Multiplexed not bidirectional) 21 | * Manually adjustable clocks with 4 levels (1Hz, 5Hz, 10Hz, 25Hz) derived from a 50 MHz clock 22 | 23 | * #### Other components in the CPU design: 24 | * 4 digit, 7-segment display for outputting the results (Multiplexed) 25 | * 8-Bit binary to BCD converter for output to 7-segment display [(Double dabble algorithm in VHDL)][WikiDoubleDabble] 26 | * Debug LEDs to see what is happening in the registers (Multiplexed) 27 | * Debounce for DIP switches and momentary push buttons [(Switch Debounce Nandland Tutorial)][DebounceTut] 28 | 29 | ## Implemented Instruction Set 30 | The following instruction set is currently implemented in the 8-Bit CPU. All the opcodes contains only one operand. 31 | 32 | Opcode | Opcode in binary | Operand | Description 33 | :---: | :---: | :--- | :--- 34 | NOP | 0000 | - | No operation 35 | LDA | 0001 | Address of variable | Load register A 36 | ADD | 0010 | Address of variable | Adds and puts the result in A register 37 | SUB | 0011 | Address of variable | Subtracts and puts the result in A register 38 | STA | 0100 | Address in RAM | Stores the value in A register to RAM 39 | LDI | 0101 | Binary value | Loads a value immediately into A register 40 | JMP | 0110 | Address to jump to | Unconditional jump 41 | JC | 0111 | Address to jump to | Jump only if the carry flag is set 42 | JZ | 1000 | Address to jump to | Jump only if the zero flag is set 43 | OUT | 1110 | - | Output the result to the 7-segment display 44 | HALT | 1111 | - | Stops the CPU clock 45 | 46 | ## Programming the CPU 47 | The programs written for the CPU are stored in the RAM. Each instruction is fetched from the RAM and executed. To change the program check the `single_port_ram.vhd` file. Example for a simple add program is given below. 48 | 49 | ```VHDL 50 | --Example for simple addition 51 | signal r_ram : memory_t := ( 52 | "00011110", --LDA 14 53 | "00101111", --ADD 15 54 | "11100000", --OUT 55 | "11110000", --HALT 56 | "00000000", 57 | "00000000", 58 | "00000000", 59 | "00000000", 60 | "00000000", 61 | "00000000", 62 | "00000000", 63 | "00000000", 64 | "00000000", 65 | "00000000", 66 | "00111000", --56 in binary at address 14 67 | "00011100" --28 in binary at address 15 68 | ); 69 | ``` 70 | Manually writing to RAM using DIP switches is not implemented. 71 | 72 | ## Demonstration 73 | Video demonstration of the CPU in action. 74 | 75 | [![Demo Video](https://img.youtube.com/vi/5W5bYbguIHo/0.jpg)](https://www.youtube.com/watch?v=5W5bYbguIHo) 76 | 77 | The following simulation is for a simple add program that loads the values from ram and then stores the result of the addition in A register. The `test_cpu.vhd` testbench was used for the simulation. 78 | 79 | ![Add Program Sim](./simulation/test_cpu_add_example.bmp) 80 | 81 | [BenEaterTut]:https://www.youtube.com/watch?v=HyznrdDSSGM&list=PLowKtXNTBypGqImE405J2565dvjafglHU 82 | [DebounceTut]:https://www.nandland.com/goboard/debounce-switch-project.html 83 | [WikiDoubleDabble]:https://en.wikipedia.org/wiki/Double_dabble 84 | -------------------------------------------------------------------------------- /alu.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | 3 | use ieee.std_logic_1164.all; 4 | use ieee.numeric_std.all; 5 | 6 | entity alu is 7 | port( 8 | i_eo : in std_logic; --Output the result (Active low) 9 | i_su : in std_logic; --Subtraction when high and addition when low 10 | i_a : in std_logic_vector (7 downto 0); 11 | i_b : in std_logic_vector (7 downto 0); 12 | o_cy : out std_logic; --Carry 13 | o_zr : out std_logic; --Zero 14 | o_alu_bus_out : out std_logic_vector (7 downto 0); 15 | o_alu_dbg_led : out std_logic_vector(7 downto 0) 16 | ); 17 | end entity alu; 18 | 19 | architecture rtl of alu is 20 | 21 | --Only combinational logic is used for the ALU 22 | 23 | signal w_a : std_logic_vector (8 downto 0) := (others => '0'); 24 | signal w_b : std_logic_vector (8 downto 0) := (others => '0'); 25 | signal w_alu_out : std_logic_vector (8 downto 0) := (others => '0'); 26 | 27 | begin 28 | 29 | w_a(7 downto 0) <= i_a; 30 | w_b(7 downto 0) <= i_b; 31 | 32 | --Arithmatic operations (Only add and subtraction) (Subtraction is active low) 33 | w_alu_out <= std_logic_vector(unsigned(w_a) + unsigned(w_b)) when (i_su = '1') else 34 | std_logic_vector(unsigned(w_a) - unsigned(w_b)); 35 | 36 | o_cy <= w_alu_out(8); --Output the carry bit used with jump carry command 37 | o_zr <= '1' when (w_alu_out(7 downto 0) = (w_alu_out(7 downto 0)'range => '0')) else --Output the zero bit used for jump zero command 38 | '0'; 39 | 40 | --Putting the ALU result onto the bus 41 | o_alu_bus_out <= w_alu_out(7 downto 0) when(i_eo = '0') else 42 | (others => '0'); 43 | 44 | --Debug LEDs if used 45 | o_alu_dbg_led <= w_alu_out(7 downto 0); 46 | 47 | end architecture rtl; -------------------------------------------------------------------------------- /alu_register.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | 3 | use ieee.std_logic_1164.all; 4 | use ieee.numeric_std.all; 5 | 6 | entity alu_register is 7 | port( 8 | i_clkin : in std_logic; 9 | i_reset : in std_logic; 10 | i_we : in std_logic; --Load enable (Active low) 11 | i_oe : in std_logic; --Write enable (Active low) 12 | i_data_bus_in: in std_logic_vector (7 downto 0); --For internal buses seperate buses are used for data in/out 13 | o_data_bus_out : out std_logic_vector (7 downto 0); --No tri-state logic internally available on at IO pins 14 | o_alu_reg_out : out std_logic_vector (7 downto 0); --This is connected to the ALU directly (Always output) 15 | o_reg_dbg_led : out std_logic_vector (7 downto 0) 16 | ); 17 | end entity alu_register; 18 | 19 | architecture rtl of alu_register is 20 | 21 | signal r_data_reg : std_logic_vector(7 downto 0) := (others => '0'); --Initialize register to zero 22 | 23 | begin 24 | 25 | --Loading the data into the Accumulator (A) or B register 26 | p_load : process(i_clkin, i_reset) is 27 | begin 28 | if i_reset = '0' then --Asynchronus reset is used since clock can be halted which means synchronous reset won't work 29 | r_data_reg <= (others => '0'); 30 | elsif rising_edge(i_clkin) then 31 | if i_we = '0' and i_oe = '1' then 32 | r_data_reg <= i_data_bus_in; --Load the data from the bus in to the register 33 | end if; 34 | end if; 35 | end process p_load; 36 | 37 | --Putting the data in the register on to the bus 38 | o_data_bus_out <= r_data_reg when(i_oe = '0' and i_we = '1') else 39 | (others => '0'); 40 | 41 | o_alu_reg_out <= r_data_reg; 42 | 43 | o_reg_dbg_led <= r_data_reg; --For debugging the data in the register used LED 44 | 45 | end rtl; 46 | 47 | 48 | -------------------------------------------------------------------------------- /alu_register_tb.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | 3 | use ieee.std_logic_1164.all; 4 | use ieee.numeric_std.all; 5 | 6 | entity alu_register_tb is 7 | end alu_register_tb; 8 | 9 | architecture behaviour of alu_register_tb is 10 | 11 | --50 MHz = 20 ns period 12 | constant c_CLOCK_PERIOD : time := 20 ns; 13 | 14 | signal r_CLKIN : std_logic := '0'; 15 | signal r_RESET : std_logic := '1'; 16 | signal r_WE : std_logic := '1'; 17 | signal r_OE : std_logic := '1'; 18 | signal r_DATA_BUS_IN : std_logic_vector (7 downto 0) := (others => '0'); 19 | signal r_DATA_BUS_OUT : std_logic_vector (7 downto 0) := (others => '0'); 20 | signal r_REG_DBG_LED : std_logic_vector (7 downto 0) := (others => '0'); 21 | 22 | component alu_register is 23 | port( 24 | i_clkin : in std_logic; 25 | i_reset : in std_logic; 26 | i_we : in std_logic; --Load enable (Active low) 27 | i_oe : in std_logic; --Write enable (Active low) 28 | i_data_bus_in: in std_logic_vector (7 downto 0); --For internal buses seperate buses are used for data in/out 29 | o_data_bus_out : out std_logic_vector (7 downto 0); --No tri-state logic internally available on at IO pins 30 | o_reg_dbg_led : out std_logic_vector (7 downto 0) 31 | ); 32 | end component alu_register; 33 | 34 | begin 35 | 36 | UUT : alu_register 37 | port map( 38 | i_clkin => r_CLKIN, 39 | i_reset => r_RESET, 40 | i_we => r_WE, 41 | i_oe => r_OE, 42 | i_data_bus_in => r_DATA_BUS_IN, 43 | o_data_bus_out => r_DATA_BUS_OUT, 44 | o_reg_dbg_led => r_REG_DBG_LED 45 | ); 46 | 47 | p_clk_gen : process is 48 | begin 49 | wait for c_CLOCK_PERIOD/2; 50 | r_CLKIN <= not r_CLKIN; 51 | end process p_clk_gen; 52 | 53 | process 54 | begin 55 | 56 | r_DATA_BUS_IN <= "10101001"; 57 | 58 | --Testing if data is getting when needed 59 | wait for 5 ns; 60 | r_WE<='0'; 61 | wait for 20 ns; 62 | r_WE<='1'; 63 | 64 | --Testing if data is being output to the out bus 65 | wait for 5 ns; 66 | r_OE<='0'; 67 | wait for 20 ns; 68 | r_OE<='1'; 69 | 70 | wait for 5 ns; 71 | r_RESET <= '0'; 72 | wait for 20 ns; 73 | r_RESET <= '1'; 74 | 75 | wait for 1 ns; 76 | 77 | end process; 78 | end behaviour; 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /alu_tb.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | 3 | use ieee.std_logic_1164.all; 4 | use ieee.numeric_std.all; 5 | 6 | entity alu_tb is 7 | end entity alu_tb; 8 | 9 | architecture behaviour of alu_tb is 10 | 11 | signal r_EO : std_logic := '1'; 12 | signal r_SU : std_logic := '1'; 13 | signal r_A : std_logic_vector (7 downto 0) := (others => '0'); 14 | signal r_B : std_logic_vector (7 downto 0) := (others => '0'); 15 | signal r_CY : std_logic := '0'; 16 | signal r_ZR : std_logic := '0'; 17 | signal r_ALU_BUS_OUT : std_logic_vector (7 downto 0) := (others => '0'); 18 | signal r_ALU_DBG_OUT : std_logic_vector (7 downto 0) := (others => '0'); 19 | 20 | component alu is 21 | port( 22 | i_eo : in std_logic; --Output the result (Active low) 23 | i_su : in std_logic; --Subtraction when high and addition when low 24 | i_a : in std_logic_vector (7 downto 0); 25 | i_b : in std_logic_vector (7 downto 0); 26 | o_cy : out std_logic; 27 | o_zr : out std_logic; 28 | o_alu_bus_out : out std_logic_vector (7 downto 0); 29 | o_alu_dbg_led : out std_logic_vector(7 downto 0) 30 | ); 31 | end component alu; 32 | 33 | begin 34 | 35 | UUT : alu 36 | port map( 37 | i_eo => r_EO, 38 | i_su => r_SU, 39 | i_a => r_A, 40 | i_b => r_B, 41 | o_cy => r_CY, 42 | o_zr => r_ZR, 43 | o_alu_bus_out => r_ALU_BUS_OUT, 44 | o_alu_dbg_led => r_ALU_DBG_OUT 45 | ); 46 | 47 | process 48 | begin 49 | wait for 10 ns; 50 | r_A <= "00101111"; 51 | r_B <= "00100001"; 52 | wait for 10 ns; 53 | 54 | r_EO <= '0'; 55 | wait for 30 ns; 56 | r_EO <= '1'; 57 | 58 | wait for 10 ns; 59 | r_A <= "10010001"; 60 | r_B <= "10010011"; 61 | wait for 10 ns; 62 | 63 | r_EO <= '0'; 64 | wait for 10 ns; 65 | r_SU <= '0'; 66 | wait for 20 ns; 67 | r_SU <= '1'; 68 | r_EO <= '1'; 69 | 70 | wait for 10 ns; 71 | r_A <= "10010011"; 72 | r_B <= "10010011"; 73 | wait for 10 ns; 74 | 75 | r_EO <= '0'; 76 | wait for 10 ns; 77 | r_SU <= '0'; 78 | wait for 20 ns; 79 | r_SU <= '1'; 80 | r_EO <= '1'; 81 | 82 | wait; 83 | 84 | end process; 85 | 86 | end architecture behaviour; -------------------------------------------------------------------------------- /bin2bcd_8bit.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | 3 | use ieee.std_logic_1164.all; 4 | use ieee.numeric_std.all; 5 | 6 | entity bin2bcd_8bit is 7 | port( 8 | i_bin : in std_logic_vector(7 downto 0); 9 | i_disp_sig : in std_logic; --Whether signed or not (Active LOW, LOW -> SIGNED, HIGH -> UNSIGNED) 10 | o_sig : out std_logic; --Signal to say whether signed or not (Active LOW, LOW -> SIGNED, HIGH -> UNSIGNED) 11 | o_ones : out std_logic_vector(3 downto 0); 12 | o_tens : out std_logic_vector(3 downto 0); 13 | o_hundreds : out std_logic_vector(3 downto 0) 14 | ); 15 | end bin2bcd_8bit; 16 | 17 | architecture rtl of bin2bcd_8bit is 18 | 19 | begin 20 | 21 | --Just combinational logic 22 | 23 | p_bin2bcd : process(i_bin, i_disp_sig) --Double dable algorithm (Based on Wikipedia example) 24 | 25 | variable temp : std_logic_vector(7 downto 0); 26 | variable bcd : unsigned(11 downto 0) := (others => '0'); 27 | 28 | begin 29 | bcd := (others => '0'); --Initialize to zero 30 | 31 | if i_disp_sig = '0' and i_bin(7) = '1' then --If the display needs to be signed output check if the MSB is 1 32 | temp(7 downto 0) := std_logic_vector(unsigned(not i_bin)+1); --Read input into the temporary variable 33 | o_sig <= '1'; --Number is signed 34 | else 35 | temp(7 downto 0) := i_bin; 36 | o_sig <= '0'; 37 | end if; 38 | 39 | --Cycling 8 times for the 8 bits 40 | for i in 0 to 7 loop 41 | 42 | if bcd(3 downto 0) > 4 then 43 | bcd(3 downto 0) := bcd(3 downto 0) + 3; 44 | end if; 45 | 46 | if bcd(7 downto 4) > 4 then 47 | bcd(7 downto 4) := bcd(7 downto 4) + 3; 48 | end if; 49 | 50 | --Shift bcd left by 1 Bit and copy the MSB of temperory into LSB of BCD 51 | bcd := bcd(10 downto 0) & temp(7); -- Concatenation of the MSB of temperory 52 | 53 | --Shift temperory left by 1 Bit 54 | temp := temp(6 downto 0) & '0'; 55 | 56 | end loop; 57 | 58 | o_ones <= std_logic_vector(bcd(3 downto 0)); 59 | o_tens <= std_logic_vector(bcd(7 downto 4)); 60 | o_hundreds <= std_logic_vector(bcd(11 downto 8)); 61 | 62 | end process p_bin2bcd; 63 | 64 | end rtl; 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /bin2bcd_8bit_tb.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | 3 | use ieee.std_logic_1164.all; 4 | use ieee.numeric_std.all; 5 | 6 | entity bin2bcd_8bit_tb is 7 | end bin2bcd_8bit_tb; 8 | 9 | architecture behaviour of bin2bcd_8bit_tb is 10 | 11 | component bin2bcd_8bit is 12 | port( 13 | i_bin : in std_logic_vector(7 downto 0); 14 | i_disp_sig : in std_logic; 15 | o_sig : out std_logic; 16 | o_ones : out std_logic_vector(3 downto 0); 17 | o_tens : out std_logic_vector(3 downto 0); 18 | o_hundreds : out std_logic_vector(3 downto 0) 19 | ); 20 | end component bin2bcd_8bit; 21 | 22 | signal r_BIN : std_logic_vector(7 downto 0) := (others => '0'); 23 | signal r_DISP_SIG : std_logic := '1'; 24 | signal r_SIG : std_logic; 25 | signal r_ONES : std_logic_vector(3 downto 0); 26 | signal r_TENS : std_logic_vector(3 downto 0); 27 | signal r_HUNDEREDS : std_logic_vector(3 downto 0); 28 | 29 | begin 30 | 31 | UUT : bin2bcd_8bit 32 | port map( 33 | i_bin => r_BIN, 34 | i_disp_sig => r_DISP_SIG, 35 | o_sig => r_SIG, 36 | o_ones => r_ONES, 37 | o_tens => r_TENS, 38 | o_hundreds => r_HUNDEREDS 39 | ); 40 | 41 | process is 42 | begin 43 | 44 | r_BIN <= X"FF"; 45 | wait for 5 ns; 46 | 47 | r_BIN <= X"00"; 48 | wait for 5 ns; 49 | 50 | r_BIN <= X"BC"; 51 | wait for 5 ns; 52 | 53 | r_DISP_SIG <= '0'; 54 | r_BIN <= X"FF"; 55 | wait for 5 ns; 56 | 57 | r_BIN <= X"7F"; 58 | wait for 5 ns; 59 | 60 | r_BIN <= X"80"; 61 | wait for 5 ns; 62 | 63 | wait; 64 | end process; 65 | 66 | end behaviour; 67 | 68 | 69 | -------------------------------------------------------------------------------- /clock.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | 3 | use ieee.std_logic_1164.all; 4 | use ieee.numeric_std.all; 5 | 6 | entity clock is 7 | port( 8 | i_clkin : in std_logic; --This is the master clock 9 | i_man_clk : in std_logic; --Manual clock pulse generate button 10 | i_select : in std_logic; --Select between manual or master clock input 11 | i_sel_clk_freq : in std_logic_vector(1 downto 0); --Select the clock frequency 12 | i_halt : in std_logic; --To stop the clock programatically (Used internally) 13 | o_clkout : out std_logic; 14 | o_clk_freq_dbg_led : out std_logic_vector(1 downto 0) 15 | ); 16 | end clock; 17 | 18 | architecture rtl of clock is 19 | 20 | --To get the required constant frequency 21 | --50 MHz / 1Hz * 50% duty cycle = 25000000 counts 22 | --Should be reduced test bench 23 | constant c_CNT_1HZ : natural := 25000000; 24 | constant c_CNT_5HZ : natural := 5000000; 25 | constant c_CNT_10HZ : natural := 2500000; 26 | constant c_CNT_25HZ : natural := 1000000; 27 | 28 | --Maximum value is used for the range 29 | signal r_CNT_FREQ : natural range 0 to c_CNT_1HZ; --Counter used to generate the required clock 30 | signal r_COMP_CNT : natural range 0 to c_CNT_1HZ; --Register to hold the count to compare and generate the clock 31 | 32 | --Counter for the amount of time the pulse should last 33 | --f = 1/T = 1/0.1 = 10 Hz (For 100 ms pulse) 34 | --50 MHz / 10Hz = 5000000 35 | constant c_CLK_MAN_COUNT : natural := 5000000; --Should be reduced to 5 for TB 36 | signal r_MAN_PULSE_COUNTER : natural range 0 to c_CLK_MAN_COUNT; 37 | 38 | --Signal that will be toggled at the required frequency 39 | signal r_TOGGLE_CLK : std_logic := '0'; 40 | signal r_MAN_CLK_PULSE : std_logic := '0'; 41 | 42 | --Register to store the selection 43 | signal r_selection : std_logic := '0'; 44 | signal r_select_sw : std_logic := '0'; 45 | signal w_select_sw : std_logic; 46 | 47 | --Manual clocking signal 48 | signal w_man_clk_sw : std_logic; 49 | signal w_sel_clk_freq_sw : std_logic_vector(1 downto 0); 50 | 51 | type t_sm_main is (s_idle, s_pulse, s_stop); 52 | signal r_sm_main : t_sm_main := s_idle; 53 | 54 | --Debounce module is used for the different switches 55 | component debounce 56 | port( 57 | i_clk : in std_logic; 58 | i_switch : in std_logic; 59 | o_switch : out std_logic 60 | ); 61 | end component; 62 | 63 | begin 64 | 65 | select_debounce : debounce port map(i_clk=>i_clkin, i_switch=>i_select, o_switch=>w_select_sw); 66 | man_clk_debounce : debounce port map(i_clk=>i_clkin, i_switch=>i_man_clk, o_switch=>w_man_clk_sw); 67 | clk_freq_sel_lsb : debounce port map(i_clk=>i_clkin, i_switch=>i_sel_clk_freq(0),o_switch=>w_sel_clk_freq_sw(0)); 68 | clk_freq_sel_msb : debounce port map(i_clk=>i_clkin, i_switch=>i_sel_clk_freq(1),o_switch=>w_sel_clk_freq_sw(1)); 69 | 70 | --Process to generate clock form master clock 71 | p_gen_cpu_clk : process(i_clkin, w_sel_clk_freq_sw) is 72 | begin 73 | if rising_edge(i_clkin) then 74 | 75 | --Selecting the clock frequency 76 | case w_sel_clk_freq_sw is 77 | when "11" => r_COMP_CNT <= c_CNT_1HZ; 78 | when "10" => r_COMP_CNT <= c_CNT_5HZ; 79 | when "01" => r_COMP_CNT <= c_CNT_10HZ; 80 | when "00" => r_COMP_CNT <= c_CNT_25HZ; 81 | when others => r_COMP_CNT <= c_CNT_1HZ; 82 | end case; 83 | 84 | if r_CNT_FREQ = r_COMP_CNT-1 then 85 | r_TOGGLE_CLK <= not r_TOGGLE_CLK; 86 | r_CNT_FREQ <= 0; 87 | else 88 | r_CNT_FREQ <= r_CNT_FREQ+1; 89 | end if; 90 | end if; 91 | end process p_gen_cpu_clk; 92 | 93 | --Process for clock type selection (Select is active low) 94 | p_select : process(i_clkin) is 95 | begin 96 | if rising_edge(i_clkin) then 97 | r_select_sw <= w_select_sw; --Shift the button value in 98 | 99 | --Looking for a falling edge looking at the current and previous state in the register 100 | if w_select_sw = '0' and r_select_sw = '1' then 101 | r_selection <= not r_selection; --Toggling the selection register 102 | end if; 103 | end if; 104 | end process p_select; 105 | 106 | p_man_clk : process(i_clkin) is 107 | begin 108 | if rising_edge(i_clkin) then 109 | 110 | case r_sm_main is 111 | 112 | when s_idle => --Starting 113 | r_MAN_CLK_PULSE <= '0'; 114 | r_MAN_PULSE_COUNTER <= 0; 115 | 116 | if w_man_clk_sw = '0' then 117 | r_sm_main <= s_pulse; 118 | r_MAN_CLK_PULSE <= '1'; --Clock line is set high 119 | else 120 | r_sm_main <= s_idle; 121 | end if; 122 | 123 | when s_pulse => --Pulse of required length 124 | if r_MAN_PULSE_COUNTER = c_CLK_MAN_COUNT-2 then 125 | r_MAN_CLK_PULSE <= '0'; --Clock line is set low 126 | r_sm_main <= s_stop; 127 | else 128 | r_MAN_PULSE_COUNTER <= r_MAN_PULSE_COUNTER+1; 129 | end if; 130 | 131 | when s_stop => --Clock pulsing is completed 132 | if w_man_clk_sw = '1' then --If the manual pulse button is released 133 | r_sm_main <= s_idle; --Set the state to idle 134 | else 135 | r_sm_main <= s_stop; 136 | end if; 137 | 138 | when others => --Default case 139 | r_sm_main <= s_idle; 140 | 141 | end case; 142 | end if; 143 | end process p_man_clk; 144 | 145 | --The final clock output 146 | o_clkout <= r_TOGGLE_CLK when (r_selection = '0' and i_halt = '1') else 147 | r_MAN_CLK_PULSE when (r_selection = '1' and i_halt = '1') else 148 | '0'; --Halt if the above condtions are not met (LED will be HIGH because of pull up) 149 | 150 | o_clk_freq_dbg_led <= w_sel_clk_freq_sw; 151 | 152 | end rtl; -------------------------------------------------------------------------------- /clock_tb.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | 3 | use ieee.std_logic_1164.all; 4 | use ieee.numeric_std.all; 5 | 6 | entity clock_tb is 7 | end clock_tb; 8 | 9 | architecture behaviour of clock_tb is 10 | 11 | --Period of 50 MHz master clock 12 | constant c_CLOCK_PERIOD : time := 20 ns; 13 | 14 | signal r_CLOCKIN : std_logic := '0'; 15 | signal r_MAN_CLK : std_logic := '1'; 16 | signal r_SELECT : std_logic := '1'; -- 1 means not active 17 | signal r_HALT : std_logic := '1'; 18 | signal r_CLKOUT : std_logic; 19 | 20 | component clock is 21 | port( 22 | i_clkin : in std_logic; 23 | i_man_clk : in std_logic; 24 | i_select : in std_logic; 25 | i_halt : in std_logic; 26 | o_clkout : out std_logic 27 | ); 28 | end component clock; 29 | 30 | begin 31 | 32 | --Unit Under Test 33 | UUT : clock 34 | port map( 35 | i_clkin => r_CLOCKIN, 36 | i_man_clk => r_MAN_CLK, 37 | i_select => r_SELECT, 38 | i_halt => r_HALT, 39 | o_clkout => r_CLKOUT 40 | ); 41 | 42 | p_CLK_GEN : process is 43 | begin 44 | wait for c_CLOCK_PERIOD/2; 45 | r_CLOCKIN <= not r_CLOCKIN; 46 | end process p_CLK_GEN; 47 | 48 | --Main testing section 49 | process 50 | begin 51 | 52 | wait; 53 | 54 | end process; 55 | 56 | end behaviour; 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /debounce.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | 3 | use ieee.std_logic_1164.all; 4 | use ieee.numeric_std.all; 5 | 6 | entity debounce is 7 | port( 8 | i_clk : in std_logic; 9 | i_switch : in std_logic; 10 | o_switch : out std_logic 11 | ); 12 | end entity debounce; 13 | 14 | architecture rtl of debounce is 15 | 16 | --500000 clock ticks for 10 ms delay at 50MHz master clock 17 | constant c_DEBOUNCE_LIMIT : integer := 500000; --Should be reduced to 2 for TB 18 | 19 | signal r_count : integer range 0 to c_DEBOUNCE_LIMIT := 0; 20 | signal r_state : std_logic := '0'; 21 | 22 | begin 23 | 24 | p_debounce : process(i_clk) is 25 | begin 26 | if rising_edge(i_clk) then 27 | 28 | --Switch bouncing is checked by checking the internal state and the actual switch value 29 | if(i_switch /= r_state and r_count < c_DEBOUNCE_LIMIT) then 30 | r_count <= r_count + 1; 31 | 32 | --Switch is stable and can be register and the counter reset 33 | elsif r_count = c_DEBOUNCE_LIMIT then 34 | r_state <= i_switch; 35 | r_count <= 0; 36 | 37 | else 38 | r_count <= 0; 39 | 40 | end if; 41 | end if; 42 | end process p_debounce; 43 | 44 | --The final debounced switch value is output here 45 | o_switch <= r_state; 46 | 47 | end architecture rtl; -------------------------------------------------------------------------------- /debugger_led.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | 3 | use ieee.std_logic_1164.all; 4 | use ieee.numeric_std.all; 5 | 6 | entity debugger_led is 7 | port( 8 | i_mclk : in std_logic; 9 | i_pc_dbg : in std_logic_vector(3 downto 0); 10 | i_a_reg_dbg : in std_logic_vector(7 downto 0); 11 | i_alu_reg_dbg : in std_logic_vector(7 downto 0); 12 | i_flags_reg_dbg : in std_logic_vector(1 downto 0); 13 | i_b_reg_dbg : in std_logic_vector(7 downto 0); 14 | i_mem_addr_dbg : in std_logic_vector(3 downto 0); 15 | i_ram_content_dbg : in std_logic_vector(7 downto 0); 16 | i_inst_reg_dbg : in std_logic_vector(7 downto 0); 17 | i_inst_step_dbg : in std_logic_vector(2 downto 0); 18 | i_ctrl_word_dbg : in std_logic_vector(15 downto 0); 19 | i_bus_dbg : in std_logic_vector(7 downto 0); 20 | o_muxed_dbg_led_bus : out std_logic_vector(7 downto 0) := (others => '0'); 21 | o_act_led_bus : out std_logic_vector(11 downto 0) := (others => '0') 22 | ); 23 | end entity debugger_led; 24 | 25 | architecture rtl of debugger_led is 26 | 27 | --Required count = 22500 28 | constant c_REFRESH_DBG_LEDS : natural := 22500; 29 | signal r_REFRESH_DBG_COUNTER : natural range 0 to c_REFRESH_DBG_LEDS := 0; 30 | 31 | constant c_MAX_REFRESH_ITEMS : natural := 12; --The number of items to be refreshed 32 | signal r_REFRESH_ITEM : natural range 0 to c_MAX_REFRESH_ITEMS := 0; --Register to keep track of what item is being updated 33 | signal r_CUR_ITEM : std_logic_vector(11 downto 0) := "000000000001"; 34 | 35 | begin 36 | 37 | p_refresh_items : process(i_mclk) is 38 | begin 39 | if rising_edge(i_mclk) then 40 | if r_REFRESH_DBG_COUNTER = c_REFRESH_DBG_LEDS-1 then 41 | 42 | if r_REFRESH_ITEM = c_MAX_REFRESH_ITEMS-1 then 43 | r_REFRESH_ITEM <= 0; --Reset the current item to 0 44 | r_CUR_ITEM <= "000000000001"; --Reset the activation to the first item 45 | else 46 | r_REFRESH_ITEM <= r_REFRESH_ITEM+1; 47 | end if; 48 | 49 | r_REFRESH_DBG_COUNTER <= 0; --Reset the refresh counter 50 | 51 | --Refreshing each of the items in sequence 52 | case r_REFRESH_ITEM is 53 | when 0 => 54 | o_act_led_bus <= r_CUR_ITEM; 55 | o_muxed_dbg_led_bus(3 downto 0) <= i_pc_dbg; 56 | when 1 => 57 | o_act_led_bus <= std_logic_vector(shift_left(unsigned(r_CUR_ITEM),1)); 58 | o_muxed_dbg_led_bus(7 downto 0) <= i_a_reg_dbg; 59 | when 2 => 60 | o_act_led_bus <= std_logic_vector(shift_left(unsigned(r_CUR_ITEM),2)); 61 | o_muxed_dbg_led_bus(7 downto 0) <= i_alu_reg_dbg; 62 | when 3 => 63 | o_act_led_bus <= std_logic_vector(shift_left(unsigned(r_CUR_ITEM),3)); 64 | o_muxed_dbg_led_bus(1 downto 0) <= i_flags_reg_dbg; 65 | when 4 => 66 | o_act_led_bus <= std_logic_vector(shift_left(unsigned(r_CUR_ITEM),4)); 67 | o_muxed_dbg_led_bus(7 downto 0) <= i_b_reg_dbg; 68 | when 5 => 69 | o_act_led_bus <= std_logic_vector(shift_left(unsigned(r_CUR_ITEM),5)); 70 | o_muxed_dbg_led_bus(3 downto 0) <= i_mem_addr_dbg; 71 | when 6 => 72 | o_act_led_bus <= std_logic_vector(shift_left(unsigned(r_CUR_ITEM),6)); 73 | o_muxed_dbg_led_bus(7 downto 0) <= i_ram_content_dbg; 74 | when 7 => 75 | o_act_led_bus <= std_logic_vector(shift_left(unsigned(r_CUR_ITEM),7)); 76 | o_muxed_dbg_led_bus(7 downto 0) <= i_inst_reg_dbg; 77 | when 8 => 78 | o_act_led_bus <= std_logic_vector(shift_left(unsigned(r_CUR_ITEM),8)); 79 | o_muxed_dbg_led_bus(2 downto 0) <= i_inst_step_dbg; 80 | when 9 => 81 | o_act_led_bus <= std_logic_vector(shift_left(unsigned(r_CUR_ITEM),9)); 82 | o_muxed_dbg_led_bus(7 downto 0) <= i_ctrl_word_dbg(7 downto 0); 83 | when 10 => 84 | o_act_led_bus <= std_logic_vector(shift_left(unsigned(r_CUR_ITEM),10)); 85 | o_muxed_dbg_led_bus(7 downto 0) <= i_ctrl_word_dbg(15 downto 8); 86 | when 11 => 87 | o_act_led_bus <= std_logic_vector(shift_left(unsigned(r_CUR_ITEM),11)); 88 | o_muxed_dbg_led_bus(7 downto 0) <= i_bus_dbg; 89 | when others => 90 | o_act_led_bus <= "000000000000"; 91 | end case; 92 | 93 | else 94 | r_REFRESH_DBG_COUNTER <= r_REFRESH_DBG_COUNTER+1; --Incrementing the refresh counter 95 | end if; 96 | end if; 97 | end process p_refresh_items; 98 | 99 | end rtl; -------------------------------------------------------------------------------- /debugger_led_tb.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | 3 | use ieee.std_logic_1164.all; 4 | use ieee.numeric_std.all; 5 | 6 | entity debugger_led_tb is 7 | end entity debugger_led_tb; 8 | 9 | architecture behaviour of debugger_led_tb is 10 | 11 | constant c_CLK_PERIOD : time := 20 ns; 12 | 13 | signal r_MCLK : std_logic := '0'; 14 | signal r_PC_BDG : std_logic_vector(3 downto 0) := "1011"; 15 | signal r_A_REG_DBG : std_logic_vector(7 downto 0) := "11011011"; 16 | signal r_ALU_REG_DBG : std_logic_vector(7 downto 0) := "10010011"; 17 | signal r_FLAGS_REG_DBG : std_logic_vector(1 downto 0) := "10"; 18 | signal r_B_REG_DBG : std_logic_vector(7 downto 0) := "10100101"; 19 | signal r_MEM_ADDR_DBG : std_logic_vector(3 downto 0) := "1001"; 20 | signal r_RAM_CONTENT_DBG : std_logic_vector(7 downto 0) := "11110011"; 21 | signal r_INST_REG_DBG : std_logic_vector(7 downto 0) := "11001111"; 22 | signal r_INST_STEP_DBG : std_logic_vector(2 downto 0) := "101"; 23 | signal r_CTRL_WORD_DBG : std_logic_vector(15 downto 0) := "1110111100001111"; 24 | signal r_BUS_DBG : std_logic_vector(7 downto 0) := "10111101"; 25 | signal r_MUXED_DBG_LED_BUS : std_logic_vector(7 downto 0); 26 | signal r_ACT_LED_BUS : std_logic_vector(11 downto 0); 27 | 28 | component debugger_led is 29 | port( 30 | i_mclk : in std_logic; 31 | i_pc_dbg : in std_logic_vector(3 downto 0); 32 | i_a_reg_dbg : in std_logic_vector(7 downto 0); 33 | i_alu_reg_dbg : in std_logic_vector(7 downto 0); 34 | i_flags_reg_dbg : in std_logic_vector(1 downto 0); 35 | i_b_reg_dbg : in std_logic_vector(7 downto 0); 36 | i_mem_addr_dbg : in std_logic_vector(3 downto 0); 37 | i_ram_content_dbg : in std_logic_vector(7 downto 0); 38 | i_inst_reg_dbg : in std_logic_vector(7 downto 0); 39 | i_inst_step_dbg : in std_logic_vector(2 downto 0); 40 | i_ctrl_word_dbg : in std_logic_vector(15 downto 0); 41 | i_bus_dbg : in std_logic_vector(7 downto 0); 42 | o_muxed_dbg_led_bus : out std_logic_vector(7 downto 0) := (others => '0'); 43 | o_act_led_bus : out std_logic_vector(11 downto 0) := (others => '0') 44 | ); 45 | end component debugger_led; 46 | 47 | begin 48 | 49 | p_clk_gen : process is 50 | begin 51 | wait for c_CLK_PERIOD/2; 52 | r_MCLK <= not r_MCLK; 53 | end process p_clk_gen; 54 | 55 | UUT : debugger_led 56 | port map( 57 | i_mclk => r_MCLK, 58 | i_pc_dbg => r_PC_BDG, 59 | i_a_reg_dbg => r_A_REG_DBG, 60 | i_alu_reg_dbg => r_ALU_REG_DBG, 61 | i_flags_reg_dbg => r_FLAGS_REG_DBG, 62 | i_b_reg_dbg => r_B_REG_DBG, 63 | i_mem_addr_dbg => r_MEM_ADDR_DBG, 64 | i_ram_content_dbg => r_RAM_CONTENT_DBG, 65 | i_inst_reg_dbg => r_INST_REG_DBG, 66 | i_inst_step_dbg => r_INST_STEP_DBG, 67 | i_ctrl_word_dbg => r_CTRL_WORD_DBG, 68 | i_bus_dbg => r_BUS_DBG, 69 | o_muxed_dbg_led_bus => r_MUXED_DBG_LED_BUS, 70 | o_act_led_bus => r_ACT_LED_BUS 71 | ); 72 | 73 | process 74 | begin 75 | 76 | wait for 10 ns; 77 | 78 | end process; 79 | 80 | end behaviour; 81 | 82 | -------------------------------------------------------------------------------- /display_7_segment.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | 3 | use ieee.std_logic_1164.all; 4 | use ieee.numeric_std.all; 5 | 6 | entity display_7_segment is 7 | port( 8 | i_mclk : in std_logic; --Master clock input 9 | i_clkin : in std_logic; --The system clock 10 | i_reset : in std_logic; --Reset the qutput register 11 | i_we : in std_logic; --Output register in (Active LOW) 12 | i_display_signed : in std_logic; 13 | i_data_bus_in : in std_logic_vector(7 downto 0); 14 | o_dig : out std_logic_vector(3 downto 0) := (others => '1'); --Selection for each digit of the 4 digit display (Active LOW) 15 | o_segment_drive : out std_logic_vector(7 downto 0) := (others => '1') --7 segment display drive (Active LOW) 16 | ); 17 | end entity display_7_segment; 18 | 19 | architecture rtl of display_7_segment is 20 | 21 | --7 segment display refresh logic 22 | constant c_REFRESH_DISP_CNT : natural := 200000; --125Hz refresh (Count 200000) 23 | constant c_MAX_REFRESH_DIGIT : natural := 4; --4 different 7 segment display 24 | 25 | --A counter is needed for the diplay refresh 26 | signal r_REFRESH_DISP_CNT : natural range 0 to c_REFRESH_DISP_CNT; 27 | 28 | --This register holds which digit of the display is getting updated 29 | signal r_REFRESH_DIGIT : natural range 0 to c_MAX_REFRESH_DIGIT; 30 | 31 | signal r_DIG0_SEG : std_logic_vector(7 downto 0) := (others=>'0'); 32 | signal r_DIG1_SEG : std_logic_vector(7 downto 0) := (others=>'0'); 33 | signal r_DIG2_SEG : std_logic_vector(7 downto 0) := (others=>'0'); 34 | signal r_DIG3_SEG : std_logic_vector(7 downto 0) := (others=>'0'); 35 | 36 | --Register to hold the result to display 37 | signal r_OUTPUT_REG : std_logic_vector(7 downto 0) := (others => '0'); 38 | 39 | --Registers for ones, tens and hundreds 40 | signal r_ONES : std_logic_vector(3 downto 0) := (others => '0'); 41 | signal r_TENS : std_logic_vector(3 downto 0) := (others => '0'); 42 | signal r_HUNDREDS : std_logic_vector(3 downto 0) := (others => '0'); 43 | signal r_SIGN : std_logic := '0'; 44 | 45 | --Function that contains the logic to convert binary to 7 segment display 46 | function f_4_BIT_BCD2SEG_DISP(r_BIN_IN: in std_logic_vector(3 downto 0)) 47 | return std_logic_vector is --Return type 48 | variable v_DISP_PATTERN : std_logic_vector(7 downto 0); --Actual return is 8 Bit vector 49 | 50 | begin --Function definition begins 51 | 52 | case r_BIN_IN is --Case statement to convert Binary to 7 segment output 53 | when "0000" => --0 54 | v_DISP_PATTERN := not "00111111"; 55 | when "0001" => --1 56 | v_DISP_PATTERN := not "00000110"; 57 | when "0010" => --2 58 | v_DISP_PATTERN := not "01011011"; 59 | when "0011" => --3 60 | v_DISP_PATTERN := not "01001111"; 61 | when "0100" => --4 62 | v_DISP_PATTERN := not "01100110"; 63 | when "0101" => --5 64 | v_DISP_PATTERN := not "01101101"; 65 | when "0110" => --6 66 | v_DISP_PATTERN := not "01111101"; 67 | when "0111" => --7 68 | v_DISP_PATTERN := not "00000111"; 69 | when "1000" => --8 70 | v_DISP_PATTERN := not "01111111"; 71 | when "1001" => --9 72 | v_DISP_PATTERN := not "01100111"; 73 | when others => --Undefined 74 | v_DISP_PATTERN := not "00000000"; 75 | end case; 76 | 77 | return std_logic_vector(v_DISP_PATTERN); 78 | end function f_4_BIT_BCD2SEG_DISP; 79 | 80 | component bin2bcd_8bit 81 | port( 82 | i_bin : in std_logic_vector(7 downto 0); 83 | i_disp_sig : in std_logic; --Whether signed or not (Active LOW, LOW -> SIGNED, HIGH -> UNSIGNED) 84 | o_sig : out std_logic; --Signal to say whether signed or not (Active LOW, LOW -> SIGNED, HIGH -> UNSIGNED) 85 | o_ones : out std_logic_vector(3 downto 0); 86 | o_tens : out std_logic_vector(3 downto 0); 87 | o_hundreds : out std_logic_vector(3 downto 0) 88 | ); 89 | end component bin2bcd_8bit; 90 | 91 | begin 92 | 93 | bin2bcd : bin2bcd_8bit 94 | port map( 95 | i_bin => r_OUTPUT_REG, 96 | i_disp_sig => i_display_signed, 97 | o_sig => r_SIGN, 98 | o_ones => r_ONES, 99 | o_tens => r_TENS, 100 | o_hundreds => r_HUNDREDS 101 | ); 102 | 103 | --Process to store the output in a register to display 104 | p_output : process(i_clkin,i_reset) is 105 | begin 106 | if i_reset = '0' then 107 | r_OUTPUT_REG <= (others => '0'); 108 | elsif rising_edge(i_clkin) then 109 | if i_we = '0' then 110 | r_OUTPUT_REG <= i_data_bus_in; 111 | end if; 112 | end if; 113 | end process p_output; 114 | 115 | 116 | p_REFRESH_DISP: process(i_mclk) is 117 | begin 118 | if rising_edge(i_mclk) then 119 | if r_REFRESH_DISP_CNT = c_REFRESH_DISP_CNT-1 then --If the refresh count is reached 120 | 121 | if r_REFRESH_DIGIT = c_MAX_REFRESH_DIGIT-1 then --If max digit is reached 122 | r_REFRESH_DIGIT<=0; --Reset to the 0th digit 123 | else 124 | r_REFRESH_DIGIT<=r_REFRESH_DIGIT+1; --Increment the digit display counter 125 | end if; 126 | 127 | r_DIG0_SEG <= f_4_BIT_BCD2SEG_DISP(r_ONES); 128 | r_DIG1_SEG <= f_4_BIT_BCD2SEG_DISP(r_TENS); 129 | r_DIG2_SEG <= f_4_BIT_BCD2SEG_DISP(r_HUNDREDS); 130 | 131 | if r_SIGN = '1' and i_display_signed = '0' then --Active low therefore signed numbers are used 132 | r_DIG3_SEG <= not "01000000"; 133 | else 134 | r_DIG3_SEG <= not "00000000"; --Turn the 7 segment completely off 135 | end if; 136 | 137 | 138 | r_REFRESH_DISP_CNT<=0; --Reset the refresh counter 139 | 140 | case r_REFRESH_DIGIT is --Updating the display 141 | when 0 => --Update digit 1 142 | o_dig <= not "1000"; 143 | o_segment_drive<=r_DIG0_SEG; 144 | when 1 => --Update digit 2 145 | o_dig <= not "0100"; 146 | o_segment_drive<=r_DIG1_SEG; 147 | when 2 => --Update digit 3 148 | o_dig <= not "0010"; 149 | o_segment_drive<=r_DIG2_SEG; 150 | when 3 => --Update digit 4 151 | o_dig <= not "0001"; 152 | o_segment_drive<=r_DIG3_SEG; 153 | when others => --Invalid case 154 | o_dig <= not "0000"; 155 | end case; 156 | 157 | else 158 | r_REFRESH_DISP_CNT<=r_REFRESH_DISP_CNT+1; --Increment the refresh counter 159 | end if; 160 | end if; 161 | end process p_REFRESH_DISP; 162 | 163 | end rtl; -------------------------------------------------------------------------------- /display_7_segment_tb.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | 3 | use ieee.std_logic_1164.all; 4 | use ieee.numeric_std.all; 5 | 6 | entity display_7_segment_tb is 7 | end entity display_7_segment_tb; 8 | 9 | architecture behaviour of display_7_segment_tb is 10 | 11 | --50MHz = 20 ns period 12 | constant c_CLK_PERIOD : time := 20 ns; 13 | 14 | signal r_MCLK : std_logic := '0'; 15 | signal r_CLKIN : std_logic := '0'; 16 | signal r_RESET : std_logic := '1'; 17 | signal r_WE : std_logic := '1'; 18 | signal r_DISPLAY_SIGNED : std_logic := '1'; 19 | signal r_DATA_BUS_IN : std_logic_vector(7 downto 0) := (others => '0'); 20 | signal r_DIG : std_logic_vector(3 downto 0); 21 | signal r_SEGMENT_DRIVE : std_logic_vector(7 downto 0); 22 | 23 | component display_7_segment is 24 | port( 25 | i_mclk : in std_logic; --Master clock input 26 | i_clkin : in std_logic; --The system clock 27 | i_reset : in std_logic; 28 | i_we : in std_logic; --Output register in (Active LOW) 29 | i_display_signed : in std_logic; 30 | i_data_bus_in : in std_logic_vector(7 downto 0); 31 | o_dig : out std_logic_vector(3 downto 0); --Selection for each digit of the 4 digit display 32 | o_segment_drive : out std_logic_vector(7 downto 0) --7 segment display drive 33 | ); 34 | end component display_7_segment; 35 | 36 | begin 37 | 38 | UUT : display_7_segment 39 | port map( 40 | i_mclk => r_MCLK, 41 | i_reset => r_RESET, 42 | i_clkin => r_CLKIN, 43 | i_we => r_WE, 44 | i_display_signed => r_DISPLAY_SIGNED, 45 | i_data_bus_in => r_DATA_BUS_IN, 46 | o_dig => r_DIG, 47 | o_segment_drive => r_SEGMENT_DRIVE 48 | ); 49 | 50 | p_clk_gen : process is 51 | begin 52 | wait for c_CLK_PERIOD/2; 53 | r_MCLK <= not r_MCLK; 54 | end process p_clk_gen; 55 | 56 | process 57 | begin 58 | 59 | r_DATA_BUS_IN <= X"FF"; 60 | r_DISPLAY_SIGNED <= '0'; 61 | wait for 5 ns; 62 | r_WE <= '0'; 63 | wait for 5 ns; 64 | r_CLKIN <= '1'; 65 | wait for 5 ns; 66 | r_CLKIN <= '0'; 67 | r_WE <= '1'; 68 | 69 | --Reset 70 | wait for 310 ns; 71 | r_RESET <= '0'; 72 | wait for 5 ns; 73 | r_RESET <= '1'; 74 | 75 | r_DATA_BUS_IN <= X"FF"; 76 | r_DISPLAY_SIGNED <= '1'; 77 | wait for 5 ns; 78 | r_WE <= '0'; 79 | wait for 5 ns; 80 | r_CLKIN <= '1'; 81 | wait for 5 ns; 82 | r_CLKIN <= '0'; 83 | r_WE <= '1'; 84 | 85 | wait; 86 | 87 | end process; 88 | end behaviour; 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /flags_reg.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | 3 | use ieee.std_logic_1164.all; 4 | 5 | entity flags_reg is 6 | port( 7 | i_clkin : in std_logic; 8 | i_reset : in std_logic; 9 | i_cb : in std_logic; --Carry bit 10 | i_zb : in std_logic; --Zero bit 11 | i_we : in std_logic; --Write to flags register(Active LOW) 12 | o_flags : out std_logic_vector(1 downto 0); 13 | o_flags_dbg_led : out std_logic_vector(1 downto 0) 14 | ); 15 | end entity flags_reg; 16 | 17 | architecture rtl of flags_reg is 18 | 19 | --Flags register arrangement 20 | --1 0 21 | --Z C 22 | --F F 23 | 24 | signal r_flags_reg : std_logic_vector(1 downto 0) := (others => '0'); 25 | 26 | begin 27 | 28 | p_flag_set : process(i_clkin,i_reset) is 29 | begin 30 | if i_reset = '0' then 31 | r_flags_reg <= (others => '0'); 32 | elsif rising_edge(i_clkin) then 33 | if i_we = '0' then 34 | r_flags_reg(0) <= i_cb; 35 | r_flags_reg(1) <= i_zb; 36 | end if; 37 | end if; 38 | end process p_flag_set; 39 | 40 | --Output the flags 41 | o_flags <= r_flags_reg; 42 | 43 | --For debug LEDs 44 | o_flags_dbg_led <= r_flags_reg; 45 | 46 | end rtl; 47 | 48 | 49 | -------------------------------------------------------------------------------- /flags_reg_tb.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | 3 | use ieee.std_logic_1164.all; 4 | 5 | entity flags_reg_tb is 6 | end entity flags_reg_tb; 7 | 8 | architecture behaviour of flags_reg_tb is 9 | 10 | signal r_CLKIN : std_logic := '0'; 11 | signal r_RESET : std_logic := '1'; 12 | signal r_CB : std_logic := '0'; 13 | signal r_ZB : std_logic := '0'; 14 | signal r_WE : std_logic := '1'; 15 | signal r_FLAGS : std_logic_vector(1 downto 0) := (others =>'0'); 16 | signal r_FLAGS_DBG_LED : std_logic_vector(1 downto 0) := (others => '0'); 17 | 18 | component flags_reg is 19 | port( 20 | i_clkin : in std_logic; 21 | i_reset : in std_logic; 22 | i_cb : in std_logic; --Carry bit 23 | i_zb : in std_logic; --Zero bit 24 | i_we : in std_logic; --Write to flags register(Active LOW) 25 | o_flags : out std_logic_vector(1 downto 0); 26 | o_flags_dbg_led : out std_logic_vector(1 downto 0) 27 | ); 28 | end component flags_reg; 29 | 30 | begin 31 | 32 | UUT : flags_reg 33 | port map( 34 | i_clkin => r_CLKIN, 35 | i_reset => r_RESET, 36 | i_cb => r_CB, 37 | i_zb => r_ZB, 38 | i_we => r_WE, 39 | o_flags => r_FLAGS, 40 | o_flags_dbg_led => r_FLAGS_DBG_LED 41 | ); 42 | 43 | process 44 | begin 45 | 46 | r_CB <= '1'; 47 | r_WE <= '0'; 48 | wait for 10 ns; 49 | r_CLKIN <= '1'; 50 | wait for 10 ns; 51 | r_CLKIN <= '0'; 52 | 53 | wait for 10 ns; 54 | 55 | r_ZB <= '1'; 56 | r_WE <= '0'; 57 | wait for 10 ns; 58 | r_CLKIN <= '1'; 59 | wait for 10 ns; 60 | r_CLKIN <= '0'; 61 | 62 | wait for 10 ns; 63 | 64 | r_RESET <= '0'; 65 | wait for 10 ns; 66 | r_RESET <= '1'; 67 | 68 | wait; 69 | 70 | end process; 71 | end behaviour; -------------------------------------------------------------------------------- /instruction_decoder.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | 3 | use ieee.std_logic_1164.all; 4 | use ieee.numeric_std.all; 5 | 6 | entity instruction_decoder is 7 | port( 8 | i_clkin : in std_logic; 9 | i_reset : in std_logic; 10 | i_instruction : in std_logic_vector(3 downto 0); 11 | i_flags : in std_logic_vector(1 downto 0); 12 | o_hlt : out std_logic; 13 | o_mi : out std_logic; 14 | o_ri : out std_logic; 15 | o_ro : out std_logic; 16 | o_io : out std_logic; 17 | o_ii : out std_logic; 18 | o_ai : out std_logic; 19 | o_ao : out std_logic; 20 | o_eps : out std_logic; 21 | o_su : out std_logic; 22 | o_bi : out std_logic; 23 | o_bo : out std_logic; 24 | o_oi : out std_logic; 25 | o_ce : out std_logic; 26 | o_co : out std_logic; 27 | o_j : out std_logic; 28 | o_fi : out std_logic; 29 | o_inv_clk : out std_logic; 30 | o_inst_step_dbg_led : out std_logic_vector(2 downto 0); 31 | o_ctrl_word_dbg_led : out std_logic_vector(15 downto 0) 32 | ); 33 | end entity instruction_decoder; 34 | 35 | architecture rtl of instruction_decoder is 36 | 37 | constant c_INST_MAX_COUNT : natural := 5; --Maximum of 5 microinstruction steps per instrunction 38 | signal r_INST_STEP_COUNTER : natural range 0 to c_INST_MAX_COUNT; 39 | 40 | --The 16 Bits of the control word are arranged in the following word 41 | --15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 42 | --H M R R I I A A E S B O C C J F 43 | --L I I 0 0 I I 0 0 U I I E O - I 44 | --T - - - - - - - - - - - - - - - 45 | 46 | --Single microcode 47 | subtype t_microcode is std_logic_vector(15 downto 0); 48 | constant c_DFT : t_microcode := "0000000000000000"; --Default when no case match is found 49 | constant c_HLT : t_microcode := "1000000000000000"; 50 | constant c_MI : t_microcode := "0100000000000000"; 51 | constant c_RI : t_microcode := "0010000000000000"; 52 | constant c_RO : t_microcode := "0001000000000000"; 53 | constant c_IO : t_microcode := "0000100000000000"; 54 | constant c_II : t_microcode := "0000010000000000"; 55 | constant c_AI : t_microcode := "0000001000000000"; 56 | constant c_AO : t_microcode := "0000000100000000"; 57 | constant c_EO : t_microcode := "0000000010000000"; 58 | constant c_SU : t_microcode := "0000000001000000"; 59 | constant c_BI : t_microcode := "0000000000100000"; 60 | constant c_OI : t_microcode := "0000000000010000"; 61 | constant c_CE : t_microcode := "0000000000001000"; 62 | constant c_CO : t_microcode := "0000000000000100"; 63 | constant c_J : t_microcode := "0000000000000010"; 64 | constant c_FI : t_microcode := "0000000000000001"; 65 | 66 | --Timestep 67 | subtype t_timestep is std_logic_vector(2 downto 0); 68 | constant c_T0 : t_timestep := "000"; 69 | constant c_T1 : t_timestep := "001"; 70 | constant c_T2 : t_timestep := "010"; 71 | constant c_T3 : t_timestep := "011"; 72 | constant c_T4 : t_timestep := "100"; 73 | 74 | --Instructions (OP codes) 75 | subtype t_instruction is std_logic_vector(3 downto 0); 76 | constant c_NOP : t_instruction := "0000"; --No OPeration 77 | constant c_LDA : t_instruction := "0001"; --Load Register A 78 | constant c_ADD : t_instruction := "0010"; --ADDition 79 | constant c_SUB : t_instruction := "0011"; --SUBtraction 80 | constant c_STA : t_instruction := "0100"; --STore A to RAM 81 | constant c_LDI : t_instruction := "0101"; --LoaD Immediate (Put a value directly into A register) 82 | constant c_JMP : t_instruction := "0110"; --JuMP to a different address in RAM 83 | constant c_JC : t_instruction := "0111"; --Jump on Carry 84 | constant c_JZ : t_instruction := "1000"; --Jump on Zero 85 | constant c_OUT : t_instruction := "1110"; --OUTput result 86 | constant c_HALT : t_instruction := "1111"; --HALT clock 87 | 88 | signal w_inv_clk : std_logic; --The inverted clock 89 | signal w_inst_step : std_logic_vector(2 downto 0); --The current microstep for the instruction 90 | 91 | --Control word that is broken into the different control signals 92 | signal w_control_word : std_logic_vector(15 downto 0); 93 | 94 | function f_INST_DECODER(w_INSTRUCTION : in std_logic_vector(3 downto 0); w_INST_STEP : in std_logic_vector(2 downto 0); w_FLAGS : in std_logic_vector(1 downto 0)) 95 | return std_logic_vector is 96 | variable v_CONTROL_WORD : std_logic_vector(15 downto 0); --Control lines are active low 97 | variable v_CF : std_logic; 98 | variable v_ZF : std_logic; 99 | 100 | begin 101 | 102 | v_CF := w_FLAGS(0); 103 | v_ZF := w_FLAGS(1); 104 | 105 | --Fetch instruction needs to be run for all the instrunctions 106 | case w_INST_STEP is 107 | when c_T0 => v_CONTROL_WORD := not (c_MI or c_CO); 108 | when c_T1 => v_CONTROL_WORD := not (c_RO or c_II or c_CE); 109 | when others => 110 | case w_INSTRUCTION is 111 | when c_NOP => --NOP instruction 112 | v_CONTROL_WORD := not c_DFT; 113 | 114 | when c_LDA => --LDA instruction 115 | case w_INST_STEP is 116 | when c_T2 => v_CONTROL_WORD := not (c_MI or c_IO); 117 | when c_T3 => v_CONTROL_WORD := not (c_RO or c_AI); 118 | when others => v_CONTROL_WORD := not c_DFT; --Important to cover all the cases 119 | end case; 120 | 121 | when c_ADD => --ADD instruction 122 | case w_INST_STEP is 123 | when c_T2 => v_CONTROL_WORD := not (c_MI or c_IO); 124 | when c_T3 => v_CONTROL_WORD := not (c_RO or c_BI); 125 | when c_T4 => v_CONTROL_WORD := not (c_AI or c_EO or c_FI); --The sum is loaded into the accumulator (A register) (Flag register is updated) 126 | when others => v_CONTROL_WORD := not c_DFT; 127 | end case; 128 | 129 | when c_SUB => --SUB instruction 130 | case w_INST_STEP is 131 | when c_T2 => v_CONTROL_WORD := not (c_MI or c_IO); --Get the address part and put it into memory address register 132 | when c_T3 => v_CONTROL_WORD := not (c_RO or c_BI); --Put the RAM content the memort address register points to into register B 133 | when c_T4 => v_CONTROL_WORD := not (c_AI or c_EO or c_SU or c_FI); --When storing the result the subtract bit is set (Flag register is updated) 134 | when others => v_CONTROL_WORD := not c_DFT; 135 | end case; 136 | 137 | when c_STA => --STA instruction 138 | case w_INST_STEP is 139 | when c_T2 => v_CONTROL_WORD := not (c_MI or c_IO); 140 | when c_T3 => v_CONTROL_WORD := not (c_AO or c_RI); 141 | when others => v_CONTROL_WORD := not c_DFT; 142 | end case; 143 | 144 | when c_LDI => --LDI instruction 145 | case w_INST_STEP is 146 | when c_T2 => v_CONTROL_WORD := not (c_IO or c_AI); --Only the 4 LSB are used and there a max value of xF can be used 147 | when others => v_CONTROL_WORD := not c_DFT; 148 | end case; 149 | 150 | when c_JMP => --JMP instruction 151 | case w_INST_STEP is 152 | when c_T2 => v_CONTROL_WORD := not (c_IO or c_J); --Put the 4 LSB which is the address for next instruction into the PC 153 | when others => v_CONTROL_WORD := not c_DFT; 154 | end case; 155 | 156 | when c_JC => --JC instruction 157 | case w_INST_STEP is 158 | when c_T2 => 159 | if v_CF = '1' then --Jump only if the carry flag is set 160 | v_CONTROL_WORD := not (c_IO or c_J); --Put new address into the PC to point to new location in RAM for the next instuction 161 | else 162 | v_CONTROL_WORD := not c_DFT; 163 | end if; 164 | when others => v_CONTROL_WORD := not c_DFT; 165 | end case; 166 | 167 | when c_JZ => --JZ instruction 168 | case w_INST_STEP is 169 | when c_T2 => 170 | if v_ZF = '1' then --Jump only if the zero flag is set 171 | v_CONTROL_WORD := not (c_IO or c_J); 172 | else 173 | v_CONTROL_WORD := not c_DFT; 174 | end if; 175 | when others => v_CONTROL_WORD := not c_DFT; 176 | end case; 177 | 178 | when c_OUT => --OUT instruction 179 | case w_INST_STEP is 180 | when c_T2 => v_CONTROL_WORD := not (c_AO or c_OI); 181 | when others => v_CONTROL_WORD := not c_DFT; 182 | end case; 183 | 184 | when c_HALT => --HLT instruction 185 | case w_INST_STEP is 186 | when c_T2 => v_CONTROL_WORD := not c_HLT; 187 | when others => v_CONTROL_WORD := not c_DFT; 188 | end case; 189 | 190 | when others => v_CONTROL_WORD := not c_DFT; --No instruction match 191 | end case; 192 | end case; 193 | 194 | return std_logic_vector(v_CONTROL_WORD); 195 | 196 | end function f_INST_DECODER; 197 | 198 | begin 199 | 200 | w_inv_clk <= not i_clkin; --Inverting the clock so the control word is changed in between clocks 201 | w_inst_step <= std_logic_vector(to_unsigned(r_INST_STEP_COUNTER,w_inst_step'length)); 202 | 203 | w_control_word <= f_INST_DECODER(i_instruction,w_inst_step,i_flags); 204 | 205 | o_hlt <= w_control_word(15); 206 | o_mi <= w_control_word(14); 207 | o_ri <= w_control_word(13); 208 | o_ro <= w_control_word(12); 209 | o_io <= w_control_word(11); 210 | o_ii <= w_control_word(10); 211 | o_ai <= w_control_word(9); 212 | o_ao <= w_control_word(8); 213 | o_eps <= w_control_word(7); 214 | o_su <= w_control_word(6); 215 | o_bi <= w_control_word(5); 216 | o_bo <= '1'; --B register out is not used 217 | o_oi <= w_control_word(4); 218 | o_ce <= w_control_word(3); 219 | o_co <= w_control_word(2); 220 | o_j <= w_control_word(1); 221 | o_fi <= w_control_word(0); 222 | 223 | --Process to increment the counter 224 | p_inst_counter : process(w_inv_clk,i_reset) is 225 | begin 226 | if i_reset = '0' then 227 | r_INST_STEP_COUNTER <= 0; --Reset the instruction step counter 228 | elsif rising_edge(w_inv_clk) then 229 | if r_INST_STEP_COUNTER = c_INST_MAX_COUNT-1 then 230 | r_INST_STEP_COUNTER <= 0; 231 | else 232 | r_INST_STEP_COUNTER <= r_INST_STEP_COUNTER+1; 233 | end if; 234 | end if; 235 | end process p_inst_counter; 236 | 237 | --Debug LED for the current time step for the instruction and control word 238 | o_inv_clk <= w_inv_clk; 239 | o_inst_step_dbg_led <= w_inst_step; 240 | o_ctrl_word_dbg_led <= w_control_word; 241 | 242 | end rtl; 243 | 244 | 245 | 246 | 247 | 248 | -------------------------------------------------------------------------------- /instruction_decoder_tb.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | 3 | use ieee.std_logic_1164.all; 4 | use ieee.numeric_std.all; 5 | 6 | entity instruction_decoder_tb is 7 | end entity instruction_decoder_tb; 8 | 9 | architecture behaviour of instruction_decoder_tb is 10 | 11 | --50 MHz = 20 ns period 12 | constant c_CLK_PERIOD : time := 20 ns; 13 | 14 | signal r_CLKIN : std_logic := '0'; 15 | signal r_RESET : std_logic := '1'; 16 | 17 | signal r_INSTRUCTION : std_logic_vector(3 downto 0) := "0000"; --NOP 18 | signal r_FLAGS : std_logic_vector(1 downto 0) := "00"; 19 | 20 | signal r_HLT : std_logic; 21 | signal r_MI : std_logic; 22 | signal r_RI : std_logic; 23 | signal r_RO : std_logic; 24 | signal r_IO : std_logic; 25 | signal r_II : std_logic; 26 | signal r_AI : std_logic; 27 | signal r_AO : std_logic; 28 | signal r_EPS : std_logic; 29 | signal r_SU : std_logic; 30 | signal r_BI : std_logic; 31 | signal r_BO : std_logic; 32 | signal r_OI : std_logic; 33 | signal r_CE : std_logic; 34 | signal r_CO : std_logic; 35 | signal r_J : std_logic; 36 | 37 | signal r_INV_CLK : std_logic; 38 | signal r_INST_STEP_DBG_LED : std_logic_vector(2 downto 0); 39 | signal r_CTRL_WORD_DBG_LED : std_logic_vector(15 downto 0); 40 | 41 | component instruction_decoder is 42 | port( 43 | i_clkin : in std_logic; 44 | i_reset : in std_logic; 45 | i_instruction : in std_logic_vector(3 downto 0); 46 | i_flags : in std_logic_vector(1 downto 0); 47 | o_hlt : out std_logic; 48 | o_mi : out std_logic; 49 | o_ri : out std_logic; 50 | o_ro : out std_logic; 51 | o_io : out std_logic; 52 | o_ii : out std_logic; 53 | o_ai : out std_logic; 54 | o_ao : out std_logic; 55 | o_eps : out std_logic; 56 | o_su : out std_logic; 57 | o_bi : out std_logic; 58 | o_bo : out std_logic; 59 | o_oi : out std_logic; 60 | o_ce : out std_logic; 61 | o_co : out std_logic; 62 | o_j : out std_logic; 63 | o_fi : out std_logic; 64 | o_inv_clk : out std_logic; 65 | o_inst_step_dbg_led : out std_logic_vector(2 downto 0); 66 | o_ctrl_word_dbg_led : out std_logic_vector(15 downto 0) 67 | ); 68 | end component instruction_decoder; 69 | 70 | begin 71 | 72 | p_clk_gen : process is 73 | begin 74 | wait for c_CLK_PERIOD/2; 75 | r_CLKIN <= not r_CLKIN; 76 | end process p_clk_gen; 77 | 78 | UUT : instruction_decoder 79 | port map( 80 | i_clkin => r_CLKIN, 81 | i_reset => r_RESET, 82 | i_instruction => r_INSTRUCTION, 83 | i_flags => r_FLAGS, 84 | o_hlt => r_HLT, 85 | o_mi => r_MI, 86 | o_ri => r_RI, 87 | o_ro => r_RO, 88 | o_io => r_IO, 89 | o_ii => r_II, 90 | o_ai => r_AI, 91 | o_ao => r_AO, 92 | o_eps => r_EPS, 93 | o_su => r_SU, 94 | o_bi => r_BI, 95 | o_bo => r_BO, 96 | o_oi => r_OI, 97 | o_ce => r_CE, 98 | o_co => r_CO, 99 | o_j => r_J, 100 | o_inv_clk => r_INV_CLK, 101 | o_inst_step_dbg_led => r_INST_STEP_DBG_LED, 102 | o_ctrl_word_dbg_led => r_CTRL_WORD_DBG_LED 103 | ); 104 | 105 | process 106 | begin 107 | 108 | r_INSTRUCTION <= "0001"; --LDA 109 | 110 | wait for 100 ns; 111 | 112 | r_INSTRUCTION <= "0111"; --JC 113 | 114 | wait for 100 ns; 115 | 116 | r_INSTRUCTION <= "1000"; --JZ 117 | 118 | wait for 100 ns; 119 | 120 | r_FLAGS <= "01"; --Set the carry flag 121 | r_INSTRUCTION <= "0111"; --JC 122 | 123 | wait for 100 ns; 124 | 125 | r_FLAGS <= "10"; --Set the carry flag 126 | r_INSTRUCTION <= "1000"; --JZ 127 | 128 | wait for 100 ns; 129 | 130 | r_FLAGS <= "11"; --Set the carry flag 131 | r_INSTRUCTION <= "0111"; --JC 132 | 133 | wait for 100 ns; 134 | 135 | r_FLAGS <= "11"; --Set the carry flag 136 | r_INSTRUCTION <= "1000"; --JZ 137 | 138 | wait for 100 ns; 139 | 140 | r_INSTRUCTION <= "0010"; --ADD 141 | 142 | wait for 100 ns; 143 | 144 | r_INSTRUCTION <= "1110"; --OUT 145 | 146 | wait for 50 ns; 147 | 148 | --Resetting in the middle 149 | r_RESET <= '0'; 150 | wait for 10 ns; 151 | r_RESET <= '1'; 152 | 153 | wait for 1 sec; 154 | 155 | end process; 156 | 157 | end behaviour; -------------------------------------------------------------------------------- /instruction_reg.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | 3 | use ieee.std_logic_1164.all; 4 | 5 | entity instruction_reg is 6 | port( 7 | i_clkin : in std_logic; 8 | i_reset : in std_logic; 9 | i_we : in std_logic; --Instruction register in (Active LOW) 10 | i_oe : in std_logic; --Instruction register output (Active LOW) 11 | i_data_bus_in : in std_logic_vector(7 downto 0); 12 | o_data_bus_out : out std_logic_vector(7 downto 0); 13 | o_instuction : out std_logic_vector(3 downto 0); 14 | o_instreg_dbg_led : out std_logic_vector(7 downto 0) 15 | ); 16 | end entity instruction_reg; 17 | 18 | architecture rtl of instruction_reg is 19 | 20 | --Instruction register 21 | signal r_instruction_reg : std_logic_vector(7 downto 0) := (others => '0'); 22 | signal w_address : std_logic_vector(7 downto 0) := (others => '0'); 23 | 24 | begin 25 | 26 | w_address(3 downto 0) <= r_instruction_reg(3 downto 0); --The address associated with the instruction is found in the 4 LSB 27 | 28 | --Instruction register input 29 | p_instreg_write : process(i_clkin,i_reset) is 30 | begin 31 | if i_reset = '0' then 32 | r_instruction_reg <= (others => '0'); 33 | elsif rising_edge(i_clkin) then 34 | if i_we = '0' and i_oe = '1' then 35 | r_instruction_reg <= i_data_bus_in; 36 | end if; 37 | end if; 38 | end process p_instreg_write; 39 | 40 | --Instruction register output to the data bus 41 | o_data_bus_out <= w_address when(i_oe = '0' and i_we = '1') else 42 | (others => '0'); 43 | 44 | o_instuction <= r_instruction_reg(7 downto 4); --The 4 MSB is the instruction 45 | o_instreg_dbg_led <= r_instruction_reg; --The debug LED is the instruction register 46 | 47 | end rtl; 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /instruction_reg_tb.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | 3 | use ieee.std_logic_1164.all; 4 | 5 | entity instruction_reg_tb is 6 | end entity instruction_reg_tb; 7 | 8 | architecture behaviour of instruction_reg_tb is 9 | 10 | --50 MHz clock = 20 ns period 11 | constant c_CLK_PERIOD : time := 20 ns; 12 | 13 | signal r_CLKIN : std_logic := '0'; 14 | signal r_RESET : std_logic := '1'; 15 | signal r_WE : std_logic := '1'; 16 | signal r_OE : std_logic := '1'; 17 | signal r_DATA_BUS_IN : std_logic_vector(7 downto 0) := (others => '0'); 18 | signal r_DATA_BUS_OUT : std_logic_vector(7 downto 0); 19 | signal r_INSTRUCTION : std_logic_vector(3 downto 0); 20 | signal r_INSTREG_DBG_LED : std_logic_vector(7 downto 0); 21 | 22 | component instruction_reg is 23 | port( 24 | i_clkin : in std_logic; 25 | i_reset : in std_logic; 26 | i_we : in std_logic; --Instruction register in (Active LOW) 27 | i_oe : in std_logic; --Instruction register output (Active LOW) 28 | i_data_bus_in : in std_logic_vector(7 downto 0); 29 | o_data_bus_out : out std_logic_vector(7 downto 0); 30 | o_instuction : out std_logic_vector(3 downto 0); 31 | o_instreg_dbg_led : out std_logic_vector(7 downto 0) 32 | ); 33 | end component instruction_reg; 34 | 35 | begin 36 | 37 | UUT : instruction_reg 38 | port map( 39 | i_clkin => r_CLKIN, 40 | i_reset => r_RESET, 41 | i_we => r_WE, 42 | i_oe => r_OE, 43 | i_data_bus_in => r_DATA_BUS_IN, 44 | o_data_bus_out => r_DATA_BUS_OUT, 45 | o_instuction => r_INSTRUCTION, 46 | o_instreg_dbg_led => r_INSTREG_DBG_LED 47 | ); 48 | 49 | p_clk_gen : process is 50 | begin 51 | wait for c_CLK_PERIOD/2; 52 | r_CLKIN <= not r_CLKIN; 53 | end process p_clk_gen; 54 | 55 | process 56 | begin 57 | 58 | r_DATA_BUS_IN <= "10100101"; 59 | wait for 5 ns; 60 | r_WE <= '0'; 61 | wait for 10 ns; 62 | r_WE <= '1'; 63 | 64 | wait for 10 ns; 65 | r_OE <= '0'; 66 | wait for 10 ns; 67 | r_OE <= '1'; 68 | 69 | wait for 10 ns; 70 | r_RESET <= '0'; 71 | wait for 5 ns; 72 | r_RESET <= '1'; 73 | 74 | wait for 1 sec; 75 | 76 | end process; 77 | end behaviour; 78 | 79 | -------------------------------------------------------------------------------- /memory_addr_reg.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | 3 | use ieee.std_logic_1164.all; 4 | 5 | entity memory_addr_reg is 6 | port( 7 | i_clkin : in std_logic; 8 | i_reset : in std_logic; 9 | i_mi : in std_logic; --Signal to take in the 4 LSB and put it into the register (Active LOW) 10 | i_data_bus_in : in std_logic_vector(7 downto 0); 11 | o_addr : out std_logic_vector(3 downto 0) --Outputs the 4 LSB stored in the memory address register 12 | ); 13 | end entity memory_addr_reg; 14 | 15 | architecture rtl of memory_addr_reg is 16 | 17 | signal r_mem_addr_reg : std_logic_vector(3 downto 0) := (others => '0'); 18 | 19 | begin 20 | 21 | p_mem_addr_write : process(i_clkin,i_reset) 22 | begin 23 | if i_reset = '0' then 24 | r_mem_addr_reg <= (others => '0'); 25 | elsif rising_edge(i_clkin) then 26 | if i_mi = '0' then 27 | r_mem_addr_reg <= i_data_bus_in(3 downto 0); --LSB of the data bus is taken and stored 28 | end if; 29 | end if; 30 | end process p_mem_addr_write; 31 | 32 | o_addr <= r_mem_addr_reg; --Output the address constantly 33 | 34 | end rtl; 35 | 36 | -------------------------------------------------------------------------------- /memory_addr_reg_tb.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | 3 | use ieee.std_logic_1164.all; 4 | 5 | entity memory_addr_reg_tb is 6 | end entity memory_addr_reg_tb; 7 | 8 | architecture behaviour of memory_addr_reg_tb is 9 | 10 | --50MHz clock = 20 ns period 11 | constant c_CLK_PERIOD : time := 20 ns; 12 | 13 | signal r_CLKIN : std_logic := '0'; 14 | signal r_RESET : std_logic := '1'; 15 | signal r_MI : std_logic := '1'; 16 | signal r_DATA_BUS_IN : std_logic_vector(7 downto 0) := (others => '0'); 17 | signal r_ADDR : std_logic_vector (3 downto 0) := (others => '0'); 18 | 19 | component memory_addr_reg is 20 | port( 21 | i_clkin : in std_logic; 22 | i_reset : in std_logic; 23 | i_mi : in std_logic; --Signal to take in the 4 LSB and put it into the register (Active LOW) 24 | i_data_bus_in : in std_logic_vector(7 downto 0); 25 | o_addr : out std_logic_vector(3 downto 0) --Outputs the 4 LSB stored in the memory address register 26 | ); 27 | end component memory_addr_reg; 28 | 29 | begin 30 | 31 | UUT : memory_addr_reg 32 | port map( 33 | i_clkin => r_CLKIN, 34 | i_reset => r_RESET, 35 | i_mi => r_MI, 36 | i_data_bus_in => r_DATA_BUS_IN, 37 | o_addr => r_ADDR 38 | ); 39 | 40 | p_clk_gen : process is 41 | begin 42 | wait for c_CLK_PERIOD/2; 43 | r_CLKIN <= not r_CLKIN; 44 | end process p_clk_gen; 45 | 46 | process 47 | begin 48 | 49 | r_DATA_BUS_IN <= "11111011"; 50 | wait for 7.5 ns; 51 | r_MI <= '0'; 52 | wait for 5 ns; 53 | r_MI <= '1'; 54 | 55 | r_DATA_BUS_IN <= "10010000"; 56 | 57 | wait for 5 ns; 58 | r_RESET <= '0'; 59 | wait for 5 ns; 60 | r_RESET <= '1'; 61 | 62 | wait for 1 sec; 63 | 64 | end process; 65 | 66 | end behaviour; 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /prog_counter.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | 3 | use ieee.std_logic_1164.all; 4 | use ieee.numeric_std.all; 5 | 6 | entity prog_counter is 7 | port( 8 | i_clkin : in std_logic; 9 | i_reset : in std_logic; 10 | i_ce : in std_logic; --Counter enable (Active LOW) 11 | i_co : in std_logic; --Counter output to bus (Active LOW) 12 | i_j : in std_logic; --Set the counter to a specfic value by reading in the 4 LSB of the bus (Used in jump instruction) (Active LOW) 13 | i_data_bus_in : in std_logic_vector(7 downto 0); --All th 8 bits are used but only the 4 LSB are considered 14 | o_data_bus_out : out std_logic_vector(7 downto 0); 15 | o_pc_dbg_led : out std_logic_vector(3 downto 0) 16 | ); 17 | end entity prog_counter; 18 | 19 | architecture rtl of prog_counter is 20 | 21 | constant c_PC_MAX : natural := 16; 22 | signal r_PC_REG : natural range 0 to c_PC_MAX; 23 | 24 | begin 25 | 26 | --Process to increment the counter and jump the counter value 27 | p_counter : process(i_clkin,i_reset) 28 | begin 29 | if i_reset = '0' then 30 | r_PC_REG <= 0; --Resetting the count register for program counter 31 | elsif rising_edge(i_clkin) then 32 | if i_ce = '0' then 33 | if r_PC_REG = c_PC_MAX-1 then 34 | r_PC_REG <= 0; 35 | else 36 | r_PC_REG <= r_PC_REG+1; 37 | end if; 38 | elsif i_j = '0' then 39 | r_PC_REG <= to_integer(unsigned(i_data_bus_in(3 downto 0))); --The 4 LSB are used (WORK NEEDED HERE) 40 | end if; 41 | end if; 42 | end process p_counter; 43 | 44 | --Put the program counter value on to the bus 45 | o_data_bus_out <= std_logic_vector(to_unsigned(r_PC_REG,o_data_bus_out'length)) when(i_co = '0') else 46 | (others => '0'); 47 | 48 | --Debug LED for the program counter 49 | o_pc_dbg_led <= std_logic_vector(to_unsigned(r_PC_REG,o_pc_dbg_led'length)); 50 | 51 | end rtl; -------------------------------------------------------------------------------- /prog_counter_tb.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | 3 | use ieee.std_logic_1164.all; 4 | use ieee.numeric_std.all; 5 | 6 | entity prog_counter_tb is 7 | end entity prog_counter_tb; 8 | 9 | architecture behaviour of prog_counter_tb is 10 | 11 | --50 Mhz = 20 ns Time period 12 | constant c_CLK_PERIOD : time := 20 ns; 13 | 14 | signal r_CLKIN : std_logic := '0'; 15 | signal r_RESET : std_logic := '1'; 16 | signal r_CE : std_logic := '1'; 17 | signal r_CO : std_logic := '1'; 18 | signal r_J : std_logic := '1'; 19 | signal r_DATA_BUS_IN : std_logic_vector(7 downto 0) := (others => '0'); 20 | signal r_DATA_BUS_OUT : std_logic_vector(7 downto 0) := (others => '0'); 21 | signal r_PC_DBG_LED : std_logic_vector(3 downto 0) := (others => '0'); 22 | 23 | component prog_counter is 24 | port( 25 | i_clkin : in std_logic; 26 | i_reset : in std_logic; 27 | i_ce : in std_logic; --Counter enable (Active LOW) 28 | i_co : in std_logic; --Counter output to bus (Active LOW) 29 | i_j : in std_logic; --Set the counter to a specfic value by reading in the 4 LSB of the bus (Used in jump instruction) (Active LOW) 30 | i_data_bus_in : in std_logic_vector(7 downto 0); --All th 8 bits are used but only the 4 LSB are considered 31 | o_data_bus_out : out std_logic_vector(7 downto 0); 32 | o_pc_dbg_led : out std_logic_vector(3 downto 0) 33 | ); 34 | end component prog_counter; 35 | 36 | begin 37 | 38 | UUT : prog_counter 39 | port map( 40 | i_clkin => r_CLKIN, 41 | i_reset => r_RESET, 42 | i_ce => r_CE, 43 | i_co => r_CO, 44 | i_j => r_J, 45 | i_data_bus_in => r_DATA_BUS_IN, 46 | o_data_bus_out => r_DATA_BUS_OUT, 47 | o_pc_dbg_led => r_PC_DBG_LED 48 | ); 49 | 50 | p_clk_gen : process is 51 | begin 52 | wait for c_CLK_PERIOD/2; 53 | r_CLKIN <= not r_CLKIN; 54 | end process p_clk_gen; 55 | 56 | process 57 | begin 58 | 59 | r_DATA_BUS_IN <= "11111001"; --Just to check if something is getting in 60 | r_CE <= '0'; 61 | r_J <= '1'; 62 | wait for 620 ns; 63 | r_CE <= '1'; 64 | 65 | wait for 5 ns; 66 | r_CO <= '0'; 67 | wait for 10 ns; 68 | r_CO <= '1'; 69 | 70 | wait for 10 ns; 71 | r_J <= '0'; 72 | wait for 10 ns; 73 | r_J <= '1'; 74 | 75 | wait for 10 ns; 76 | r_RESET <= '0'; 77 | wait for 10 ns; 78 | r_RESET <= '1'; 79 | 80 | wait for 1 sec; 81 | 82 | end process; 83 | 84 | end behaviour; 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /simulation/alu.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajithcodesit/8-bit_fpga_cpu/a7cbd3b130138923cacaaab5d8e874a6a85bbece/simulation/alu.bmp -------------------------------------------------------------------------------- /simulation/alu_reg.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajithcodesit/8-bit_fpga_cpu/a7cbd3b130138923cacaaab5d8e874a6a85bbece/simulation/alu_reg.bmp -------------------------------------------------------------------------------- /simulation/bin_to_bcd.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajithcodesit/8-bit_fpga_cpu/a7cbd3b130138923cacaaab5d8e874a6a85bbece/simulation/bin_to_bcd.bmp -------------------------------------------------------------------------------- /simulation/clock.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajithcodesit/8-bit_fpga_cpu/a7cbd3b130138923cacaaab5d8e874a6a85bbece/simulation/clock.bmp -------------------------------------------------------------------------------- /simulation/debug_leds.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajithcodesit/8-bit_fpga_cpu/a7cbd3b130138923cacaaab5d8e874a6a85bbece/simulation/debug_leds.bmp -------------------------------------------------------------------------------- /simulation/flags.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajithcodesit/8-bit_fpga_cpu/a7cbd3b130138923cacaaab5d8e874a6a85bbece/simulation/flags.bmp -------------------------------------------------------------------------------- /simulation/inst_decoder.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajithcodesit/8-bit_fpga_cpu/a7cbd3b130138923cacaaab5d8e874a6a85bbece/simulation/inst_decoder.bmp -------------------------------------------------------------------------------- /simulation/instruction_regis.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajithcodesit/8-bit_fpga_cpu/a7cbd3b130138923cacaaab5d8e874a6a85bbece/simulation/instruction_regis.bmp -------------------------------------------------------------------------------- /simulation/mem_addr_reg.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajithcodesit/8-bit_fpga_cpu/a7cbd3b130138923cacaaab5d8e874a6a85bbece/simulation/mem_addr_reg.bmp -------------------------------------------------------------------------------- /simulation/out_7_seg.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajithcodesit/8-bit_fpga_cpu/a7cbd3b130138923cacaaab5d8e874a6a85bbece/simulation/out_7_seg.bmp -------------------------------------------------------------------------------- /simulation/prog_counter.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajithcodesit/8-bit_fpga_cpu/a7cbd3b130138923cacaaab5d8e874a6a85bbece/simulation/prog_counter.bmp -------------------------------------------------------------------------------- /simulation/ram.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajithcodesit/8-bit_fpga_cpu/a7cbd3b130138923cacaaab5d8e874a6a85bbece/simulation/ram.bmp -------------------------------------------------------------------------------- /simulation/test_cpu_add_example.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajithcodesit/8-bit_fpga_cpu/a7cbd3b130138923cacaaab5d8e874a6a85bbece/simulation/test_cpu_add_example.bmp -------------------------------------------------------------------------------- /single_port_ram.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | 3 | use ieee.std_logic_1164.all; 4 | use ieee.numeric_std.all; 5 | 6 | entity single_port_ram is 7 | port( 8 | i_clkin : in std_logic; 9 | i_we : in std_logic; --Active LOW 10 | i_oe : in std_logic; --Active LOW 11 | i_addr : in std_logic_vector(3 downto 0); 12 | i_data_bus_in : in std_logic_vector(7 downto 0); 13 | o_data_bus_out : out std_logic_vector(7 downto 0); 14 | o_ram_dbg_led : out std_logic_vector(7 downto 0) 15 | ); 16 | end entity single_port_ram; 17 | 18 | architecture rtl of single_port_ram is 19 | 20 | --Based on Intel single port RAM example 21 | --Building a 2D array type of RAM 22 | subtype word_t is std_logic_vector(7 downto 0); 23 | type memory_t is array (0 to (2**i_addr'length)-1) of word_t; 24 | 25 | --RAM signal (This register hold the value stored in the address accessed from RAM) 26 | --Example for simple addition 27 | signal r_ram : memory_t :=( 28 | "00011110", --LDA 14 29 | "00101111", --ADD 15 30 | "11100000", --OUT 31 | "11110000", --HALT 32 | "00000000", 33 | "00000000", 34 | "00000000", 35 | "00000000", 36 | "00000000", 37 | "00000000", 38 | "00000000", 39 | "00000000", 40 | "00000000", 41 | "00000000", 42 | "00111000", --56 in binary at address 14 43 | "00011100" --28 in binary at address 15 44 | ); 45 | 46 | --Example for conditional jumps 47 | -- signal r_ram : memory_t :=( 48 | -- "00011110", --LDA 14 49 | -- "00101111", --ADD 15 50 | -- "11100000", --OUT 51 | -- "01110101", --JC 5 52 | -- "01100001", --JMP 1 53 | -- "00111111", --SUB 15 54 | -- "11100000", --OUT 55 | -- "10000001", --JZ 1 56 | -- "01100101", --JMP 5 57 | -- "00000000", 58 | -- "00000000", 59 | -- "00000000", 60 | -- "00000000", 61 | -- "00000000", 62 | -- "00000001", --1 in binary at address 14 63 | -- "00000001" --1 in binary at addresss 15 64 | -- ); 65 | 66 | begin 67 | 68 | --Writing to RAM 69 | p_ram_write : process(i_clkin) 70 | begin 71 | if rising_edge(i_clkin) then 72 | if i_we = '0' and i_oe ='1' then 73 | r_ram(to_integer(unsigned(i_addr))) <= i_data_bus_in; 74 | end if; 75 | end if; 76 | end process p_ram_write; 77 | 78 | --Putting the data in RAM on to the bus 79 | o_data_bus_out <= r_ram(to_integer(unsigned(i_addr))) when(i_oe = '0' and i_we = '1') else 80 | (others => '0'); 81 | 82 | --Shows the contents of the current address if debug LEDs are used 83 | o_ram_dbg_led <= r_ram(to_integer(unsigned(i_addr))); 84 | 85 | end rtl; 86 | -------------------------------------------------------------------------------- /single_port_ram_tb.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | 3 | use ieee.std_logic_1164.all; 4 | use ieee.numeric_std.all; 5 | 6 | entity single_port_ram_tb is 7 | end entity single_port_ram_tb; 8 | 9 | architecture rtl of single_port_ram_tb is 10 | 11 | --50 MHz = 20 ns period 12 | constant c_CLOCK_PERIOD : time := 20 ns; 13 | 14 | signal r_CLKIN : std_logic := '0'; 15 | signal r_WE : std_logic := '1'; 16 | signal r_OE : std_logic := '1'; 17 | signal r_ADDR : std_logic_vector(3 downto 0) := (others => '0'); 18 | signal r_DATA_BUS_IN : std_logic_vector(7 downto 0) := (others => '0'); 19 | signal r_DATA_BUS_OUT : std_logic_vector(7 downto 0) := (others => '0'); 20 | signal r_RAM_DBG_LED : std_logic_vector(7 downto 0) := (others => '0'); 21 | 22 | component single_port_ram is 23 | port( 24 | i_clkin : in std_logic; 25 | i_we : in std_logic; --Active LOW 26 | i_oe : in std_logic; --Active LOW 27 | i_addr : in std_logic_vector(3 downto 0); 28 | i_data_bus_in : in std_logic_vector(7 downto 0); 29 | o_data_bus_out : out std_logic_vector(7 downto 0); 30 | o_ram_dbg_led : out std_logic_vector(7 downto 0) 31 | ); 32 | end component single_port_ram; 33 | 34 | begin 35 | 36 | UUT : single_port_ram 37 | port map( 38 | i_clkin => r_CLKIN, 39 | i_we => r_WE, 40 | i_oe => r_OE, 41 | i_addr => r_ADDR, 42 | i_data_bus_in => r_DATA_BUS_IN, 43 | o_data_bus_out => r_DATA_BUS_OUT, 44 | o_ram_dbg_led => r_RAM_DBG_LED 45 | ); 46 | 47 | p_clk_gen : process is 48 | begin 49 | wait for c_CLOCK_PERIOD/2; 50 | r_CLKIN <= not r_CLKIN; 51 | end process p_clk_gen; 52 | 53 | process 54 | begin 55 | 56 | r_ADDR <= "0001"; 57 | r_DATA_BUS_IN <= "10011001"; 58 | wait for 7.5 ns; 59 | r_WE <= '0'; 60 | wait for 5 ns; 61 | r_WE <= '1'; 62 | 63 | r_ADDR <= "1010"; 64 | r_DATA_BUS_IN <= "10111101"; 65 | wait for 15 ns; 66 | r_WE <= '0'; 67 | wait for 5 ns; 68 | r_WE <= '1'; 69 | 70 | r_ADDR <= "0001"; 71 | r_DATA_BUS_IN <= "11111111"; --Just to ckeck if data gets in the ram 72 | wait for 15 ns; 73 | r_OE <= '0'; 74 | wait for 5 ns; 75 | r_OE <= '1'; 76 | 77 | r_ADDR <= "1010"; 78 | r_DATA_BUS_IN <= "11111111"; 79 | wait for 15 ns; 80 | r_OE <= '0'; 81 | wait for 5 ns; 82 | r_OE <= '1'; 83 | 84 | wait for 1 sec; 85 | 86 | end process; 87 | 88 | end architecture rtl; 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /test_cpu.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | 3 | use ieee.std_logic_1164.all; 4 | 5 | entity test_cpu is 6 | port( 7 | i_cpu_clk : in std_logic; 8 | i_master_rst : in std_logic; 9 | o_output : out std_logic_vector(7 downto 0) 10 | ); 11 | end entity test_cpu; 12 | 13 | architecture rtl of test_cpu is 14 | 15 | --CPU Clock 16 | signal w_CLK_1HZ : std_logic; 17 | signal w_HLT : std_logic; 18 | 19 | --Master reset for the entire CPU 20 | signal w_RESET : std_logic; 21 | 22 | --Data bus connections 23 | signal w_DATA_BUS_IN : std_logic_vector(7 downto 0); 24 | signal w_DATA_BUS_OUT_PC : std_logic_vector(7 downto 0); 25 | signal w_DATA_BUS_OUT_INR : std_logic_vector(7 downto 0); 26 | 27 | --Memory address register controls and output 28 | signal w_MI : std_logic; --Memory address register in 29 | signal w_ADDR : std_logic_vector(3 downto 0); --Address to be put into RAM 30 | 31 | --RAM control and outputs 32 | signal w_RI : std_logic; 33 | signal w_RO : std_logic; 34 | signal w_DATA_BUS_OUT_RAM : std_logic_vector(7 downto 0); 35 | signal w_RAM_DBG_LED : std_logic_vector(7 downto 0); 36 | 37 | --Program counter controls and output 38 | signal w_CO : std_logic; --Counter out 39 | signal w_CE : std_logic; --Counter enable (Increments) 40 | signal w_J : std_logic; --Jump 41 | signal w_PC_DBG_LED : std_logic_vector(3 downto 0); 42 | 43 | --Register A and B for the ALU (A is the accumulator) 44 | signal w_AI : std_logic; 45 | signal w_AO : std_logic; 46 | signal w_DATA_BUS_OUT_A : std_logic_vector(7 downto 0); 47 | signal w_ALU_REG_OUT_A : std_logic_vector(7 downto 0); 48 | signal w_REG_DBG_LED_A : std_logic_vector(7 downto 0); 49 | 50 | signal w_BI : std_logic; 51 | signal w_BO : std_logic; 52 | signal w_DATA_BUS_OUT_B : std_logic_vector(7 downto 0); 53 | signal w_ALU_REG_OUT_B : std_logic_vector(7 downto 0); 54 | signal w_REG_DBG_LED_B : std_logic_vector(7 downto 0); 55 | 56 | --ALU 57 | signal w_EO : std_logic; 58 | signal w_SU : std_logic; 59 | signal w_CY : std_logic; 60 | signal w_ZR : std_logic; 61 | signal w_DATA_BUS_OUT_ALU : std_logic_vector(7 downto 0); 62 | signal w_ALU_DBG_LED : std_logic_vector(7 downto 0); 63 | 64 | --Flags register 65 | signal w_FI : std_logic; 66 | signal w_FLAGS : std_logic_vector(1 downto 0); 67 | signal w_FLAGS_DBG_LED : std_logic_vector(1 downto 0); 68 | 69 | --Instruction register controls and output 70 | signal w_II : std_logic; 71 | signal w_IO : std_logic; 72 | signal w_INSTRUCTION : std_logic_vector(3 downto 0); 73 | signal w_INSTREG_DBG_LED : std_logic_vector(7 downto 0); 74 | 75 | --Instruction decoder 76 | signal w_INST_STEP_DBG_LED : std_logic_vector(2 downto 0); 77 | signal w_CTRL_WORD_DBG_LED : std_logic_vector(15 downto 0); 78 | 79 | --Output register 80 | signal w_OI : std_logic; 81 | 82 | component memory_addr_reg 83 | port( 84 | i_clkin : in std_logic; 85 | i_reset : in std_logic; 86 | i_mi : in std_logic; --Signal to take in the 4 LSB and put it into the register (Active LOW) 87 | i_data_bus_in : in std_logic_vector(7 downto 0); 88 | o_addr : out std_logic_vector(3 downto 0) --Outputs the 4 LSB stored in the memory address register 89 | ); 90 | end component memory_addr_reg; 91 | 92 | component single_port_ram 93 | port( 94 | i_clkin : in std_logic; 95 | i_we : in std_logic; --Active LOW 96 | i_oe : in std_logic; --Active LOW 97 | i_addr : in std_logic_vector(3 downto 0); 98 | i_data_bus_in : in std_logic_vector(7 downto 0); 99 | o_data_bus_out : out std_logic_vector(7 downto 0); 100 | o_ram_dbg_led : out std_logic_vector(7 downto 0) 101 | ); 102 | end component single_port_ram; 103 | 104 | component prog_counter 105 | port( 106 | i_clkin : in std_logic; 107 | i_reset : in std_logic; 108 | i_ce : in std_logic; --Counter enable (Active LOW) 109 | i_co : in std_logic; --Counter output to bus (Active LOW) 110 | i_j : in std_logic; --Set the counter to a specfic value by reading in the 4 LSB of the bus (Used in jump instruction) (Active LOW) 111 | i_data_bus_in : in std_logic_vector(7 downto 0); --All th 8 bits are used but only the 4 LSB are considered 112 | o_data_bus_out : out std_logic_vector(7 downto 0); 113 | o_pc_dbg_led : out std_logic_vector(3 downto 0) 114 | ); 115 | end component prog_counter; 116 | 117 | component alu_register 118 | port( 119 | i_clkin : in std_logic; 120 | i_reset : in std_logic; 121 | i_we : in std_logic; --Load enable (Active low) 122 | i_oe : in std_logic; --Write enable (Active low) 123 | i_data_bus_in: in std_logic_vector (7 downto 0); --For internal buses seperate buses are used for data in/out 124 | o_data_bus_out : out std_logic_vector (7 downto 0); --No tri-state logic internally available on at IO pins 125 | o_alu_reg_out : out std_logic_vector (7 downto 0); --This is connected to the ALU directly (Always outputs) 126 | o_reg_dbg_led : out std_logic_vector (7 downto 0) 127 | ); 128 | end component alu_register; 129 | 130 | component alu 131 | port( 132 | i_eo : in std_logic; --Output the result (Active low) 133 | i_su : in std_logic; --Subtraction when high and addition when low 134 | i_a : in std_logic_vector (7 downto 0); 135 | i_b : in std_logic_vector (7 downto 0); 136 | o_cy : out std_logic; 137 | o_zr : out std_logic; 138 | o_alu_bus_out : out std_logic_vector (7 downto 0); 139 | o_alu_dbg_led : out std_logic_vector(7 downto 0) 140 | ); 141 | end component alu; 142 | 143 | component flags_reg 144 | port( 145 | i_clkin : in std_logic; 146 | i_reset : in std_logic; 147 | i_cb : in std_logic; --Carry bit 148 | i_zb : in std_logic; --Zero bit 149 | i_we : in std_logic; --Write to flags register(Active LOW) 150 | o_flags : out std_logic_vector(1 downto 0); 151 | o_flags_dbg_led : out std_logic_vector(1 downto 0) 152 | ); 153 | end component flags_reg; 154 | 155 | component instruction_reg 156 | port( 157 | i_clkin : in std_logic; 158 | i_reset : in std_logic; 159 | i_we : in std_logic; --Instruction register in (Active LOW) 160 | i_oe : in std_logic; --Instruction register output (Active LOW) 161 | i_data_bus_in : in std_logic_vector(7 downto 0); 162 | o_data_bus_out : out std_logic_vector(7 downto 0); 163 | o_instuction : out std_logic_vector(3 downto 0); 164 | o_instreg_dbg_led : out std_logic_vector(7 downto 0) 165 | ); 166 | end component instruction_reg; 167 | 168 | component instruction_decoder 169 | port( 170 | i_clkin : in std_logic; 171 | i_reset : in std_logic; 172 | i_instruction : in std_logic_vector(3 downto 0); 173 | i_flags : in std_logic_vector(1 downto 0); 174 | o_hlt : out std_logic; 175 | o_mi : out std_logic; 176 | o_ri : out std_logic; 177 | o_ro : out std_logic; 178 | o_io : out std_logic; 179 | o_ii : out std_logic; 180 | o_ai : out std_logic; 181 | o_ao : out std_logic; 182 | o_eps : out std_logic; 183 | o_su : out std_logic; 184 | o_bi : out std_logic; 185 | o_bo : out std_logic; 186 | o_oi : out std_logic; 187 | o_ce : out std_logic; 188 | o_co : out std_logic; 189 | o_j : out std_logic; 190 | o_fi : out std_logic; 191 | o_inst_step_dbg_led : out std_logic_vector(2 downto 0); 192 | o_ctrl_word_dbg_led : out std_logic_vector(15 downto 0) 193 | ); 194 | end component instruction_decoder; 195 | 196 | begin 197 | 198 | --Clock input for testing with halt functionality 199 | w_CLK_1HZ <= i_cpu_clk when(w_HLT = '1') else 200 | '0'; 201 | 202 | --Reset (Button needs to debounced) 203 | w_RESET <= i_master_rst; 204 | 205 | --Bus connections 206 | w_DATA_BUS_IN <= w_DATA_BUS_OUT_PC when(w_CO = '0') else 207 | w_DATA_BUS_OUT_A when(w_AO = '0') else 208 | w_DATA_BUS_OUT_ALU when(w_EO = '0') else 209 | w_DATA_BUS_OUT_B when(w_BO = '0') else 210 | w_DATA_BUS_OUT_RAM when(w_RO = '0') else 211 | w_DATA_BUS_OUT_INR when(w_IO = '0') else 212 | (others => '0'); 213 | 214 | o_output <= w_ALU_REG_OUT_A; --The final output 215 | 216 | pc : prog_counter 217 | port map( 218 | i_clkin => w_CLK_1HZ, 219 | i_reset => w_RESET, 220 | i_ce => w_CE, 221 | i_co => w_CO, 222 | i_j => w_J, 223 | i_data_bus_in => w_DATA_BUS_IN, 224 | o_data_bus_out => w_DATA_BUS_OUT_PC, 225 | o_pc_dbg_led => w_PC_DBG_LED 226 | ); 227 | 228 | a_reg : alu_register 229 | port map( 230 | i_clkin => w_CLK_1HZ, 231 | i_reset => w_RESET, 232 | i_we => w_AI, 233 | i_oe => w_AO, 234 | i_data_bus_in => w_DATA_BUS_IN, 235 | o_data_bus_out => w_DATA_BUS_OUT_A, 236 | o_alu_reg_out => w_ALU_REG_OUT_A, 237 | o_reg_dbg_led => w_REG_DBG_LED_A 238 | ); 239 | 240 | arith_logic_unit : alu 241 | port map( 242 | i_eo => w_EO, 243 | i_su => w_SU, 244 | i_a => w_ALU_REG_OUT_A, 245 | i_b => w_ALU_REG_OUT_B, 246 | o_cy => w_CY, 247 | o_zr => w_ZR, 248 | o_alu_bus_out => w_DATA_BUS_OUT_ALU, 249 | o_alu_dbg_led => w_ALU_DBG_LED 250 | ); 251 | 252 | flags_register : flags_reg 253 | port map( 254 | i_clkin => w_CLK_1HZ, 255 | i_reset => w_RESET, 256 | i_cb => w_CY, 257 | i_zb => w_ZR, 258 | i_we => w_FI, 259 | o_flags => w_FLAGS, 260 | o_flags_dbg_led => w_FLAGS_DBG_LED 261 | ); 262 | 263 | b_reg : alu_register 264 | port map( 265 | i_clkin => w_CLK_1HZ, 266 | i_reset => w_RESET, 267 | i_we => w_BI, 268 | i_oe => w_BO, 269 | i_data_bus_in => w_DATA_BUS_IN, 270 | o_data_bus_out => w_DATA_BUS_OUT_B, 271 | o_alu_reg_out => w_ALU_REG_OUT_B, 272 | o_reg_dbg_led => w_REG_DBG_LED_B 273 | ); 274 | 275 | mem_addr_reg : memory_addr_reg 276 | port map( 277 | i_clkin => w_CLK_1HZ, 278 | i_reset => w_RESET, 279 | i_mi => w_MI, 280 | i_data_bus_in => w_DATA_BUS_IN, 281 | o_addr => w_ADDR 282 | ); 283 | 284 | ram : single_port_ram 285 | port map( 286 | i_clkin => w_CLK_1HZ, 287 | i_we => w_RI, 288 | i_oe => w_RO, 289 | i_addr => w_ADDR, 290 | i_data_bus_in => w_DATA_BUS_IN, 291 | o_data_bus_out => w_DATA_BUS_OUT_RAM, 292 | o_ram_dbg_led => w_RAM_DBG_LED 293 | ); 294 | 295 | inst_reg : instruction_reg 296 | port map( 297 | i_clkin => w_CLK_1HZ, 298 | i_reset => w_RESET, 299 | i_we => w_II, 300 | i_oe => w_IO, 301 | i_data_bus_in => w_DATA_BUS_IN, 302 | o_data_bus_out => w_DATA_BUS_OUT_INR, 303 | o_instuction => w_INSTRUCTION, 304 | o_instreg_dbg_led => w_INSTREG_DBG_LED 305 | ); 306 | 307 | inst_decode : instruction_decoder 308 | port map( 309 | i_clkin => w_CLK_1HZ, 310 | i_reset => w_RESET, 311 | i_instruction => w_INSTRUCTION, 312 | i_flags => w_FLAGS, 313 | o_hlt => w_HLT, 314 | o_mi => w_MI, 315 | o_ri => w_RI, 316 | o_ro => w_RO, 317 | o_io => w_IO, 318 | o_ii => w_II, 319 | o_ai => w_AI, 320 | o_ao => w_AO, 321 | o_eps => w_EO, 322 | o_su => w_SU, 323 | o_bi => w_BI, 324 | o_bo => w_BO, 325 | o_oi => w_OI, 326 | o_ce => w_CE, 327 | o_co => w_CO, 328 | o_j => w_J, 329 | o_fi => w_FI, 330 | o_inst_step_dbg_led => w_INST_STEP_DBG_LED, 331 | o_ctrl_word_dbg_led => w_CTRL_WORD_DBG_LED 332 | ); 333 | 334 | end rtl; -------------------------------------------------------------------------------- /test_cpu_tb.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | 3 | use ieee.std_logic_1164.all; 4 | use ieee.numeric_std.all; 5 | 6 | --This testbench requires the simple addition example in the RAM 7 | 8 | entity test_cpu_tb is 9 | end entity test_cpu_tb; 10 | 11 | architecture behaviour of test_cpu_tb is 12 | 13 | --50 MHz clock = 20 ns time period 14 | constant c_CLK_PERIOD : time := 20 ns; 15 | 16 | signal r_CPU_CLK : std_logic := '0'; 17 | signal r_MASTER_RESET : std_logic := '1'; 18 | signal r_OUTPUT : std_logic_vector(7 downto 0) := (others=>'0'); 19 | 20 | component test_cpu is 21 | port( 22 | i_cpu_clk : in std_logic; 23 | i_master_rst : in std_logic; 24 | o_output : out std_logic_vector(7 downto 0) 25 | ); 26 | end component test_cpu; 27 | 28 | begin 29 | 30 | p_clk_gen : process is 31 | begin 32 | wait for c_CLK_PERIOD/2; 33 | r_CPU_CLK <= not r_CPU_CLK; 34 | end process p_clk_gen; 35 | 36 | UUT : test_cpu 37 | port map( 38 | i_cpu_clk => r_CPU_CLK, 39 | i_master_rst => r_MASTER_RESET, 40 | o_output => r_OUTPUT 41 | ); 42 | 43 | process 44 | begin 45 | 46 | wait for 400 ns; 47 | 48 | if r_OUTPUT = "01010100" then 49 | report "Test Passed -- Correct byte in the ALU register A" severity note; 50 | else 51 | report "Test Failed -- Incorrect byte in the ALU register A" severity note; 52 | end if; 53 | 54 | wait for 10 ns; 55 | r_MASTER_RESET <= '0'; 56 | wait for 10 ns; 57 | r_MASTER_RESET <= '1'; 58 | 59 | assert false report "Test complete" severity failure; 60 | 61 | end process; 62 | end behaviour; 63 | 64 | --------------------------------------------------------------------------------