├── LICENSE ├── accum.v ├── addr_mux.v ├── alu.v ├── assets ├── CPU-comp-right.png ├── CPU-comp-tigh.png ├── CPU-comp.png ├── RTL Viewer.png ├── RTL_Viewer_s.png ├── accum.png ├── alu.png ├── controller-tb-result-1-0.png ├── fsm.pdf ├── fsm.png ├── ir.png ├── ldo-debug.png ├── mux.png ├── mv.bmp ├── mv2.png ├── mv3.png ├── pc.png ├── ram.png ├── reg.png ├── reg1.png ├── rom-tb-result-1-1.png ├── rom-tb-result-1-2.png ├── rom-tb-result-2.png ├── rom-tb-result.png ├── rom.png ├── s0.png ├── s1.png ├── schematic.pdf ├── schematic.png ├── short-ins-caption.png ├── short-ins.png ├── short-long-caption.png ├── short-long.png ├── sidle.png ├── sm.pdf ├── von.png ├── von0.pdf ├── von0.tif ├── wave.png └── wv1.png ├── controller.v ├── core.v ├── core_tb_00.v ├── counter.v ├── ins_reg.v ├── machine.v ├── output ├── design.pdf ├── readme.pdf ├── schematic.pdf ├── states.xlsx ├── wave-video.wmv └── wave.do ├── ram.v ├── readme.rst ├── reg_32.v └── rom.v /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 魔法师LQ 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 | -------------------------------------------------------------------------------- /accum.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | module accum( in, out, ena, clk, rst); // a register, to storage result after computing 4 | input clk,rst,ena; 5 | input [7:0] in; 6 | output reg [7:0] out; 7 | 8 | always @(posedge clk or negedge rst) begin 9 | if(!rst) out <= 8'd0; 10 | else begin 11 | if(ena) out <= in; 12 | else out <= out; 13 | end 14 | end 15 | 16 | endmodule 17 | -------------------------------------------------------------------------------- /addr_mux.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | module addr_mux(addr, sel, ir_ad, pc_ad); 4 | // Address multiplexer 5 | // to choose address of instruction register or address of program counter 6 | input [7:0] ir_ad, pc_ad; 7 | input sel; 8 | output [7:0] addr; 9 | 10 | assign addr = (sel)? ir_ad:pc_ad; 11 | 12 | endmodule 13 | -------------------------------------------------------------------------------- /alu.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | module alu(alu_out, alu_in, accum, op);// arithmetic logic unit 4 | // to perform arithmetic and logic operations. 5 | input [2:0] op; 6 | input [7:0] alu_in,accum; 7 | output reg [7:0] alu_out; 8 | 9 | parameter NOP=3'b000, 10 | LDO=3'b001, 11 | LDA=3'b010, 12 | STO=3'b011, 13 | PRE=3'b100, 14 | ADD=3'b101, 15 | LDM=3'b110, 16 | HLT=3'b111; 17 | 18 | 19 | always @(*) begin 20 | casez(op) 21 | NOP: alu_out = accum; 22 | HLT: alu_out = accum; 23 | LDO: alu_out = alu_in; 24 | LDA: alu_out = alu_in; 25 | STO: alu_out = accum; 26 | PRE: alu_out = alu_in; 27 | ADD: alu_out = accum+alu_in; 28 | LDM: alu_out = accum; 29 | default: alu_out = 8'bzzzz_zzzz; 30 | endcase 31 | end 32 | 33 | 34 | endmodule 35 | -------------------------------------------------------------------------------- /assets/CPU-comp-right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/assets/CPU-comp-right.png -------------------------------------------------------------------------------- /assets/CPU-comp-tigh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/assets/CPU-comp-tigh.png -------------------------------------------------------------------------------- /assets/CPU-comp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/assets/CPU-comp.png -------------------------------------------------------------------------------- /assets/RTL Viewer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/assets/RTL Viewer.png -------------------------------------------------------------------------------- /assets/RTL_Viewer_s.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/assets/RTL_Viewer_s.png -------------------------------------------------------------------------------- /assets/accum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/assets/accum.png -------------------------------------------------------------------------------- /assets/alu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/assets/alu.png -------------------------------------------------------------------------------- /assets/controller-tb-result-1-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/assets/controller-tb-result-1-0.png -------------------------------------------------------------------------------- /assets/fsm.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/assets/fsm.pdf -------------------------------------------------------------------------------- /assets/fsm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/assets/fsm.png -------------------------------------------------------------------------------- /assets/ir.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/assets/ir.png -------------------------------------------------------------------------------- /assets/ldo-debug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/assets/ldo-debug.png -------------------------------------------------------------------------------- /assets/mux.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/assets/mux.png -------------------------------------------------------------------------------- /assets/mv.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/assets/mv.bmp -------------------------------------------------------------------------------- /assets/mv2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/assets/mv2.png -------------------------------------------------------------------------------- /assets/mv3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/assets/mv3.png -------------------------------------------------------------------------------- /assets/pc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/assets/pc.png -------------------------------------------------------------------------------- /assets/ram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/assets/ram.png -------------------------------------------------------------------------------- /assets/reg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/assets/reg.png -------------------------------------------------------------------------------- /assets/reg1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/assets/reg1.png -------------------------------------------------------------------------------- /assets/rom-tb-result-1-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/assets/rom-tb-result-1-1.png -------------------------------------------------------------------------------- /assets/rom-tb-result-1-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/assets/rom-tb-result-1-2.png -------------------------------------------------------------------------------- /assets/rom-tb-result-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/assets/rom-tb-result-2.png -------------------------------------------------------------------------------- /assets/rom-tb-result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/assets/rom-tb-result.png -------------------------------------------------------------------------------- /assets/rom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/assets/rom.png -------------------------------------------------------------------------------- /assets/s0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/assets/s0.png -------------------------------------------------------------------------------- /assets/s1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/assets/s1.png -------------------------------------------------------------------------------- /assets/schematic.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/assets/schematic.pdf -------------------------------------------------------------------------------- /assets/schematic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/assets/schematic.png -------------------------------------------------------------------------------- /assets/short-ins-caption.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/assets/short-ins-caption.png -------------------------------------------------------------------------------- /assets/short-ins.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/assets/short-ins.png -------------------------------------------------------------------------------- /assets/short-long-caption.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/assets/short-long-caption.png -------------------------------------------------------------------------------- /assets/short-long.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/assets/short-long.png -------------------------------------------------------------------------------- /assets/sidle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/assets/sidle.png -------------------------------------------------------------------------------- /assets/sm.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/assets/sm.pdf -------------------------------------------------------------------------------- /assets/von.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/assets/von.png -------------------------------------------------------------------------------- /assets/von0.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/assets/von0.pdf -------------------------------------------------------------------------------- /assets/von0.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/assets/von0.tif -------------------------------------------------------------------------------- /assets/wave.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/assets/wave.png -------------------------------------------------------------------------------- /assets/wv1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/assets/wv1.png -------------------------------------------------------------------------------- /controller.v: -------------------------------------------------------------------------------- 1 | module controller_purify(ins, clk, rst, write_r, read_r, PC_en, fetch, ac_ena, ram_ena, rom_ena,ram_write, ram_read, rom_read, ad_sel); 2 | 3 | input clk, rst; // clock, reset 4 | input [2:0] ins; // instructions, 3 bits, 8 types 5 | 6 | // Enable signals 7 | output reg write_r, read_r, PC_en, ac_ena, ram_ena, rom_ena; 8 | 9 | // ROM: where instructions are storaged. Read only. 10 | // RAM: where data is storaged, readable and writable. 11 | output reg ram_write, ram_read, rom_read, ad_sel; 12 | 13 | output reg [1:0] fetch; // 01: to fetch from RAM/ROM; 10: to fetch from REG 14 | 15 | // State code(current state) 16 | reg [3:0] state; // current state 17 | reg [3:0] next_state; // next state 18 | 19 | 20 | // instruction code 21 | parameter NOP=3'b000, // no operation 22 | LDO=3'b001, // load ROM to register 23 | LDA=3'b010, // load RAM to register 24 | STO=3'b011, // Store intermediate results to accumulator 25 | PRE=3'b100, // Prefetch Data from Address 26 | ADD=3'b101, // Adds the contents of the memory address or integer to the accumulator 27 | LDM=3'b110, // Load Multiple 28 | HLT=3'b111; // Halt 29 | 30 | // state code 31 | parameter Sidle=4'hf, 32 | S0=4'd0, 33 | S1=4'd1, 34 | S2=4'd2, 35 | S3=4'd3, 36 | S4=4'd4, 37 | S5=4'd5, 38 | S6=4'd6, 39 | S7=4'd7, 40 | S8=4'd8, 41 | S9=4'd9, 42 | S10=4'd10, 43 | S11=4'd11, 44 | S12=4'd12; 45 | 46 | //PART A: D flip latch; State register 47 | always @(posedge clk or negedge rst) 48 | begin 49 | if(!rst) state<=Sidle; 50 | //current_state <= Sidle; 51 | else state<=next_state; 52 | //current_state <= next_state; 53 | end 54 | 55 | //PART B: Next-state combinational logic 56 | always @* 57 | begin 58 | case(state) 59 | S1: begin 60 | if (ins==NOP) next_state=S0; 61 | else if (ins==HLT) next_state=S2; 62 | else if (ins==PRE | ins==ADD) next_state=S9; 63 | else if (ins==LDM) next_state=S11; 64 | else next_state=S3; 65 | end 66 | 67 | S4: begin 68 | if (ins==LDA | ins==LDO) next_state=S5; 69 | //else if (ins==STO) next_state=S7; 70 | else next_state=S7; // ---Note: there are only 3 long instrucions. So, all the cases included. if (counter_A==2*b11) 71 | end 72 | Sidle: next_state=S0; 73 | S0: next_state=S1; 74 | S2: next_state=S2; 75 | S3: next_state=S4; 76 | S5: next_state=S6; 77 | S6: next_state=S0; 78 | S7: next_state=S8; 79 | S8: next_state=S0; 80 | S9: next_state=S10; 81 | S10: next_state=S0; 82 | S11: next_state=S12; 83 | S12: next_state=S0; 84 | default: next_state=Sidle; 85 | endcase 86 | end 87 | 88 | // another style 89 | //PART C: Output combinational logic 90 | always@* 91 | begin 92 | case(state) 93 | // --Note: for each statement, we concentrate on the current state, not next_state 94 | // because it is combinational logic. 95 | Sidle: begin 96 | write_r=1'b0; 97 | read_r=1'b0; 98 | PC_en=1'b0; 99 | ac_ena=1'b0; 100 | ram_ena=1'b0; 101 | rom_ena=1'b0; 102 | ram_write=1'b0; 103 | ram_read=1'b0; 104 | rom_read=1'b0; 105 | ad_sel=1'b0; 106 | fetch=2'b00; 107 | end 108 | S0: begin // load IR 109 | write_r=0; 110 | read_r=0; 111 | PC_en=0; 112 | ac_ena=0; 113 | ram_ena=0; 114 | rom_ena=1; 115 | ram_write=0; 116 | ram_read=0; 117 | rom_read=1; 118 | ad_sel=0; 119 | fetch=2'b01; 120 | end 121 | S1: begin 122 | write_r=0; 123 | read_r=0; 124 | PC_en=1; 125 | ac_ena=0; 126 | ram_ena=0; 127 | ram_write=0; 128 | ram_read=0; 129 | rom_ena=1; 130 | rom_read=1; 131 | ad_sel=0; 132 | fetch=2'b00; 133 | end 134 | S2: begin 135 | write_r=0; 136 | read_r=0; 137 | PC_en=0; 138 | ac_ena=0; 139 | ram_ena=0; 140 | rom_ena=0; 141 | ram_write=0; 142 | ram_read=0; 143 | rom_read=0; 144 | ad_sel=0; 145 | fetch=2'b00; 146 | end 147 | S3: begin 148 | write_r=0; 149 | read_r=0; 150 | PC_en=0; 151 | ac_ena=1; 152 | ram_ena=0; 153 | rom_ena=1; 154 | ram_write=0; 155 | ram_read=0; 156 | rom_read=1; 157 | ad_sel=0; 158 | fetch=2'b10; 159 | end 160 | S4: begin 161 | write_r=0; 162 | read_r=0; 163 | PC_en=1; 164 | ac_ena=1; 165 | ram_ena=0; 166 | ram_write=0; 167 | ram_read=0; 168 | rom_ena=1; 169 | rom_read=1; 170 | ad_sel=0; 171 | fetch=2'b10; 172 | end 173 | S5: begin 174 | if (ins==LDO) 175 | begin 176 | write_r=1; 177 | read_r=0; 178 | PC_en=0; 179 | ac_ena=1; 180 | ram_ena=0; 181 | ram_write=0; 182 | ram_read=0; 183 | rom_ena=1; 184 | rom_read=1; 185 | ad_sel=1; 186 | fetch=2'b01; 187 | end 188 | else 189 | begin 190 | write_r=1; 191 | read_r=0; 192 | PC_en=0; 193 | ac_ena=1; 194 | ram_ena=1; 195 | ram_write=0; 196 | ram_read=1; 197 | rom_ena=0; 198 | rom_read=0; 199 | ad_sel=1; 200 | fetch=2'b01; 201 | end 202 | end 203 | S6: begin 204 | 205 | write_r=1'b0; 206 | read_r=1'b0; 207 | PC_en=1'b0; //** not so sure, log: change 1 to 0 208 | ac_ena=1'b0; 209 | ram_ena=1'b0; 210 | rom_ena=1'b0; 211 | ram_write=1'b0; 212 | ram_read=1'b0; 213 | rom_read=1'b0; 214 | ad_sel=1'b0; 215 | fetch=2'b00; 216 | end 217 | 218 | S7: begin // STO, reg->ram. step1. read REG 219 | write_r=0; 220 | read_r=1; 221 | PC_en=0; 222 | ac_ena=0; 223 | ram_ena=0; 224 | rom_ena=0; 225 | ram_write=0; 226 | ram_read=0; 227 | rom_read=0; 228 | ad_sel=0; 229 | fetch=2'b00; 230 | end 231 | S8: begin // STO, step2, write RAM 232 | write_r=0; 233 | read_r=1; 234 | PC_en=0; 235 | ac_ena=0; 236 | rom_read=0; 237 | rom_ena=0; 238 | 239 | ram_ena=1; 240 | ram_write=1; 241 | ram_read=0; 242 | 243 | ad_sel=1; 244 | fetch=2'b00; //fetch=2'b10, ram_ena=1, ram_write=1, ad_sel=1; 245 | end 246 | S9: begin 247 | if (ins==PRE) // REG->ACCUM 248 | begin 249 | write_r=0; 250 | read_r=1; 251 | PC_en=0; 252 | ac_ena=1; 253 | ram_ena=0; 254 | rom_ena=0; 255 | ram_write=0; 256 | ram_read=0; 257 | rom_read=0; 258 | ad_sel=0; 259 | fetch=2'b00; 260 | end 261 | else 262 | begin 263 | write_r=0; 264 | read_r=1; 265 | PC_en=0; 266 | ac_ena=1; 267 | ram_ena=0; 268 | rom_ena=0; 269 | ram_write=0; 270 | ram_read=0; 271 | rom_read=0; 272 | ad_sel=0; 273 | 274 | fetch=2'b00; 275 | end 276 | end 277 | S10: begin 278 | write_r=0; 279 | read_r=1; 280 | PC_en=0; 281 | ac_ena=0; 282 | ram_ena=0; 283 | rom_ena=0; 284 | ram_write=0; 285 | ram_read=0; 286 | rom_read=0; 287 | ad_sel=0; 288 | fetch=2'b00; 289 | end 290 | S11: begin // LDM, step1, write reg 291 | write_r=1; 292 | read_r=0; 293 | PC_en=0; 294 | ac_ena=1; 295 | ram_ena=0; 296 | 297 | ram_write=0; 298 | ram_read=0; 299 | rom_ena=1; 300 | rom_read=1; 301 | ad_sel=0; 302 | fetch=2'b00; 303 | 304 | end 305 | S12: begin 306 | write_r=0; 307 | read_r=0; 308 | PC_en=0; 309 | ac_ena=0; 310 | ram_ena=0; 311 | rom_ena=0; 312 | ram_write=0; 313 | ram_read=0; 314 | rom_read=0; 315 | ad_sel=0; 316 | fetch=2'b00; 317 | end 318 | default: begin 319 | write_r=0; 320 | read_r=0; 321 | PC_en=0; 322 | ac_ena=0; 323 | ram_ena=0; 324 | rom_ena=0; 325 | ram_write=0; 326 | ram_read=0; 327 | rom_read=0; 328 | ad_sel=0; 329 | fetch=2'b00; 330 | end 331 | endcase 332 | end 333 | endmodule 334 | -------------------------------------------------------------------------------- /core.v: -------------------------------------------------------------------------------- 1 | module core(clk, rst); // Top-level entity(except core-tb) 2 | input clk, rst; 3 | 4 | wire write_r, read_r, PC_en, ac_ena, ram_ena, rom_ena; 5 | wire ram_write, ram_read, rom_read, ad_sel; 6 | 7 | wire [1:0] fetch; 8 | wire [7:0] data, addr; 9 | wire [7:0] accum_out, alu_out; 10 | wire [7:0] ir_ad, pc_ad; 11 | wire [4:0] reg_ad; 12 | wire [2:0] ins; 13 | 14 | ram RAM1(.data(data), .addr(addr), .ena(ram_ena), .read(ram_read), .write(ram_write)); //module ram(data, addr, ena, read, write); 15 | 16 | rom ROM1(.data(data), .addr(addr), .ena(rom_ena), .read(rom_read)); //module rom(data, addr, read, ena); 17 | 18 | addr_mux MUX1(.addr(addr), .sel(ad_sel), .ir_ad(ir_ad), .pc_ad(pc_ad)); //module addr_mux(addr, sel, ir_ad, pc_ad); 19 | 20 | counter PC1(.pc_addr(pc_ad), .clock(clk), .rst(rst), .en(PC_en)); //module counter(pc_addr, clock, rst, en); 21 | 22 | accum ACCUM1(.out(accum_out), .in(alu_out), .ena(ac_ena), .clk(clk), .rst(rst)); //module accum( in, out, ena, clk, rst); 23 | 24 | alu ALU1(.alu_out(alu_out), .alu_in(data), .accum(accum_out), .op(ins)); // module alu(alu_out, alu_in, accum, op); 25 | 26 | reg_32 REG1(.in(alu_out), .data(data), .write(write_r), .read(read_r), .addr({ins,reg_ad}), .clk(clk)); //module reg_32(in, data, write, read, addr, clk); 27 | //reg_32 REG1(.in(alu_out), .data(data), .write(write_r), .read(read_r), .addr(reg_ad), .clk(clk)); //module reg_32(in, data, write, read, addr, clk); 28 | 29 | ins_reg IR1(.data(data), .fetch(fetch), .clk(clk), .rst(rst), .ins(ins), .ad1(reg_ad), .ad2(ir_ad)); //module ins_reg(data, fetch, clk, rst, ins, ad1, ad2); 30 | 31 | //module machine(ins, clk, rst, write_r, read_r, PC_en, fetch, ac_ena, ram_ena, rom_ena,ram_write, ram_read, rom_read, ad_sel); 32 | controller CONTROLLER1(.ins(ins), 33 | .clk(clk), 34 | .rst(rst), 35 | .write_r(write_r), 36 | .read_r(read_r), 37 | .PC_en(PC_en), 38 | .fetch(fetch), 39 | .ac_ena(ac_ena), 40 | .ram_ena(ram_ena), 41 | .rom_ena(rom_ena), 42 | .ram_write(ram_write), 43 | .ram_read(ram_read), 44 | .rom_read(rom_read), 45 | .ad_sel(ad_sel) 46 | ); 47 | 48 | 49 | endmodule 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /core_tb_00.v: -------------------------------------------------------------------------------- 1 | `timescale 1ps / 1ps 2 | module core_tb_00 ; 3 | 4 | reg rst ; 5 | reg clk ; 6 | core 7 | DUT ( 8 | .rst (rst ) , 9 | .clk (clk ) ); 10 | 11 | 12 | 13 | // "Clock Pattern" : dutyCycle = 50 14 | // Start Time = 0 ps, End Time = 10 ns, Period = 100 ps 15 | initial 16 | begin 17 | clk = 1'b0 ; 18 | # 150 ; 19 | // 50 ps, single loop till start period. 20 | repeat(99) 21 | begin 22 | clk = 1'b1 ; 23 | #50 clk = 1'b0 ; 24 | #50 ; 25 | // 9950 ps, repeat pattern in loop. 26 | end 27 | clk = 1'b1 ; 28 | # 50 ; 29 | // dumped values till 10 ns 30 | end 31 | 32 | 33 | // "Constant Pattern" 34 | // Start Time = 0 ps, End Time = 10 ns, Period = 0 ps 35 | initial 36 | begin 37 | rst = 1'b0 ; 38 | # 100; 39 | rst=1'b1; 40 | # 9000 ; 41 | // dumped values till 10 ns 42 | end 43 | 44 | initial 45 | #20000 $stop; 46 | endmodule 47 | -------------------------------------------------------------------------------- /counter.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | //PC, program counter 3 | module counter(pc_addr, clock, rst, en); 4 | input clock, rst, en; 5 | output reg [7:0] pc_addr; 6 | 7 | always @(posedge clock or negedge rst) begin 8 | if(!rst) begin 9 | pc_addr <= 8'd0; 10 | end 11 | else begin 12 | if(en) pc_addr <= pc_addr+1; 13 | else pc_addr <= pc_addr; 14 | end 15 | end 16 | 17 | endmodule -------------------------------------------------------------------------------- /ins_reg.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | module ins_reg(data, fetch, clk, rst, ins, ad1, ad2); // instruction register 4 | input clk, rst; 5 | input [1:0] fetch; 6 | input [7:0] data; 7 | output [2:0] ins; 8 | output [4:0] ad1; 9 | output [7:0] ad2; 10 | 11 | reg [7:0] ins_p1, ins_p2; 12 | reg [2:0] state; 13 | 14 | assign ins = ins_p1[7:5]; //hign 3 bits, instructions 15 | assign ad1 = ins_p1[4:0]; //low 5 bits, register address 16 | assign ad2 = ins_p2; 17 | 18 | always @(posedge clk or negedge rst) begin 19 | if(!rst) begin 20 | ins_p1 <= 8'd0; 21 | ins_p2 <= 8'd0; 22 | end 23 | else begin 24 | if(fetch==2'b01) begin //fetch==2'b01 operation1, to fetch data from REG 25 | ins_p1 <= data; 26 | ins_p2 <= ins_p2; 27 | end 28 | else if(fetch==2'b10) begin //fetch==2'b10 operation2, to fetch data from RAM/ROM 29 | ins_p1 <= ins_p1; 30 | ins_p2 <= data; 31 | end 32 | else begin 33 | ins_p1 <= ins_p1; 34 | ins_p2 <= ins_p2; 35 | end 36 | end 37 | end 38 | 39 | 40 | endmodule 41 | -------------------------------------------------------------------------------- /machine.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | module machine(ins, clk, rst, write_r, read_r, PC_en, fetch, ac_ena, ram_ena, rom_ena,ram_write, ram_read, rom_read, ad_sel); 4 | 5 | input clk, rst; // clock, reset 6 | input [2:0] ins; // instructions, 3 bits, 8 types 7 | 8 | // Enable signals 9 | output reg write_r, read_r, PC_en, ac_ena, ram_ena, rom_ena; 10 | 11 | // ROM: where instructions are storaged. Read only. 12 | // RAM: where data is storaged, readable and writable. 13 | output reg ram_write, ram_read, rom_read, ad_sel; 14 | 15 | output reg [1:0] fetch; // 01: to fetch from RAM/ROM; 10: to fetch from REG 16 | 17 | // State code(current state) 18 | reg [3:0] state; // current state 19 | reg [3:0] next_state; // next state 20 | 21 | 22 | // instruction code 23 | parameter NOP=3'b000, // no operation 24 | LDO=3'b001, // load ROM to register 25 | LDA=3'b010, // load RAM to register 26 | STO=3'b011, // Store intermediate results to accumulator 27 | PRE=3'b100, // Prefetch Data from Address 28 | ADD=3'b101, // Adds the contents of the memory address or integer to the accumulator 29 | LDM=3'b110, // Load Multiple 30 | HLT=3'b111; // Halt 31 | 32 | // state code 33 | parameter Sidle=4'hf, 34 | S0=4'd0, 35 | S1=4'd1, 36 | S2=4'd2, 37 | S3=4'd3, 38 | S4=4'd4, 39 | S5=4'd5, 40 | S6=4'd6, 41 | S7=4'd7, 42 | S8=4'd8, 43 | S9=4'd9, 44 | S10=4'd10, 45 | S11=4'd11, 46 | S12=4'd12; 47 | 48 | //PART A: D flip latch; State register 49 | always @(posedge clk or negedge rst) 50 | begin 51 | if(!rst) state<=Sidle; 52 | //current_state <= Sidle; 53 | else state<=next_state; 54 | //current_state <= next_state; 55 | end 56 | 57 | 58 | //PART B: Next-state combinational logic 59 | always @* 60 | begin 61 | case(state) 62 | S1: begin 63 | if (ins==NOP) next_state=S0; 64 | else if (ins==HLT) next_state=S2; 65 | else if (ins==PRE | ins==ADD) next_state=S9; 66 | else if (ins==LDM) next_state=S11; 67 | else next_state=S3; 68 | end 69 | 70 | S4: begin 71 | if (ins==LDA | ins==LDO) next_state=S5; 72 | //else if (ins==STO) next_state=S7; 73 | else next_state=S7; // ---Note: there are only 3 long instrucions. So, all the cases included. if (counter_A==2*b11) 74 | end 75 | Sidle: next_state=S0; 76 | S0: next_state=S1; 77 | S2: next_state=S2; 78 | S3: next_state=S4; 79 | S5: next_state=S6; 80 | S6: next_state=S0; 81 | S7: next_state=S8; 82 | S8: next_state=S0; 83 | S9: next_state=S10; 84 | S10: next_state=S0; 85 | S11: next_state=S12; 86 | S12: next_state=S0; 87 | default: next_state=Sidle; 88 | endcase 89 | 90 | // assign style 91 | // TODO 92 | end 93 | 94 | // another style 95 | //PART C: Output combinational logic 96 | always@* 97 | begin 98 | case(state) 99 | // --Note: for each statement, we concentrate on the current state, not next_state 100 | // because it is combinational logic. 101 | Sidle: begin 102 | write_r=1'b0; 103 | read_r=1'b0; 104 | PC_en=1'b0; //** not so sure, log: change 1 to 0 105 | ac_ena=1'b0; 106 | ram_ena=1'b0; 107 | rom_ena=1'b0; 108 | ram_write=1'b0; 109 | ram_read=1'b0; 110 | rom_read=1'b0; 111 | ad_sel=1'b0; 112 | fetch=2'b00; 113 | end 114 | S0: begin // load IR 115 | write_r=0; 116 | read_r=0; 117 | PC_en=0; 118 | ac_ena=0; 119 | ram_ena=0; 120 | rom_ena=1; 121 | ram_write=0; 122 | ram_read=0; 123 | rom_read=1; 124 | ad_sel=0; 125 | fetch=2'b01; 126 | 127 | //write_r, read_r, PC_en, ac_ena, ram_ena, rom_ena; 128 | //ram_write, ram_read, rom_read, ad_sel; 129 | 130 | // fetch=2'b01; // fetch ins+reg_addr from ROM 131 | // rom_read=1; 132 | // rom_ena=1; 133 | end 134 | S1: begin 135 | write_r=0; 136 | read_r=0; 137 | PC_en=1; //PC+1 138 | ac_ena=0; 139 | ram_ena=0; 140 | rom_ena=0; 141 | ram_write=0; 142 | ram_read=0; 143 | rom_read=0; 144 | ad_sel=0; 145 | fetch=2'b00; 146 | // 147 | // PC_en=1; 148 | // ad_sel=0; // **not so sure, sel=0, select pc_addr(where next ins located) 149 | end 150 | S2: begin 151 | write_r=0; 152 | read_r=0; 153 | PC_en=0; 154 | ac_ena=0; 155 | ram_ena=0; 156 | rom_ena=0; 157 | ram_write=0; 158 | ram_read=0; 159 | rom_read=0; 160 | ad_sel=0; 161 | fetch=2'b00; 162 | end 163 | S3: begin 164 | write_r=0; 165 | read_r=0; 166 | PC_en=0; 167 | ac_ena=0; 168 | ram_ena=0; 169 | rom_ena=1; 170 | ram_write=0; 171 | ram_read=0; 172 | rom_read=1; 173 | ad_sel=0; 174 | fetch=2'b01; 175 | 176 | // fetch=2'b01; 177 | // rom_read=1; 178 | // rom_ena=1; 179 | end 180 | S4: begin 181 | write_r=0; 182 | read_r=0; 183 | PC_en=1; 184 | ac_ena=0; 185 | ram_ena=0; 186 | rom_ena=0; 187 | ram_write=0; 188 | ram_read=0; 189 | rom_read=0; 190 | ad_sel=0; 191 | fetch=2'b00; 192 | 193 | // PC_en=1; 194 | // ad_sel=0; 195 | end 196 | S5: begin 197 | if (ins==LDO) 198 | begin 199 | write_r=1; 200 | read_r=0; 201 | PC_en=0; 202 | ac_ena=0; 203 | ram_ena=0; 204 | rom_ena=1; 205 | ram_write=0; 206 | ram_read=0; 207 | rom_read=1; 208 | ad_sel=1; // ! Attention, don't forget 209 | fetch=2'b00; 210 | end 211 | else // ins==LDA 212 | begin 213 | write_r=1; 214 | read_r=0; 215 | PC_en=0; 216 | ac_ena=0; 217 | ram_ena=1; 218 | rom_ena=0; 219 | ram_write=0; 220 | ram_read=1; 221 | rom_read=0; 222 | ad_sel=1; 223 | fetch=2'b00; 224 | end 225 | 226 | // write_r=1; 227 | // ram_ena=1; 228 | end 229 | S6: begin // same as s5 230 | if (ins==LDO) 231 | begin 232 | write_r=1; 233 | read_r=0; 234 | PC_en=0; 235 | ac_ena=0; 236 | ram_ena=0; 237 | rom_ena=1; 238 | ram_write=0; 239 | ram_read=0; 240 | rom_read=1; 241 | ad_sel=1; 242 | fetch=2'b00; 243 | end 244 | else 245 | begin 246 | write_r=1; 247 | read_r=0; 248 | PC_en=0; 249 | ac_ena=0; 250 | ram_ena=1; 251 | rom_ena=0; 252 | ram_write=0; 253 | ram_read=1; 254 | rom_read=0; 255 | ad_sel=1; 256 | fetch=2'b00; 257 | end 258 | 259 | end 260 | S7: begin // STO, reg->ram. step1. read REG 261 | write_r=0; 262 | read_r=1; 263 | PC_en=0; 264 | ac_ena=0; 265 | ram_ena=0; 266 | rom_ena=0; 267 | ram_write=0; 268 | ram_read=0; 269 | rom_read=0; 270 | ad_sel=0; 271 | fetch=2'b01; 272 | 273 | //read_r=1; 274 | end 275 | S8: begin // STO, step2, write RAM 276 | write_r=0; 277 | read_r=0; 278 | PC_en=0; 279 | ac_ena=0; 280 | ram_ena=1; 281 | rom_ena=0; 282 | ram_write=1; 283 | ram_read=0; 284 | rom_read=0; 285 | ad_sel=1; 286 | fetch=2'b10; //fetch=2'b10, ram_ena=1, ram_write=1, ad_sel=1; 287 | 288 | // ram_ena=1; 289 | // ram_write=1; 290 | end 291 | S9: begin 292 | if (ins==PRE) // REG->ACCUM 293 | begin 294 | write_r=0; 295 | read_r=1; 296 | PC_en=0; 297 | ac_ena=0; 298 | ram_ena=0; 299 | rom_ena=0; 300 | ram_write=0; 301 | ram_read=0; 302 | rom_read=0; 303 | ad_sel=0; 304 | fetch=2'b01; 305 | end 306 | else // ins==ADD, same as PRE 307 | begin 308 | write_r=0; 309 | read_r=1; 310 | PC_en=0; 311 | ac_ena=0; 312 | ram_ena=0; 313 | rom_ena=0; 314 | ram_write=0; 315 | ram_read=0; 316 | rom_read=0; 317 | ad_sel=0; 318 | fetch=2'b01; 319 | end 320 | end 321 | S10: begin 322 | write_r=0; 323 | read_r=0; 324 | PC_en=0; 325 | ac_ena=1; 326 | ram_ena=0; 327 | rom_ena=0; 328 | ram_write=0; 329 | ram_read=0; 330 | rom_read=0; 331 | ad_sel=0; 332 | fetch=2'b01; 333 | 334 | //ac_ena=1; 335 | end 336 | S11: begin // LDM, step1, write reg 337 | write_r=1; 338 | read_r=0; 339 | PC_en=0; 340 | ac_ena=1; 341 | ram_ena=0; 342 | rom_ena=0; 343 | ram_write=0; 344 | ram_read=0; 345 | rom_read=0; 346 | ad_sel=0; 347 | fetch=2'b00; 348 | 349 | //write_r=1; 350 | end 351 | S12: begin // same as s11 352 | write_r=1; 353 | read_r=0; 354 | PC_en=0; 355 | ac_ena=1; 356 | ram_ena=0; 357 | rom_ena=0; 358 | ram_write=0; 359 | ram_read=0; 360 | rom_read=0; 361 | ad_sel=0; 362 | fetch=2'b00; 363 | end 364 | default: begin 365 | write_r=0; 366 | read_r=0; 367 | PC_en=0; 368 | ac_ena=0; 369 | ram_ena=0; 370 | rom_ena=0; 371 | ram_write=0; 372 | ram_read=0; 373 | rom_read=0; 374 | ad_sel=0; 375 | fetch=2'b00; 376 | end 377 | endcase 378 | end 379 | 380 | 381 | endmodule 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | -------------------------------------------------------------------------------- /output/design.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/output/design.pdf -------------------------------------------------------------------------------- /output/readme.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/output/readme.pdf -------------------------------------------------------------------------------- /output/schematic.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/output/schematic.pdf -------------------------------------------------------------------------------- /output/states.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/output/states.xlsx -------------------------------------------------------------------------------- /output/wave-video.wmv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuqdev/8-bits-RISC-CPU-Verilog/620e9c21dcda4822728ba7fad4ce3d9a0eea3e2d/output/wave-video.wmv -------------------------------------------------------------------------------- /output/wave.do: -------------------------------------------------------------------------------- 1 | onerror {resume} 2 | quietly WaveActivateNextPane {} 0 3 | add wave -noupdate /core_tb_00/DUT/clk 4 | add wave -noupdate /core_tb_00/DUT/rst 5 | add wave -noupdate /core_tb_00/DUT/write_r 6 | add wave -noupdate /core_tb_00/DUT/read_r 7 | add wave -noupdate /core_tb_00/DUT/PC_en 8 | add wave -noupdate /core_tb_00/DUT/ac_ena 9 | add wave -noupdate /core_tb_00/DUT/ram_ena 10 | add wave -noupdate /core_tb_00/DUT/rom_ena 11 | add wave -noupdate /core_tb_00/DUT/ram_write 12 | add wave -noupdate /core_tb_00/DUT/ram_read 13 | add wave -noupdate /core_tb_00/DUT/rom_read 14 | add wave -noupdate /core_tb_00/DUT/ad_sel 15 | add wave -noupdate /core_tb_00/DUT/fetch 16 | add wave -noupdate -radix unsigned /core_tb_00/DUT/data 17 | add wave -noupdate -radix unsigned /core_tb_00/DUT/addr 18 | add wave -noupdate -radix unsigned /core_tb_00/DUT/accum_out 19 | add wave -noupdate -radix unsigned /core_tb_00/DUT/alu_out 20 | add wave -noupdate -radix unsigned /core_tb_00/DUT/ir_ad 21 | add wave -noupdate -radix unsigned /core_tb_00/DUT/pc_ad 22 | add wave -noupdate -radix unsigned /core_tb_00/DUT/reg_ad 23 | add wave -noupdate /core_tb_00/DUT/ins 24 | TreeUpdate [SetDefaultTree] 25 | WaveRestoreCursors {{Cursor 1} {5038 ps} 0} 26 | quietly wave cursor active 1 27 | configure wave -namecolwidth 202 28 | configure wave -valuecolwidth 100 29 | configure wave -justifyvalue left 30 | configure wave -signalnamewidth 0 31 | configure wave -snapdistance 10 32 | configure wave -datasetprefix 0 33 | configure wave -rowmargin 4 34 | configure wave -childrowmargin 2 35 | configure wave -gridoffset 0 36 | configure wave -gridperiod 1 37 | configure wave -griddelta 40 38 | configure wave -timeline 0 39 | configure wave -timelineunits ps 40 | update 41 | WaveRestoreZoom {2625 ps} {7654 ps} 42 | -------------------------------------------------------------------------------- /ram.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | module ram(data, addr, ena, read, write); 4 | input ena, read, write; 5 | input [7:0] addr; 6 | inout [7:0] data; 7 | 8 | reg [7:0] ram[255:0]; 9 | 10 | assign data = (read&&ena)? ram[addr]:8'hzz; // read data from RAM 11 | 12 | always @(posedge write) begin // write data to RAM 13 | ram[addr] <= data; 14 | end 15 | 16 | endmodule 17 | -------------------------------------------------------------------------------- /readme.rst: -------------------------------------------------------------------------------- 1 | 8位RISC CPU的Verilog实现 2 | ======================== 3 | 4 | 5 | 一. 设计需求 6 | ------------ 7 | 8 | 当今绝大多数计算机,无论是大型机还是微型机其基本结构都是冯诺依曼体系结构,即计算机由控制器,运算器,存储器,和输入/输出设备五部分组成。指令和程序都是存储在存储器中。 9 | 10 | |image0| 11 | 12 | 中央处理器,也称微处理器(microprocessor),是计算机系统的核心。主要完成以下任务:(1)从存储器中取指令,指令译码;(2)执行简单的算数逻辑运算;(3)在处理器和存储器或I/O之间传送数据;(4)程序流向控制等[1]。 13 | 14 | RISC,reduced instruction set 15 | computer,精简指令集计算机相较于CISC,complex instruction set 16 | computer,复杂指令集计算机能够在一个始终周期执行更多的指令,这些指令比CISC的指令集具有更短,功能更简单,指令格式更统一等特点,因此适合流水线处理,加快处理速度。 17 | 18 | 8位CPU是上世纪70年代开始采用的典型CPU结构,代表产品有因特尔的8080系列[1]。是现代普遍采用的64位,32位总线结构CPU的起始。 19 | 20 | 本文将基于有限状态机(Finite State Machine, 21 | FSM)采用Verilog硬件描述语言对8位RISC架构CPU进行实现。 22 | 23 | 二. 硬件组成 24 | ------------ 25 | 26 | |image1| 27 | 28 | 如图是微型计算机系统中关键组成部分,包含CPU,存储器,数据和地址总线。CPU主要由算数逻辑单元(ALU,Arithmetic 29 | Logic 30 | Unit),累加器(accumulator),通用寄存器(registers),程序计数器(PC,Program 31 | Counter),指令寄存器(IR,Instruction Register),地址选择器(address 32 | multiplexer)组成。存储器这里指主存储器,分为随机存取存储器RAM(Radom 33 | Access Memory)和只读存储器ROM(Read Only 34 | Memory)。主存和CPU之间通过总线访问,总线有地址总线(Address 35 | Bus)和数据总线(Data Address)两种。 36 | 37 | 2.1 存储器 38 | ~~~~~~~~~~ 39 | 40 | 2.1.1 ROM 41 | ^^^^^^^^^ 42 | 43 | ROM用于存储要执行的指令,关于指令的介绍见第三章。 44 | 45 | Verilog实现: 46 | 47 | .. code:: verilog 48 | 49 | module rom(data, addr, read, ena); 50 | input read, ena; 51 | input [7:0] addr; 52 | output [7:0] data; 53 | 54 | reg [7:0] memory[255:0]; 55 | 56 | 57 | // note: Decimal number in the bracket 58 | initial begin 59 | memory[0] = 8'b000_00000; //NOP 60 | ... // some instructions 61 | end 62 | 63 | assign data = (read&&ena)? memory[addr]:8'hzz; 64 | 65 | endmodule 66 | 67 | ROM,只读指令。接受输入地址,当读信号和使能信号高电平时输出对应地址存储的指令,否则输出保持高阻态。地址和数据都是8位,可寻址以及内部存储的大小为256Bytes。 68 | 69 | |image2| 70 | 71 | RTL(register-transfer level,寄存器传输级)综合如上图所示。 72 | 73 | 2.2.2 RAM 74 | ^^^^^^^^^ 75 | 76 | 存储数据,可读可写。 77 | 78 | Verilog实现: 79 | 80 | .. code:: verilog 81 | 82 | module ram(data, addr, ena, read, write); 83 | input ena, read, write; 84 | input [7:0] addr; 85 | inout [7:0] data; 86 | 87 | reg [7:0] ram[255:0]; 88 | 89 | assign data = (read&&ena)? ram[addr]:8'hzz; // read data from RAM 90 | 91 | always @(posedge write) begin // write data to RAM 92 | ram[addr] <= data; 93 | end 94 | endmodule 95 | 96 | 可读可写,接收8位地址,当读信号和使能信号有效时,输出对应地址存储的数据,否则输出保持高阻态。当写信号上升沿是触发,将输入输出写入地址对应位置。内部存储以及可循址大小也为256Byters。 97 | 98 | |image3| 99 | 100 | RTL视图如上。 101 | 102 | 2.2 CPU 103 | ~~~~~~~ 104 | 105 | 2.2.1 PC 106 | ^^^^^^^^ 107 | 108 | 程序计数器,有时也叫做指令地址寄存器(Instruction Address Register, 109 | IAR),对应于Intel X86体系CPU中的指令指针(Instruction 110 | pointer)寄存器。其功能是用来存放要执行的下一条指令在现行代码段中的偏移地址。本文中PC由Controller自动修改,使得其中始终存放着下一条将要执行指令的地址。因此,PC是用来控制指令序列执行流程的寄存器[2]。 111 | 112 | Verilog实现: 113 | 114 | .. code:: verilog 115 | 116 | //PC, program counter 117 | module counter(pc_addr, clock, rst, en); 118 | input clock, rst, en; 119 | output reg [7:0] pc_addr; 120 | always @(posedge clock or negedge rst) begin 121 | if(!rst) pc_addr <= 8'd0; 122 | else begin 123 | if(en) pc_addr <= pc_addr+1; 124 | else pc_addr <= pc_addr; 125 | end 126 | end 127 | endmodule 128 | 129 | 异步清零。时钟上升沿触发,高电平使能时程序计数器计数,指向下一条要执行指令的地址。指令存储在ROM中,故每次pc_addr加1。 130 | 131 | |image4| 132 | 133 | RTL视图如上。 134 | 135 | 2.2.2 累加器 136 | ^^^^^^^^^^^^ 137 | 138 | 累加器,用于储存计算的中间结果。 139 | 140 | Verilog实现: 141 | 142 | .. code:: verilog 143 | 144 | // Accumulator 145 | module accum( in, out, ena, clk, rst); 146 | // a register, to storage result after computing 147 | input clk,rst,ena; 148 | input [7:0] in; 149 | output reg [7:0] out; 150 | 151 | always @(posedge clk or negedge rst) begin 152 | if(!rst) out <= 8'd0; 153 | else begin 154 | if(ena) out <= in; 155 | else out <= out; 156 | end 157 | end 158 | endmodule 159 | 160 | 异步清零。时钟上升沿触发,高电平使能时输出当前输入信号。 161 | 162 | |image5| 163 | 164 | RTL视图如上,可以看出其是一个Q触发器来实现。 165 | 166 | 2.2.3 地址选择器 167 | ^^^^^^^^^^^^^^^^ 168 | 169 | 接受控制使能信号对输入的来自程序计数器和指令寄存器的地址进行选择。 170 | 171 | Verilog实现: 172 | 173 | .. code:: verilog 174 | 175 | // Address multiplexer 176 | module addr_mux(addr, sel, ir_ad, pc_ad); 177 | // To choose address of instruction register or address of program counter 178 | input [7:0] ir_ad, pc_ad; 179 | input sel; 180 | output [7:0] addr; 181 | assign addr = (sel)? ir_ad:pc_ad; 182 | endmodule 183 | 184 | 当选择信号为1时,选择来自寄存器输入的地址到数据总线,否则将程序计数器中的地址加载到数据总线。 185 | 186 | |image6| 187 | 188 | RTL视图如上。 189 | 190 | 2.2.4 ALU 191 | ^^^^^^^^^ 192 | 193 | 算术逻辑运算单元,根据指令类型来决定进行哪种运算,从而将运算结果输出通用寄存器或者累加器中。 194 | 195 | .. code:: verilog 196 | 197 | module alu(alu_out, alu_in, accum, op); 198 | // Arithmetic logic unit 199 | // to perform arithmetic and logic operations. 200 | input [2:0] op; 201 | input [7:0] alu_in,accum; 202 | output reg [7:0] alu_out; 203 | 204 | parameter NOP=3'b000, 205 | LDO=3'b001, 206 | LDA=3'b010, 207 | STO=3'b011, 208 | PRE=3'b100, 209 | ADD=3'b101, 210 | LDM=3'b110, 211 | HLT=3'b111; 212 | 213 | always @(*) begin 214 | casez(op) 215 | NOP: alu_out = accum; 216 | HLT: alu_out = accum; 217 | LDO: alu_out = alu_in; 218 | LDA: alu_out = alu_in; 219 | STO: alu_out = accum; 220 | PRE: alu_out = alu_in; 221 | ADD: alu_out = accum+alu_in; 222 | LDM: alu_out = accum; 223 | default: alu_out = 8'bzzzz_zzzz; 224 | endcase 225 | end 226 | endmodule 227 | 228 | |image7| 229 | 230 | RTL视图如上。 231 | 232 | 2.2.5 通用寄存器 233 | ^^^^^^^^^^^^^^^^ 234 | 235 | 通用寄存器,ALU输出结果,指令寄存器输出的操作数都可以存储到寄存器中的特定的地址。输出寄存器中存储的数据到数据总线。 236 | 237 | Verilog实现: 238 | 239 | .. code:: verilog 240 | 241 | module reg_32(in, data, write, read, addr, clk); 242 | input write, read, clk; 243 | input [7:0] in; 244 | input [7:0] addr; 245 | //!Warning: addr should be reduced to 5 bits width, not 8 bits width. 246 | //input [4:0] addr; 247 | 248 | output [7:0] data; 249 | 250 | reg [7:0] R[31:0]; //32Byte 251 | wire [4:0] r_addr; 252 | 253 | assign r_addr = addr[4:0]; 254 | assign data = (read)? R[r_addr]:8'hzz; //read enable 255 | 256 | always @(posedge clk) begin //write, clk posedge 257 | if(write) R[r_addr] <= in; 258 | end 259 | endmodule 260 | 261 | 当写信号有效时,将输入数据(来自ALU的输出)存储到寄存器中的特定地址。当读信号有效时,将寄存器中特定位置的数据输出(到数据总线)。寄存器大小为32Bytes。 262 | 263 | |image8| 264 | 265 | RTL视图如上。 266 | 267 | 2.2.6 IR 268 | ^^^^^^^^ 269 | 270 | 指令寄存器,从数据总线上获取数据,根据输入控制信号,根据指令类型将特定指令和地址输出到ALU,通用寄存器和地址选择器。 271 | 272 | verilog实现: 273 | 274 | .. code:: verilog 275 | 276 | // instruction register 277 | module ins_reg(data, fetch, clk, rst, ins, ad1, ad2); 278 | input clk, rst; 279 | input [1:0] fetch; 280 | input [7:0] data; 281 | output [2:0] ins; 282 | output [4:0] ad1; 283 | output [7:0] ad2; 284 | 285 | reg [7:0] ins_p1, ins_p2; 286 | reg [2:0] state; 287 | 288 | assign ins = ins_p1[7:5]; //hign 3 bits, instructions 289 | assign ad1 = ins_p1[4:0]; //low 5 bits, register address 290 | assign ad2 = ins_p2; 291 | 292 | always @(posedge clk or negedge rst) begin 293 | if(!rst) begin 294 | ins_p1 <= 8'd0; 295 | ins_p2 <= 8'd0; 296 | end 297 | else begin 298 | if(fetch==2'b01) begin //fetch==2'b01 operation1, to fetch data from REG 299 | ins_p1 <= data; 300 | ins_p2 <= ins_p2; 301 | end 302 | else if(fetch==2'b10) begin //fetch==2'b10 operation2, to fetch data from RAM/ROM 303 | ins_p1 <= ins_p1; 304 | ins_p2 <= data; 305 | end 306 | else begin 307 | ins_p1 <= ins_p1; 308 | ins_p2 <= ins_p2; 309 | end 310 | end 311 | end 312 | endmodule 313 | 314 | 异步清零。当输入控制信号为\ ``01``\ 时表示数据总线当前为指令(形式为指令编码+寄存器地址,见第三章),将其从\ ``ins``\ 和\ ``ad1``\ 输出,当控制信号为\ ``10``\ 时,表示当前数据总线上的为数据(8位地址数据,见第三章),将其从\ ``ad2``\ 输出到地址选择器。 315 | 316 | |image9| 317 | 318 | RTL视图如上。 319 | 320 | 2.3 内部结构(总) 321 | ~~~~~~~~~~~~~~~~~~ 322 | 323 | |image10| 324 | 325 | 如图是系统内部结构原理图,显示了各个部件之间的连接关系,数据总线和地址总线是总线系统的核心。其中地址总线连接了地址选择器的输出,ROM以及RAM的输入端。地址总线和ROM/RAM的输出,IR和ALU的输入,以及通用寄存器的输出相连。控制器controller(图左上方)是系统的控制单元,相关细节见第四章。 326 | 327 | 整个硬件系统使用元件例化语句的Verilog描述如下: 328 | 329 | .. code:: verilog 330 | 331 | // Core 332 | // Top-level entity(except core-tb) 333 | module core(clk, rst); 334 | input clk, rst; 335 | 336 | wire write_r, read_r, PC_en, ac_ena, ram_ena, rom_ena; 337 | wire ram_write, ram_read, rom_read, ad_sel; 338 | 339 | wire [1:0] fetch; 340 | wire [7:0] data, addr; 341 | wire [7:0] accum_out, alu_out; 342 | wire [7:0] ir_ad, pc_ad; 343 | wire [4:0] reg_ad; 344 | wire [2:0] ins; 345 | 346 | ram RAM1(.data(data), 347 | .addr(addr), 348 | .ena(ram_ena), 349 | .read(ram_read), 350 | .write(ram_write)); //module ram(data, addr, ena, read, write); 351 | 352 | rom ROM1(.data(data), 353 | .addr(addr), 354 | .ena(rom_ena), 355 | .read(rom_read)); //module rom(data, addr, read, ena); 356 | 357 | addr_mux MUX1(.addr(addr), 358 | .sel(ad_sel), 359 | .ir_ad(ir_ad), 360 | .pc_ad(pc_ad)); //module addr_mux(addr, sel, ir_ad, pc_ad); 361 | 362 | counter PC1(.pc_addr(pc_ad), 363 | .clock(clk), 364 | .rst(rst), 365 | .en(PC_en)); //module counter(pc_addr, clock, rst, en); 366 | 367 | accum ACCUM1(.out(accum_out), 368 | .in(alu_out), 369 | .ena(ac_ena), 370 | .clk(clk), 371 | .rst(rst)); //module accum( in, out, ena, clk, rst); 372 | 373 | alu ALU1(.alu_out(alu_out), 374 | .alu_in(data), 375 | .accum(accum_out), 376 | .op(ins)); // module alu(alu_out, alu_in, accum, op); 377 | 378 | reg_32 REG1(.in(alu_out), 379 | .data(data), 380 | .write(write_r), 381 | .read(read_r), 382 | .addr({ins,reg_ad}), 383 | .clk(clk)); 384 | //module reg_32(in, data, write, read, addr, clk); 385 | //reg_32 REG1(.in(alu_out), .data(data), .write(write_r), .read(read_r), .addr(reg_ad), .clk(clk)); 386 | //module reg_32(in, data, write, read, addr, clk); 387 | 388 | ins_reg IR1(.data(data), 389 | .fetch(fetch), 390 | .clk(clk), 391 | .rst(rst), 392 | .ins(ins), 393 | .ad1(reg_ad), 394 | .ad2(ir_ad)); 395 | //module ins_reg(data, fetch, clk, rst, ins, ad1, ad2); 396 | 397 | //module machine(ins, clk, rst, write_r, read_r, PC_en, fetch, ac_ena, ram_ena, rom_ena,ram_write, ram_read, rom_read, ad_sel); 398 | controller CONTROLLER1(.ins(ins), 399 | .clk(clk), 400 | .rst(rst), 401 | .write_r(write_r), 402 | .read_r(read_r), 403 | .PC_en(PC_en), 404 | .fetch(fetch), 405 | .ac_ena(ac_ena), 406 | .ram_ena(ram_ena), 407 | .rom_ena(rom_ena), 408 | .ram_write(ram_write), 409 | .ram_read(ram_read), 410 | .rom_read(rom_read), 411 | .ad_sel(ad_sel) 412 | ); 413 | endmodule 414 | 415 | |image11| 416 | 417 | 各个模块进行例化后的系统总体RTL视图如上。 418 | 419 | 三. 指令集 420 | ---------- 421 | 422 | 我们定义的RISC指令集长度类型两种,分别为短指令和长指令: 423 | 424 | |image12| 425 | 426 | |image13| 427 | 428 | 其中指令编码采用三位二进制表示,共定义有8种指令。短指令共8位,高三位为指令编码,低五位为通用寄存器地址。长指令为16位,每个长指令分两次取,每次取8位,首先取高8位,格式和短指令相通,也是高3位为指令编码,低5位为通用寄存器地址;第二次取低8位,表示ROM或者RAM地址,取决于指令编码。 429 | 430 | 因此有指令集如下表所示,为了方便理解指令的缩写含义,表中用英文进行了描述并将缩写的由来使用加粗来表示: 431 | 432 | +---+---+---------------------------------------+---+---------------------+ 433 | | I | B | Description | T | Comment | 434 | | N | i | | y | | 435 | | S | n | | p | | 436 | | | a | | e | | 437 | | | r | | | | 438 | | | y | | | | 439 | +===+===+=======================================+===+=====================+ 440 | | N | 0 | **N**\ o **op**\ eration | S | 空操作 | 441 | | O | 0 | | h | | 442 | | P | 0 | | o | | 443 | | | | | r | | 444 | | | | | t | | 445 | +---+---+---------------------------------------+---+---------------------+ 446 | | L | 0 | **L**\ oa\ **d**\ s the contents of | L | REG[reg_addr]<-ROM[ | 447 | | D | 0 | the R\ **O**\ M address into the REG | o | ROM_addr] | 448 | | O | 1 | address | n | | 449 | | | | | g | | 450 | +---+---+---------------------------------------+---+---------------------+ 451 | | L | 0 | **L**\ oa\ **d**\ s the contents of | L | REG[reg_addr]<-RAM[ | 452 | | D | 1 | the R\ **A**\ M address into the REG | o | RAM_addr] | 453 | | A | 0 | address | n | | 454 | | | | | g | | 455 | +---+---+---------------------------------------+---+---------------------+ 456 | | S | 0 | **Sto**\ re intermediate results into | L | RAM[RAM_addr]<-REG[ | 457 | | T | 1 | RAM address | o | reg_addr] | 458 | | O | 1 | | n | | 459 | | | | | g | | 460 | +---+---+---------------------------------------+---+---------------------+ 461 | | P | 1 | **Pre**\ fetch Data from REG address | S | ACCUM<-REG[reg_addr | 462 | | R | 0 | | h | ] | 463 | | E | 0 | | o | | 464 | | | | | r | | 465 | | | | | t | | 466 | +---+---+---------------------------------------+---+---------------------+ 467 | | A | 1 | **Add**\ s the contents of the REG | S | accumulator<-REG[re | 468 | | D | 0 | address or integer to the accumulator | h | g_addr]+ | 469 | | D | 1 | | o | ACCUM | 470 | | | | | r | | 471 | | | | | t | | 472 | +---+---+---------------------------------------+---+---------------------+ 473 | | L | 1 | **Lo**\ ad **M**\ ultiple | S | REG[reg_addr]<-ACCU | 474 | | D | 1 | | h | M | 475 | | M | 0 | | o | | 476 | | | | | r | | 477 | | | | | t | | 478 | +---+---+---------------------------------------+---+---------------------+ 479 | | H | 1 | **H**\ a\ **lt** | S | 停机指令 | 480 | | L | 1 | | h | | 481 | | T | 1 | | o | | 482 | | | | | r | | 483 | | | | | t | | 484 | +---+---+---------------------------------------+---+---------------------+ 485 | 486 | 四. 控制器 487 | ---------- 488 | 489 | 控制器是系统的核心,具有以下功能:取指令,指令排队,读写操作数,总线控制等。这里采用(Mealy型)有限状态机(FSM)来实现控制器,指令存储在ROM中来执行,控制器接受外界时钟和复位信号,控制器根据当前状态以及输入进行状态的转移。 490 | 491 | 4.1 状态转移图 492 | ~~~~~~~~~~~~~~ 493 | 494 | |image14| 495 | 496 | 根据指令的任务,我们设计了如上图所示的状态转移图,从左至右依次为状态Sidle,S0~S12。各个状态的含义如下: 497 | 498 | ============ ============== =================================== 499 | Source State Description Comment 500 | ============ ============== =================================== 501 | S0 Load ir1 取指令1(短指令或者长指令的第一个) 502 | S1 PC+1 每执行一条PC+1 503 | S2 HLT 停机 504 | S3 Load ir2 取指令2 505 | S4 PC+1 每执行一条PC+1 506 | S5 ROM/RAM to REG LDA/LDO 507 | S6 Protect 写保护 508 | S7 Read REG STO第1阶段 509 | S8 Write RAM STO第2阶段 510 | S9 Read REG PRE/ADD,第1阶段 511 | S10 Write ACCUM PRE/ADD,第2阶段 512 | S11 Write REG LDM 513 | S12 Protect LDM 514 | Sidle Reset 重启 515 | ============ ============== =================================== 516 | 517 | 各个状态之间的转移有: 518 | 519 | ===== == == == == == == == == == == === === === ===== 520 | \ S0 S1 S2 S3 S4 S5 S6 S7 S8 S9 S10 S11 S12 Sidle 521 | ===== == == == == == == == == == == === === === ===== 522 | S0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 523 | S1 0 1 0 0 0 0 0 0 0 0 0 0 0 1 524 | S2 0 0 1 0 0 0 0 0 0 0 0 0 0 1 525 | S3 0 0 0 1 0 0 0 0 0 0 0 0 0 1 526 | S4 0 0 0 0 1 0 0 0 0 0 0 0 0 1 527 | S5 0 0 0 0 0 1 0 0 0 0 0 0 0 1 528 | S6 0 0 0 0 0 0 1 0 0 0 0 0 0 1 529 | S7 0 0 0 0 0 0 0 1 0 0 0 0 0 1 530 | S8 0 0 0 0 0 0 0 0 1 0 0 0 0 1 531 | S9 0 0 0 0 0 0 0 0 0 1 0 0 0 1 532 | S10 0 0 0 0 0 0 0 0 0 0 1 0 0 1 533 | S11 0 0 0 0 0 0 0 0 0 0 0 1 0 1 534 | S12 0 0 0 0 0 0 0 0 0 0 0 0 1 1 535 | Sidle 0 0 0 0 0 0 0 0 0 0 0 0 0 0 536 | ===== == == == == == == == == == == === === === ===== 537 | 538 | +--------+------------+-----------------------------------------------+ 539 | | Source | Destinatio | Condition | 540 | | State | n | | 541 | | | State | | 542 | +========+============+===============================================+ 543 | | S0 | S1 | | 544 | +--------+------------+-----------------------------------------------+ 545 | | S1 | S0 | (!ins[0]).(!ins[1]).(!ins[2]) | 546 | +--------+------------+-----------------------------------------------+ 547 | | S1 | S3 | (!ins[0]).(ins[1]).(!ins[2]) + | 548 | | | | (ins[0]).(!ins[2]) | 549 | +--------+------------+-----------------------------------------------+ 550 | | S1 | S11 | (!ins[0]).(ins[1]).(ins[2]) | 551 | +--------+------------+-----------------------------------------------+ 552 | | S1 | S9 | (!ins[1]).(ins[2]) | 553 | +--------+------------+-----------------------------------------------+ 554 | | S1 | S2 | (ins[0]).(ins[1]).(ins[2]) | 555 | +--------+------------+-----------------------------------------------+ 556 | | S2 | S2 | | 557 | +--------+------------+-----------------------------------------------+ 558 | | S3 | S4 | | 559 | +--------+------------+-----------------------------------------------+ 560 | | S4 | S7 | (!ins[0]).(!ins[1]) + | 561 | | | | (!ins[0]).(ins[1]).(ins[2]) + | 562 | | | | (ins[0]).(!ins[1]).(ins[2]) + | 563 | | | | (ins[0]).(ins[1]) | 564 | +--------+------------+-----------------------------------------------+ 565 | | S4 | S5 | (!ins[0]).(ins[1]).(!ins[2]) + | 566 | | | | (ins[0]).(!ins[1]).(!ins[2]) | 567 | +--------+------------+-----------------------------------------------+ 568 | | S5 | S6 | | 569 | +--------+------------+-----------------------------------------------+ 570 | | S6 | S0 | | 571 | +--------+------------+-----------------------------------------------+ 572 | | S7 | S8 | | 573 | +--------+------------+-----------------------------------------------+ 574 | | S8 | S0 | | 575 | +--------+------------+-----------------------------------------------+ 576 | | S9 | S10 | | 577 | +--------+------------+-----------------------------------------------+ 578 | | S10 | S0 | | 579 | +--------+------------+-----------------------------------------------+ 580 | | S11 | S12 | | 581 | +--------+------------+-----------------------------------------------+ 582 | | S12 | S0 | | 583 | +--------+------------+-----------------------------------------------+ 584 | | Sidle | S0 | | 585 | +--------+------------+-----------------------------------------------+ 586 | 587 | 例如我们可以看到S0,S1的状态转移: 588 | 589 | |image15| 590 | 591 | |image16| 592 | 593 | 详情请见附件\ ``fsm.pdf``\ 。 594 | 595 | 关于图示有限状态机的verilog实现,这里采用了经典的3段式结构:状态寄存器(state 596 | register),下一个状态组合逻辑电路(Next-state combinational 597 | logic),输出组合逻辑电路(Output combinational logic)。 598 | 599 | 4.2 FSM之状态寄存器 600 | ~~~~~~~~~~~~~~~~~~~ 601 | 602 | 本质是一个D触发器,负责将下一个状态赋给当前状态值(即跳转到下一个状态),异步清零。 603 | 604 | .. code:: verilog 605 | 606 | //PART A: D flip latch; State register 607 | always @(posedge clk or negedge rst) 608 | begin 609 | if(!rst) state<=Sidle; 610 | //current_state <= Sidle; 611 | else state<=next_state; 612 | //current_state <= next_state; 613 | end 614 | 615 | 4.3 FSM之下一个状态组合逻辑 616 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 617 | 618 | 负责控制状态的转移,这里下一个状态跟当前状态\ ``state``\ 以及输入\ ``ins``\ 均有关,属于Mealy型状态机。 619 | 620 | .. code:: verilog 621 | 622 | //PART B: Next-state combinational logic 623 | always @* 624 | begin 625 | case(state) 626 | S1: begin 627 | if (ins==NOP) next_state=S0; 628 | else if (ins==HLT) next_state=S2; 629 | else if (ins==PRE | ins==ADD) next_state=S9; 630 | else if (ins==LDM) next_state=S11; 631 | else next_state=S3; 632 | end 633 | 634 | S4: begin 635 | if (ins==LDA | ins==LDO) next_state=S5; 636 | //else if (ins==STO) next_state=S7; 637 | else next_state=S7; // ---Note: there are only 3 long instrucions. So, all the cases included. if (counter_A==2*b11) 638 | end 639 | Sidle: next_state=S0; 640 | S0: next_state=S1; 641 | S2: next_state=S2; 642 | S3: next_state=S4; 643 | S5: next_state=S6; 644 | S6: next_state=S0; 645 | S7: next_state=S8; 646 | S8: next_state=S0; 647 | S9: next_state=S10; 648 | S10: next_state=S0; 649 | S11: next_state=S12; 650 | S12: next_state=S0; 651 | default: next_state=Sidle; 652 | endcase 653 | end 654 | 655 | 4.4 FSM之输出组合逻辑 656 | ~~~~~~~~~~~~~~~~~~~~~ 657 | 658 | 输出组合逻辑电路根据当前状态以及输入命令,来确定输出值。 659 | 660 | 由于篇幅较长,见附录。 661 | 662 | 五. 测试及结果 663 | -------------- 664 | 665 | 为了验证RISC CPU功能的正确与否,下面进行芯片进行测试。 666 | 667 | 5.1 测试指令 668 | ~~~~~~~~~~~~ 669 | 670 | ROM中存储的指令如下: 671 | 672 | .. code:: verilog 673 | 674 | // note: Decimal number in the bracket 675 | initial begin 676 | memory[0] = 8'b000_00000; //NOP 677 | 678 | memory[1] = 8'b001_00001; //LDO s1 679 | memory[2] = 8'b010_00001; //rom(65) //end, reg[1]<-rom[65] 680 | memory[3] = 8'b001_00010; //LDO s2 681 | memory[4] = 8'b010_00010; //rom(66) //end, reg[2]<-rom[66] 682 | memory[5] = 8'b001_00011; //LDO s3 683 | memory[6] = 8'b010_00011; //rom(67) //end, reg[3]<-rom[67] 684 | 685 | memory[7] = 8'b100_00001; //PRE s1 686 | memory[8] = 8'b101_00010; //ADD s2 687 | memory[9] = 8'b110_00001; //LDM s1 // REG[1] <- REG[1]+REG[2] 688 | 689 | memory[10] = 8'b011_00001; //STO s1 690 | memory[11] = 8'b000_00001; //ram(1) // RAM[1] <- REG[1] 691 | memory[12] = 8'b010_00010; //LDA s2 692 | memory[13] = 8'b000_00001; //ram(1) // REG[2] <- RAM[1] 693 | 694 | memory[14] = 8'b100_00011; //PRE s3 695 | memory[15] = 8'b101_00010; //ADD s2 696 | memory[16] = 8'b110_00011; //LDM s3 // REG[3] <- REG[2]+REG[3] 697 | 698 | memory[17] = 8'b011_00011; //STO s3 699 | memory[18] = 8'b000_00010; //ram(2) //REG[3] -> ram[2] 700 | memory[19] = 8'b111_00000; //HLT 701 | 702 | memory[65] = 8'b001_00101; //37 703 | memory[66] = 8'b010_11001; //89 704 | memory[67] = 8'b001_10101; //53 705 | end 706 | 707 | 指令按照顺序执行,最终的结果是将ROM中的65,66,67位的三个数进行加法,存储到RAM[2]中,即实现三个数的加法,于此同时RAM[1]存放着前两个数加法的和。 708 | 709 | 5.2 Test-Bench 710 | ~~~~~~~~~~~~~~ 711 | 712 | 为了测试系统的功能,这里生成/编写test-bench文件,用于仿真: 713 | 714 | .. code:: verilog 715 | 716 | `timescale 1ps / 1ps 717 | module core_tb_00 ; 718 | 719 | reg rst ; 720 | reg clk ; 721 | core 722 | DUT ( 723 | .rst (rst ) , 724 | .clk (clk ) ); 725 | 726 | // "Clock Pattern" : dutyCycle = 50 727 | // Start Time = 0 ps, End Time = 10 ns, Period = 100 ps 728 | initial 729 | begin 730 | clk = 1'b0 ; 731 | # 150 ; 732 | // 50 ps, single loop till start period. 733 | repeat(99) 734 | begin 735 | clk = 1'b1 ; 736 | #50 clk = 1'b0 ; 737 | #50 ; 738 | // 9950 ps, repeat pattern in loop. 739 | end 740 | clk = 1'b1 ; 741 | # 50 ; 742 | // dumped values till 10 ns 743 | end 744 | 745 | 746 | // "Constant Pattern" 747 | // Start Time = 0 ps, End Time = 10 ns, Period = 0 ps 748 | initial 749 | begin 750 | rst = 1'b0 ; 751 | # 100; 752 | rst=1'b1; 753 | # 9000 ; 754 | // dumped values till 10 ns 755 | end 756 | 757 | initial 758 | #20000 $stop; 759 | endmodule 760 | 761 | 只需要给CPU两个信号,激励时钟\ ``clk``\ 和异步复位信号\ ``rst``\ 。 762 | 763 | 5.3 波形 764 | ~~~~~~~~ 765 | 766 | |image17| 767 | 768 | 根据ModelSIM仿真结果,如上图所示累加器输出最终结果179,在最后的停机指令前(图中6300ps处),addr地址为2,data为179,ram写,使能信号均为1,将最终结果写入到了RAM[2]中,指令指令结果无误。 769 | 770 | 从仿真波形中,不仅可以看出每个控制信号在每个时刻的状态,还可以看出每条指令执行的状态机的状态转换信息: 771 | 772 | |image18| 773 | 774 | 如图所示,从波形可以看出执行一个LDO长指令消耗了6个时钟周期,NOP指令消耗了两个时钟周期,和状态转换图一致,得到的结果和测试指令的输出要求一致。 775 | 776 | |image19| 777 | 778 | 如图是两个最重要的用来验证功能正确性的两个时刻,从波形可以看出,相应的计算结果126,179分别被写到了RAM的地址第1,2位置,相关控制信号正常。即达到了我们设计的功能。更多关于波形的情况,见附件即仿真源文件。 779 | 780 | 六. 结论 781 | -------- 782 | 783 | 本文构建了8位的RISC 784 | CPU,详细介绍了设计过程和实验测试,包括:硬件组成,指令集系统等。重点在于控制器的设计,基于有限状态机,实现了指令和状态之间的对应和转移,并进行了详实的仿真实验,结果证明CPU功能正常,达到了预期。 785 | 786 | 参考文献 787 | -------- 788 | 789 | [1]周荷琴, 吴秀清. 790 | 微型计算机原理和接口技术(第三版).中国科学技术大学出版社. 2008. 791 | 792 | 附录 793 | ---- 794 | 795 | **附录A Controller的Verilog实现** 796 | 797 | .. code:: verilog 798 | 799 | module controller(ins, clk, rst, write_r, read_r, PC_en, fetch, ac_ena, ram_ena, rom_ena,ram_write, ram_read, rom_read, ad_sel); 800 | 801 | input clk, rst; // clock, reset 802 | input [2:0] ins; // instructions, 3 bits, 8 types 803 | 804 | // Enable signals 805 | output reg write_r, read_r, PC_en, ac_ena, ram_ena, rom_ena; 806 | 807 | // ROM: where instructions are storaged. Read only. 808 | // RAM: where data is storaged, readable and writable. 809 | output reg ram_write, ram_read, rom_read, ad_sel; 810 | 811 | output reg [1:0] fetch; // 01: to fetch from RAM/ROM; 10: to fetch from REG 812 | 813 | // State code(current state) 814 | reg [3:0] state; // current state 815 | reg [3:0] next_state; // next state 816 | 817 | 818 | // instruction code 819 | parameter NOP=3'b000, // no operation 820 | LDO=3'b001, // load ROM to register 821 | LDA=3'b010, // load RAM to register 822 | STO=3'b011, // Store intermediate results to accumulator 823 | PRE=3'b100, // Prefetch Data from Address 824 | ADD=3'b101, // Adds the contents of the memory address or integer to the accumulator 825 | LDM=3'b110, // Load Multiple 826 | HLT=3'b111; // Halt 827 | 828 | // state code 829 | parameter Sidle=4'hf, 830 | S0=4'd0, 831 | S1=4'd1, 832 | S2=4'd2, 833 | S3=4'd3, 834 | S4=4'd4, 835 | S5=4'd5, 836 | S6=4'd6, 837 | S7=4'd7, 838 | S8=4'd8, 839 | S9=4'd9, 840 | S10=4'd10, 841 | S11=4'd11, 842 | S12=4'd12; 843 | 844 | //PART A: D flip latch; State register 845 | always @(posedge clk or negedge rst) 846 | begin 847 | if(!rst) state<=Sidle; 848 | //current_state <= Sidle; 849 | else state<=next_state; 850 | //current_state <= next_state; 851 | end 852 | 853 | //PART B: Next-state combinational logic 854 | always @* 855 | begin 856 | case(state) 857 | S1: begin 858 | if (ins==NOP) next_state=S0; 859 | else if (ins==HLT) next_state=S2; 860 | else if (ins==PRE | ins==ADD) next_state=S9; 861 | else if (ins==LDM) next_state=S11; 862 | else next_state=S3; 863 | end 864 | 865 | S4: begin 866 | if (ins==LDA | ins==LDO) next_state=S5; 867 | //else if (ins==STO) next_state=S7; 868 | else next_state=S7; // ---Note: there are only 3 long instrucions. So, all the cases included. if (counter_A==2*b11) 869 | end 870 | Sidle: next_state=S0; 871 | S0: next_state=S1; 872 | S2: next_state=S2; 873 | S3: next_state=S4; 874 | S5: next_state=S6; 875 | S6: next_state=S0; 876 | S7: next_state=S8; 877 | S8: next_state=S0; 878 | S9: next_state=S10; 879 | S10: next_state=S0; 880 | S11: next_state=S12; 881 | S12: next_state=S0; 882 | default: next_state=Sidle; 883 | endcase 884 | end 885 | 886 | // another style 887 | //PART C: Output combinational logic 888 | always@* 889 | begin 890 | case(state) 891 | // --Note: for each statement, we concentrate on the current state, not next_state 892 | // because it is combinational logic. 893 | Sidle: begin 894 | write_r=1'b0; 895 | read_r=1'b0; 896 | PC_en=1'b0; 897 | ac_ena=1'b0; 898 | ram_ena=1'b0; 899 | rom_ena=1'b0; 900 | ram_write=1'b0; 901 | ram_read=1'b0; 902 | rom_read=1'b0; 903 | ad_sel=1'b0; 904 | fetch=2'b00; 905 | end 906 | S0: begin // load IR 907 | write_r=0; 908 | read_r=0; 909 | PC_en=0; 910 | ac_ena=0; 911 | ram_ena=0; 912 | rom_ena=1; 913 | ram_write=0; 914 | ram_read=0; 915 | rom_read=1; 916 | ad_sel=0; 917 | fetch=2'b01; 918 | end 919 | S1: begin 920 | write_r=0; 921 | read_r=0; 922 | PC_en=1; 923 | ac_ena=0; 924 | ram_ena=0; 925 | ram_write=0; 926 | ram_read=0; 927 | rom_ena=1; 928 | rom_read=1; 929 | ad_sel=0; 930 | fetch=2'b00; 931 | end 932 | S2: begin 933 | write_r=0; 934 | read_r=0; 935 | PC_en=0; 936 | ac_ena=0; 937 | ram_ena=0; 938 | rom_ena=0; 939 | ram_write=0; 940 | ram_read=0; 941 | rom_read=0; 942 | ad_sel=0; 943 | fetch=2'b00; 944 | end 945 | S3: begin 946 | write_r=0; 947 | read_r=0; 948 | PC_en=0; 949 | ac_ena=1; 950 | ram_ena=0; 951 | rom_ena=1; 952 | ram_write=0; 953 | ram_read=0; 954 | rom_read=1; 955 | ad_sel=0; 956 | fetch=2'b10; 957 | end 958 | S4: begin 959 | write_r=0; 960 | read_r=0; 961 | PC_en=1; 962 | ac_ena=1; 963 | ram_ena=0; 964 | ram_write=0; 965 | ram_read=0; 966 | rom_ena=1; 967 | rom_read=1; 968 | ad_sel=0; 969 | fetch=2'b10; 970 | end 971 | S5: begin 972 | if (ins==LDO) 973 | begin 974 | write_r=1; 975 | read_r=0; 976 | PC_en=0; 977 | ac_ena=1; 978 | ram_ena=0; 979 | ram_write=0; 980 | ram_read=0; 981 | rom_ena=1; 982 | rom_read=1; 983 | ad_sel=1; 984 | fetch=2'b01; 985 | end 986 | else 987 | begin 988 | write_r=1; 989 | read_r=0; 990 | PC_en=0; 991 | ac_ena=1; 992 | ram_ena=1; 993 | ram_write=0; 994 | ram_read=1; 995 | rom_ena=0; 996 | rom_read=0; 997 | ad_sel=1; 998 | fetch=2'b01; 999 | end 1000 | end 1001 | S6: begin 1002 | 1003 | write_r=1'b0; 1004 | read_r=1'b0; 1005 | PC_en=1'b0; //** not so sure, log: change 1 to 0 1006 | ac_ena=1'b0; 1007 | ram_ena=1'b0; 1008 | rom_ena=1'b0; 1009 | ram_write=1'b0; 1010 | ram_read=1'b0; 1011 | rom_read=1'b0; 1012 | ad_sel=1'b0; 1013 | fetch=2'b00; 1014 | end 1015 | 1016 | S7: begin // STO, reg->ram. step1. read REG 1017 | write_r=0; 1018 | read_r=1; 1019 | PC_en=0; 1020 | ac_ena=0; 1021 | ram_ena=0; 1022 | rom_ena=0; 1023 | ram_write=0; 1024 | ram_read=0; 1025 | rom_read=0; 1026 | ad_sel=0; 1027 | fetch=2'b00; 1028 | end 1029 | S8: begin // STO, step2, write RAM 1030 | write_r=0; 1031 | read_r=1; 1032 | PC_en=0; 1033 | ac_ena=0; 1034 | rom_read=0; 1035 | rom_ena=0; 1036 | 1037 | ram_ena=1; 1038 | ram_write=1; 1039 | ram_read=0; 1040 | 1041 | ad_sel=1; 1042 | fetch=2'b00; //fetch=2'b10, ram_ena=1, ram_write=1, ad_sel=1; 1043 | end 1044 | S9: begin 1045 | if (ins==PRE) // REG->ACCUM 1046 | begin 1047 | write_r=0; 1048 | read_r=1; 1049 | PC_en=0; 1050 | ac_ena=1; 1051 | ram_ena=0; 1052 | rom_ena=0; 1053 | ram_write=0; 1054 | ram_read=0; 1055 | rom_read=0; 1056 | ad_sel=0; 1057 | fetch=2'b00; 1058 | end 1059 | else 1060 | begin 1061 | write_r=0; 1062 | read_r=1; 1063 | PC_en=0; 1064 | ac_ena=1; 1065 | ram_ena=0; 1066 | rom_ena=0; 1067 | ram_write=0; 1068 | ram_read=0; 1069 | rom_read=0; 1070 | ad_sel=0; 1071 | 1072 | fetch=2'b00; 1073 | end 1074 | end 1075 | S10: begin 1076 | write_r=0; 1077 | read_r=1; 1078 | PC_en=0; 1079 | ac_ena=0; 1080 | ram_ena=0; 1081 | rom_ena=0; 1082 | ram_write=0; 1083 | ram_read=0; 1084 | rom_read=0; 1085 | ad_sel=0; 1086 | fetch=2'b00; 1087 | end 1088 | S11: begin // LDM, step1, write reg 1089 | write_r=1; 1090 | read_r=0; 1091 | PC_en=0; 1092 | ac_ena=1; 1093 | ram_ena=0; 1094 | 1095 | ram_write=0; 1096 | ram_read=0; 1097 | rom_ena=1; 1098 | rom_read=1; 1099 | ad_sel=0; 1100 | fetch=2'b00; 1101 | 1102 | end 1103 | S12: begin 1104 | write_r=0; 1105 | read_r=0; 1106 | PC_en=0; 1107 | ac_ena=0; 1108 | ram_ena=0; 1109 | rom_ena=0; 1110 | ram_write=0; 1111 | ram_read=0; 1112 | rom_read=0; 1113 | ad_sel=0; 1114 | fetch=2'b00; 1115 | end 1116 | default: begin 1117 | write_r=0; 1118 | read_r=0; 1119 | PC_en=0; 1120 | ac_ena=0; 1121 | ram_ena=0; 1122 | rom_ena=0; 1123 | ram_write=0; 1124 | ram_read=0; 1125 | rom_read=0; 1126 | ad_sel=0; 1127 | fetch=2'b00; 1128 | end 1129 | endcase 1130 | end 1131 | endmodule 1132 | 1133 | .. |image0| image:: assets/von.png 1134 | .. |image1| image:: assets/CPU-comp-right.png 1135 | .. |image2| image:: assets/rom.png 1136 | .. |image3| image:: assets/ram.png 1137 | .. |image4| image:: assets/pc.png 1138 | .. |image5| image:: assets/accum.png 1139 | .. |image6| image:: assets/mux.png 1140 | .. |image7| image:: assets/alu.png 1141 | .. |image8| image:: assets/reg.png 1142 | .. |image9| image:: assets/ir.png 1143 | .. |image10| image:: assets/schematic.png 1144 | .. |image11| image:: assets/RTL_Viewer_s.png 1145 | .. |image12| image:: assets/short-ins-caption.png 1146 | .. |image13| image:: assets/short-long-caption.png 1147 | .. |image14| image:: assets/fsm.png 1148 | .. |image15| image:: assets/s0.png 1149 | .. |image16| image:: assets/s1.png 1150 | .. |image17| image:: assets/wave.png 1151 | .. |image18| image:: assets/mv3.png 1152 | .. |image19| image:: assets/reg1.png 1153 | 1154 | -------------------------------------------------------------------------------- /reg_32.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | module reg_32(in, data, write, read, addr, clk); 4 | input write, read, clk; 5 | input [7:0] in; 6 | input [7:0] addr; //!Warning: addr should be reduced to 5 bits width, not 8 bits width. 7 | //input [4:0] addr; 8 | 9 | output [7:0] data; 10 | 11 | reg [7:0] R[31:0]; //32Byte 12 | wire [4:0] r_addr; 13 | 14 | assign r_addr = addr[4:0]; 15 | assign data = (read)? R[r_addr]:8'hzz; //read enable 16 | 17 | always @(posedge clk) begin //write, clk posedge 18 | if(write) R[r_addr] <= in; 19 | end 20 | 21 | endmodule 22 | -------------------------------------------------------------------------------- /rom.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | 4 | module rom(data, addr, read, ena); 5 | input read, ena; 6 | input [7:0] addr; 7 | output [7:0] data; 8 | 9 | reg [7:0] memory[255:0]; 10 | 11 | 12 | // note: Decimal number in the bracket 13 | initial begin 14 | memory[0] = 8'b000_00000; //NOP 15 | 16 | // [ins] [target_reg_addr] [from_rom_addr] 17 | memory[1] = 8'b001_00001; //LDO s1 18 | memory[2] = 8'b010_00001; //rom(65) //rom[65] -> reg[1] 19 | memory[3] = 8'b001_00010; //LDO s2 20 | memory[4] = 8'b010_00010; //rom(66) 21 | memory[5] = 8'b001_00011; //LDO s3 22 | memory[6] = 8'b010_00011; //rom(67) 23 | 24 | memory[7] = 8'b100_00001; //PRE s1 25 | memory[8] = 8'b101_00010; //ADD s2 26 | memory[9] = 8'b110_00001; //LDM s1 27 | 28 | memory[10] = 8'b011_00001; //STO s1 29 | memory[11] = 8'b000_00001; //ram(1) 30 | memory[12] = 8'b010_00010; //LDA s2 31 | memory[13] = 8'b000_00001; //ram(1) 32 | 33 | memory[14] = 8'b100_00011; //PRE s3 34 | memory[15] = 8'b101_00010; //ADD s2 35 | memory[16] = 8'b110_00011; //LDM s3 36 | 37 | memory[17] = 8'b011_00011; //STO s3 38 | memory[18] = 8'b000_00010; //ram(2) 39 | memory[19] = 8'b111_00000; //HLT 40 | 41 | memory[65] = 8'b001_00101; //37 42 | memory[66] = 8'b010_11001; //89 43 | memory[67] = 8'b001_10101; //53 44 | end 45 | 46 | 47 | assign data = (read&&ena)? memory[addr]:8'hzz; 48 | 49 | endmodule 50 | --------------------------------------------------------------------------------