Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- module yfcpu(clk, rst, PC, ra_w, rb_w, rd_w, current_state_w, opcode_w);
- // our cpu core parameters
- parameter im_size = 8; // 2^n instruction word memory
- parameter rf_size = 4; // 2^n word register file
- input clk; // our system clock
- output PC; // our program counter
- input rst; // reset signal
- output reg [2:0] current_state_w;
- output reg [ rf_size-1 : 0 ] ra_w; // left operand register address
- output reg [ rf_size-1 : 0 ] rb_w; // right operand register address
- output reg [ rf_size-1 : 0 ] rd_w; // destination register
- output reg [ opcode_size-1 : 0 ] opcode_w;
- // the cycle states of our cpu, i.e. the Control Unit states
- parameter s_fetch = 3'b000; // fetch next instruction from memory
- parameter s_decode = 3'b001; // decode instruction into opcode and operands
- parameter s_execute = 3'b010; // execute the instruction inside the ALU
- parameter s_store = 3'b011; // store the result back to memory
- parameter s_nostore = 3'b100; // dont store any result, skips a cycle
- // the parts of our instruction word
- parameter opcode_size = 4; // size of opcode in bits
- // Mnemonic Op Codes
- parameter LRI = 4'b0001;
- parameter ADD = 4'b0100;
- parameter SUB = 4'b0101;
- parameter OR = 4'b0110;
- parameter XOR = 4'b0111;
- parameter HALT = 4'b0000;
- // our new branch mnemonics!
- parameter BRA = 4'b1000; // branch to address in memory location RB
- parameter BRANZ = 4'b1001; // branch to address in memory location RB, if RA is zero
- parameter BRAL = 4'b1010; // branch to literal address RB
- parameter BRALNZ = 4'b1011; // branch to literal address RB, if RA is zero
- parameter CALL = 4'b1100; // call subroutine; store current PC into RD and jump to address in literal location RB
- // our memory core consisting of Instruction Memory, Register File and an ALU working (W) register
- reg [ opcode_size + (rf_size*3) -1 : 0 ] IMEM[0: 2 ** im_size -1 ] ; // instruction memory
- reg [ 7:0 ] REGFILE[0: 2 ** rf_size -1 ]; // data memory
- reg [ 7:0 ] W; // working (intermediate) register
- // our cpu core registers
- reg [ im_size-1 : 0 ] PC; // program counter
- reg [ opcode_size + (rf_size*3) -1 : 0 ] IR; // instruction register
- /* Control Unit registers
- The control unit sequencer cycles through fetching the next instruction
- from memory, decoding the instruction into the opcode and operands and
- executing the opcode in the ALU.
- */
- reg [ 2:0 ] current_state;
- reg [ 2:0 ] next_state;
- // our instruction registers
- // an opcode typically loads registers addressed from RA and RB, and stores
- // the result into destination register RD. RA:RB can also be used to form
- // an 8bit immediate (literal) value.
- reg [ opcode_size-1 : 0 ] OPCODE;
- reg [ rf_size-1 : 0 ] RA; // left operand register address
- reg [ rf_size-1 : 0 ] RB; // right operand register address
- reg [ rf_size-1 : 0 ] RD; // destination register
- always @ (*) begin
- ra_w <= RA;
- rb_w <= RB;
- rd_w <= RD;
- opcode_w <= OPCODE;
- current_state_w <= current_state;
- end
- // the initial cpu state bootstrap
- initial begin
- PC = 0;
- current_state = s_fetch;
- // Our sample computes 11 + 10*3...the long way, via 10 additions of 3!
- // IMEM[n] = { OPCODE, RA, RB, RD };
- IMEM[0] = { LRI , 8'd10, 4'd0 }; // load 10 into R0, our loop counter
- IMEM[1] = { LRI , 8'd1 , 4'd1 }; // load 1 into R1, our loop decrement value
- IMEM[2] = { LRI , 8'd11, 4'd2 }; // load 11 into R2
- IMEM[3] = { LRI , 8'd3 , 4'd3 }; // load 3 into R3
- IMEM[4] = { ADD , 4'd2 , 4'd3 , 4'd2 }; // add R2 + R3, into R2
- IMEM[5] = { SUB , 4'd0 , 4'd1 , 4'd0 }; // decrement the loop counter R0
- IMEM[6] = { BRALNZ , 4'd0 , 4'd4 , 4'd0 }; // jump to address 4, if R0 is zero
- IMEM[7] = { CALL , 4'd0 , 4'd11, 4'd15 }; // call subroutine, store PC into R15
- IMEM[8] = { LRI , 8'd4, 4'd12 }; // load 10 into R0, our loop counter
- IMEM[9] = { ADD , 4'd12 , 4'd2 , 4'd2 }; // add R2 + R3, into R2
- IMEM[10] = { HALT , 12'd0 }; // end program
- // subroutine that subtracts 11 from R2
- IMEM[11] = { LRI , 8'd11, 4'd3 }; // load 10 into R0, our loop counter
- IMEM[12] = { SUB , 4'd2 , 4'd3 , 4'd2 }; // decrement the loop counter R0
- IMEM[13] = { BRA , 4'd0 , 4'd15, 4'd0 }; // return, branch to location from R15
- end
- // at each clock cycle we sequence the Control Unit, or if rst is
- // asserted we keep the cpu in reset.
- always @ (posedge clk or posedge rst)
- begin
- if(rst) begin
- current_state = s_fetch;
- PC = 0;
- end
- else
- begin
- // sequence our Control Unit
- case( current_state )
- s_fetch: begin
- // fetch instruction from instruction memory
- IR = IMEM[ PC ];
- next_state = s_decode;
- end
- s_decode: begin
- // PC can be incremented as current instruction is loaded into IR
- PC = PC + 1;
- next_state = s_execute;
- // decode the opcode and register operands
- OPCODE = IR[ opcode_size + (rf_size*3) -1 : (rf_size*3) ];
- RA = IR[ (rf_size*3) -1 : (rf_size*2) ];
- RB = IR[ (rf_size*2) -1 : (rf_size ) ];
- RD = IR[ (rf_size ) -1 : 0 ];
- end
- s_execute: begin
- // Execute ALU instruction, process the OPCODE
- case (OPCODE)
- LRI: begin
- // load register RD with immediate from RA:RB operands
- W = {RA, RB};
- next_state = s_store;
- end
- ADD: begin
- // Add RA + RB
- W = REGFILE[RA] + REGFILE[RB];
- next_state = s_store;
- end
- SUB: begin
- // Sub RA - RB
- W = REGFILE[RA] - REGFILE[RB];
- next_state = s_store;
- end
- OR: begin
- // OR RA + RB
- W = REGFILE[RA] | REGFILE[RB];
- next_state = s_store;
- end
- XOR: begin
- // Exclusive OR RA ^ RB
- W = REGFILE[RA] ^ REGFILE[RB];
- next_state = s_store;
- end
- HALT: begin
- // Halt execution, loop indefinately
- next_state = s_execute;
- end
- BRA: begin
- // branch to REGFILE[RB]
- PC = REGFILE[RB];
- next_state = s_nostore;
- end
- BRAL: begin
- // branch to RB
- PC = RB;
- next_state = s_nostore;
- end
- BRANZ: begin
- // branch to REGFILE[RB] if REGFILE[RA] is zero
- if(REGFILE[RA] !=8'd0)
- PC = REGFILE[RB];
- next_state = s_nostore;
- end
- BRALNZ: begin
- // branch to RB if REGFILE[RA] is zero
- if(REGFILE[RA] !=8'd0)
- PC = RB;
- next_state = s_nostore;
- end
- CALL: begin
- // call a subroutine; store PC into RD and jump to location in REGFILE[RB]
- W = PC;
- PC = RB;
- next_state = s_store; // note state s_store! because we store PC into REGFILE[RD]
- end
- // catch all
- default: begin end
- endcase
- end
- s_store: begin
- // store the ALU working register into the destination register RD
- REGFILE[RD] = W;
- next_state = s_fetch;
- end
- s_nostore: begin
- // not a store instruction, skip this cycle
- // this is typically referred to as a "wait state".
- next_state = s_fetch;
- end
- // invalid state!
- default: begin end
- endcase
- // move the control unit to the next state
- current_state = next_state;
- end
- end
- endmodule
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement