Yogi rides the new 6 wheeled robotic base platform. Designed in Solidworks and milled on my CNC machine.

Tuesday November 20 , 2018
Font Size
   

Your First CPU - Chapter 1 - Basic CPU - YFCPU Source Code

Electronics

Article Index
Your First CPU - Chapter 1 - Basic CPU
Principles of CPU Design
YFCPU Source Code
All Pages

Verilog source:

Chapter 1 - Basic CPU Logic (tgz)

Chapter 1 - Basic CPU Logic (windows zip)

 

yfcpu.v

  1:  module yfcpu(clk, rst, PC);
2:
3: // our cpu core parameters
4: parameter im_size = 8; // 2^n instruction word memory
5: parameter rf_size = 4; // 2^n word register file
6:
7: input clk; // our system clock
8: output PC; // our program counter
9: input rst; // reset signal
10:
11: // the cycle states of our cpu, i.e. the Control Unit states
12: parameter s_fetch = 2'b00; // fetch next instruction from memory
13: parameter s_decode = 2'b01; // decode instruction into opcode and operands
14: parameter s_execute = 2'b10; // execute the instruction inside the ALU
15: parameter s_store = 2'b11; // store the result back to memory
16:
17: // the parts of our instruction word
18: parameter opcode_size = 4; // size of opcode in bits
19:
20: // our mnemonic op codes
21: parameter LRI = 4'b0001;
22: parameter ADD = 4'b0100;
23: parameter OR = 4'b0110;
24: parameter XOR = 4'b0111;
25: parameter HALT = 4'b0000;
26:
27: // our memory core consisting of Instruction Memory, Register File and an ALU working (W) register
28: reg [ opcode_size + (rf_size*3) -1 : 0 ] IMEM[0: 2 ** im_size -1 ] ; // instruction memory
29: reg [ 7:0 ] REGFILE[0: 2 ** rf_size -1 ]; // data memory
30: reg [ 7:0 ] W; // working (intermediate) register
31:
32: // our cpu core registers
33: reg [ im_size-1 : 0 ] PC; // program counter
34: reg [ opcode_size + (rf_size*3) -1 : 0 ] IR; // instruction register
35:
36: /* Control Unit registers
37: The control unit sequencer cycles through fetching the next instruction
38: from memory, decoding the instruction into the opcode and operands and
39: executing the opcode in the ALU.
40: */
41: reg [ 1:0 ] current_state;
42: reg [ 1:0 ] next_state;
43:
44: // our instruction registers
45: // an opcode typically loads registers addressed from RA and RB, and stores
46: // the result into destination register RD. RA:RB can also be used to form
47: // an 8bit immediate (literal) value.
48: reg [ opcode_size-1 : 0 ] OPCODE;
49: reg [ rf_size-1 : 0 ] RA; // left operand register address
50: reg [ rf_size-1 : 0 ] RB; // right operand register address
51: reg [ rf_size-1 : 0 ] RD; // destination register
52:
53:
54: // the initial cpu state bootstrap
55: initial begin
56: PC = 0;
57: current_state = s_fetch;
58:
59: // PROGRAM MEMORY : initialize our instruction memory with a test program
60: // IMEM[n] = { OPCODE, RA, RB, RD };
61: IMEM[0] = { LRI , 4'd00, 4'd00, 4'd00 }; // clear R1, R2, R3
62: IMEM[1] = { LRI , 4'd02, 4'd04, 4'd01 }; // load immediate into R1
63: IMEM[2] = { LRI , 4'd01, 4'd11, 4'd02 }; // load immediate into R2
64: IMEM[3] = { ADD, 4'd01, 4'd02, 4'd03 }; // add R1 + R2, into R3
65: IMEM[4] = { XOR, 4'd02, 4'd03, 4'd04 }; // or R2 & R3 into R4
66: IMEM[5] = { OR , 4'd02, 4'd01, 4'd00 }; // or R2 & R1 into R0
67: IMEM[6] = { HALT, 12'd0 }; // end program
68: end
69:
70: // at each clock cycle we sequence the Control Unit, or if rst is
71: // asserted we keep the cpu in reset.
72: always @ (clk, rst)
73: begin
74: if(rst) begin
75: current_state = s_fetch;
76: PC = 0;
77: end
78: else
79: begin
80: // sequence our Control Unit
81: case( current_state )
82: s_fetch: begin
83: // fetch instruction from instruction memory
84: IR = IMEM[ PC ];
85: next_state = s_decode;
86: end
87:
88: s_decode: begin
89: // PC can be incremented as current instruction is loaded into IR
90: PC = PC + 1;
91: next_state = s_execute;
92:
93: // decode the opcode and register operands
94: OPCODE = IR[ opcode_size + (rf_size*3) -1 : (rf_size*3) ];
95: RA = IR[ (rf_size*3) -1 : (rf_size*2) ];
96: RB = IR[ (rf_size*2) -1 : (rf_size ) ];
97: RD = IR[ (rf_size ) -1 : 0 ];
98: end
99:
100: s_execute: begin
101: // Execute ALU instruction, process the OPCODE
102: case (OPCODE)
103: LRI: begin
104: // load register RD with immediate from RA:RB operands
105: W = {RA, RB};
106: next_state = s_store;
107: end
108:
109: ADD: begin
110: // Add RA + RB
111: W = REGFILE[RA] + REGFILE[RB];
112: next_state = s_store;
113: end
114:
115: OR: begin
116: // OR RA + RB
117: W = REGFILE[RA] | REGFILE[RB];
118: next_state = s_store;
119: end
120:
121: XOR: begin
122: // Exclusive OR RA ^ RB
123: W = REGFILE[RA] ^ REGFILE[RB];
124: next_state = s_store;
125: end
126:
127: HALT: begin
128: // Halt execution, loop indefinately
129: next_state = s_execute;
130: end
131:
132: // catch all
133: default: begin end
134: endcase
135: end
136:
137: s_store: begin
138: // store the ALU working register into the destination register RD
139: REGFILE[RD] = W;
140: next_state = s_fetch;
141: end
142:
143: // invalid state!
144: default: begin end
145: endcase
146:
147: // move the control unit to the next state
148: current_state = next_state;
149: end
150: end
151:
152: endmodule

Testbench Module

The yfcpu module is a hardware description. We havent instantiated it into real hardware yet, and in fact, we could instantiate it many times and have a multi-cpu IC. If we were targeting an FPGA we would want to instantiate physical IO pins and attach these pins to the inputs and outputs of our cpu module appropriately. However, for our initial tutorials we will simply be simulating the design in ModelSim or similar program so we will create a testbench source file instead. A testbench is a regular verilog source file, it instantiates our cpu module and will also provide our test stimuli to sequence our cpu. When designing any hardware module it is always a good idea to develop a robust testbench that fully tests all of it's the features for the desired response. Verilog includes some language constructs intended for testbench use only and these testbench features cannot be instantiated inside an FPGA. (A compiler error will result if the target is not set to a simulator.)

testbench.v

  1:  
2: // ============================================================================
3: // TESTBENCH FOR CPU CORE
4: // ============================================================================
5:
6: module tb ();
7:
8: reg clk, rst;
9: wire [7:0] pc;
10:
11: yfcpu mycpu (
12: clk, rst, pc
13: );
14:
15: initial begin
16: clk = 1;
17: rst = 1;
18: #1 rst = 0;
19: #1300 rst = 0;
20: $stop;
21: end
22:
23: always clk = #1 ~clk;
24:
25: endmodule

 



User Rating: / 64
PoorBest 

RSS Feeds

Visitor Poll

What sort of peripherals do you desire in a robotics main board? (you may vote more than once.)

Who's Online

We have 55 guests online