Shri Ramdeobaba College of Engineering and

Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 18

DEPARTMENT OF ELECTRONICS ENGINEERING

SHRI RAMDEOBABA COLLEGE OF ENGINEERING AND MANAGEMENT,


(An Autonomous Institution permanently affiliated to Rashtrasant Tukadoji Maharaj Nagpur University,
Nagpur)

Computer Architecture and Organization Laboratory (ENP360)

Session: 2020-21(EVEN)

Project report on

“16 bit Single Cycle MIPS CPU Design and Implementation on FPGA ”

Submitted by: Juhi Panname

Class and Roll No.: VI-C-17


Objective: Design a 16 bit Single Cycle MIPS CPU with following Instruction encoding and ISA
support.

Below is the description for instructions being supported by SCCPU:

1) Add : R[rd] = R[rs] + R[rt]


2) Subtract : R[rd] = R[rs] - R[rt]
3) And: R[rd] = R[rs] & R[rt]
4) Or : R[rd] = R[rs] | R[rt]
5) SLT: R[rd] = 1 if R[rs] < R[rt] else 0
6) Jr: PC=R[rs]
7) Lw: R[rt] = M[R[rs]+SignExtImm]
8) Sw : M[R[rs]+SignExtImm] = R[rt]
9) Beq : if(R[rs]==R[rt]) PC=PC+1+BranchAddr
10)Addi: R[rt] = R[rs] + SignExtImm
11)J : PC=JumpAddr
12)Jal : R[7]=PC+2;PC=JumpAddr
13)SLTI: R[rt] = 1 if R[rs] < imm else 0 Synthesis
tool : Xilinx Vivado 2016.2

Verilog code for the MIPS processor. The Verilog code for the whole design of the
MIPS processor as follows:

Verilog code for data memory:

module data_memory
(
input clk,
// address input, shared by read and write port
input [15:0] mem_access_addr,
// write port
input [15:0] mem_write_data, input
mem_write_en,
input mem_read,
// read port
output [15:0] mem_read_data
);
integer i;
reg [15:0] ram [255:0]; wire [7 : 0] ram_addr =
mem_access_addr[8 : 1]; initial begin
for(i=0;i<256;i=i+1) ram[i] <= 16'd0; end
always @(posedge clk) begin if (mem_write_en)
ram[ram_addr] <= mem_write_data;
end
assign mem_read_data = (mem_read==1'b1) ? ram[ram_addr]: 16'd0;
endmodule

Verilog code for instruction memory:


// Verilog code for instruction memory module instr_mem //
a synthesisable rom implementation
(
input [15:0] pc,
output wire [15:0] instruction
);
wire [3 : 0] rom_addr = pc[4 :
1]; /* lw $3, 0($0) -- Loop: slti
$1, $3, 50 beq $1, $0, Skip add
$4, $4, $3 addi $3, $3, 1 beq
$0,
$0, Loop-- Skip
*/
reg [15:0] rom[15:0];
initial
begin rom[0] = 16'b1000000110000000; rom[1]
= 16'b0010110010110010; rom[2] =
16'b1101110001100111; rom[3] =
16'b1101110111011001; rom[4] =
16'b1111110110110001; rom[5] =
16'b1100000001111011; rom[6] =
16'b0000000000000000; rom[7] =
16'b0000000000000000; rom[8] =
16'b0000000000000000; rom[9] =
16'b0000000000000000; rom[10] =
16'b0000000000000000; rom[11]
= 16'b0000000000000000;
rom[12] =
16'b0000000000000000; rom[13]
= 16'b0000000000000000;
rom[14] =
16'b0000000000000000; rom[15]
= 16'b0000000000000000; end
assign instruction = (pc[15:0] < 32 )? rom[rom_addr[3:0]]: 16'd0;
endmodule

Verilog code for register file:


// Verilog code for register file module
register_file
(
input clk,
input rst,
// write port
input reg_write_en,
input [2:0] reg_write_dest, input
[15:0] reg_write_data,
//read port 1
input [2:0] reg_read_addr_1, output
[15:0] reg_read_data_1,
//read port 2
input [2:0] reg_read_addr_2, output
[15:0] reg_read_data_2
);
reg [15:0] reg_array [7:0];
// write port //reg
[2:0] i;
always @ (posedge clk or posedge rst)
begin if(rst) begin reg_array[0] <= 16'b0;
reg_array[1] <= 16'b0; reg_array[2] <=
16'b0; reg_array[3] <= 16'b0; reg_array[4]
<= 16'b0; reg_array[5] <= 16'b0;
reg_array[6] <= 16'b0; reg_array[7] <=
16'b0;
end else begin if(reg_write_en) begin
reg_array[reg_write_dest] <= reg_write_data; end
end end assign reg_read_data_1 =
( reg_read_addr_1

== 0)? 16'b0 :
reg_array[reg_read_addr_1]; assign reg_read_data_2 = == 0)? 16'b0 :
( reg_read_addr_2
reg_array[reg_read_addr_2];
endmodule

Control Unit in Verilog:

// Submodule: Control Unit in Verilog module control( input[2:0] reg


opcode, input reset, output reg[1:0]
reg_dst,mem_to_reg,alu_op,
jump,branch,mem_read,mem_write,alu_src,reg_write,sign_or_zero
); output
always @(*) begin if(reset == 1'b1)
begin reg_dst = 2'b00;
mem_to_reg = 2'b00; alu_op =
2'b00; jump = 1'b0; branch =
1'b0; mem_read = 1'b0;
mem_write = 1'b0; alu_src =
1'b0; reg_write = 1'b0;
sign_or_zero = 1'b1; end
else begin
case(opcode)
3'b000: begin // add reg_dst
= 2'b01; mem_to_reg
= 2'b00; alu_op =
2'b00; jump = 1'b0;
branch =
1'b0; mem_read =
1'b0; mem_write = 1'b0;
alu_src = 1'b0;
reg_write = 1'b1;
sign_or_zero = 1'b1;
end
3'b001: begin // sli reg_dst
= 2'b00; mem_to_reg
= 2'b00; alu_op = 2'b10;
jump = 1'b0; branch =
1'b0; mem_read = 1'b0;
mem_write = 1'b0;
alu_src = 1'b1;
reg_write = 1'b1;
sign_or_zero = 1'b0;
end

3'b010: begin // j reg_dst =


2'b00; mem_to_reg = 2'b00; alu_op = 2'b00; jump = 1'b1; branch =
1'b0; mem_read = 1'b0; mem_write = 1'b0; alu_src = 1'b0; reg_write
= 1'b0; sign_or_zero =
1'b1; end 3'b011: begin // jal reg_dst =
2'b10; mem_to_reg = 2'b10; alu_op = 2'b00; jump = 1'b1; branch = 1'b0; mem_read =
1'b0; mem_write = 1'b0; alu_src = 1'b0; reg_write
= 1'b1; sign_or_zero =
1'b1; end
3'b100: begin // lw reg_dst =
2'b00; mem_to_reg = 2'b01; alu_op = 2'b11; jump = 1'b0; branch = 1'b0; mem_read =
1'b1; mem_write = 1'b0; alu_src = 1'b1; reg_write
= 1'b1; sign_or_zero =
1'b1; end
3'b101: begin // sw reg_dst =
2'b00; mem_to_reg = 2'b00; alu_op = 2'b11; jump = 1'b0; branch = 1'b0; mem_read =
1'b0; mem_write = 1'b1; alu_src = 1'b1; reg_write
= 1'b0; sign_or_zero =
1'b1; end
3'b110: begin // beq reg_dst = 2'b00;
mem_to_reg =
2'b00; alu_op = 2'b01;
jump = 1'b0; branch =
1'b1; mem_read =
1'b0; mem_write =
1'b0; alu_src = 1'b0;
reg_write = 1'b0;
sign_or_zero = 1'b1;
end
3'b111: begin // addi reg_dst
= 2'b00; mem_to_reg
=
2'b00; alu_op = 2'b11;
jump = 1'b0; branch =
1'b0; mem_read =
1'b0; mem_write =
1'b0; alu_src = 1'b1;
reg_write = 1'b1;
sign_or_zero = 1'b1;
end default: begin
reg_dst = 2'b01;
mem_to_reg = 2'b00;
alu_op = 2'b00; jump =
1'b0; branch = 1'b0;
mem_read = 1'b0;
mem_write = 1'b0; alu_src
= 1'b0; reg_write = 1'b1;
sign_or_zero = 1'b1; end
endcase end
end endmodule

Verilog code for ALU:


// Verilog code for ALU module alu( input [15:0] a,
//src1 input [15:0] b,
//src2
input [2:0] alu_control, //function sel
output reg [15:0] result, //result output zero
);
always @(*) begin
case(alu_control)
3'b000: result = a + b; // add 3'b001:
result = a - b; // sub 3'b010: result =
a & b; // and
3'b011: result = a | b; // or
3'b100: begin if (a<b) result = 16'd1; else result =
16'd0; end
default:result = a + b; // add
endcase
end
assign zero = (result==16'd0) ? 1'b1: 1'b0; endmodule

ALU Control Unit in Verilog


// Submodule: ALU Control Unit in Verilog module ALUControl(
ALU_Control, ALUOp, Function); output reg[2:0]
ALU_Control; input [1:0] ALUOp; input [3:0] Function; wire
[5:0] ALUControlIn;
assign ALUControlIn = {ALUOp,Function}; always
@(ALUControlIn) casex (ALUControlIn)
6'b11xxxx: ALU_Control=3'b000;
6'b10xxxx: ALU_Control=3'b100;
6'b01xxxx: ALU_Control=3'b001;
6'b000000: ALU_Control=3'b000;
6'b000001: ALU_Control=3'b001; 6'b000010:
ALU_Control=3'b010;
6'b000011: ALU_Control=3'b011;
6'b000100: ALU_Control=3'b100; default:
ALU_Control=3'b000; endcase
endmodule
// Verilog code for JR control unit module
JR_Control( input[1:0] alu_op, input [3:0]
funct, output JRControl
);
assign JRControl = ({alu_op,funct}==6'b001000) ? 1'b1 : 1'b0; endmodule

Verilog code for 16 bit single cycle MIPS CPU:

// Verilog code for 16 bit single cycle MIPS CPU module mips_16( input
clk,reset,
output[15:0] pc_out, alu_result
//,reg3,reg4
);
reg[15:0] pc_current; wire
signed[15:0] pc_next,pc2;
wire [15:0] instr;
wire[1:0] reg_dst,mem_to_reg,alu_op; wire
jump,branch,mem_read,mem_write,alu_src,reg_write ; wire [2:0]
reg_write_dest; wire [15:0] reg_write_data; wire [2:0]
reg_read_addr_1; wire [15:0] reg_read_data_1; wire [2:0]
reg_read_addr_2; wire [15:0] reg_read_data_2;
wire [15:0] sign_ext_im,read_data2,zero_ext_im,imm_ext; wire JRControl;
wire [2:0] ALU_Control; wire [15:0] ALU_out; wire zero_flag; wire
signed[15:0] im_shift_1, PC_j, PC_beq, PC_4beq,PC_4beqj,PC_jr; wire
beq_control; wire [14:0] jump_shift_1; wire [15:0]mem_read_data; wire [15:0]
no_sign_ext; wire sign_or_zero;
// PC
always @(posedge clk or posedge reset) begin
if(reset) pc_current <=
16'd0; else pc_current
<= pc_next;
end // PC +
2
assign pc2 = pc_current + 16'd2; //
instruction memory instr_mem
instrucion_memory(.pc(pc_current),.instruction(instr)); // jump shift left
1

assign jump_shift_1 = {instr[13:0],1'b0};


// control unit
control
control_unit(.reset(reset),.opcode(instr[15:13]),.reg_dst(reg_dst)
,.mem_to_reg(mem_to_reg),.alu_op(alu_op),.jump(jump),.branch(branch),.
mem_read(mem_read),

.mem_write(mem_write),.alu_src(alu_src),.reg_write(reg_write),.sign_or_zer
o(sign_or_zero));
// multiplexer regdest assign reg_write_dest = (reg_dst==2'b10) ? 3'b111: ((reg_dst==2'b01)
? instr[6:4]
:instr[9:7]);
// register file assign reg_read_addr_1 = instr[12:10]; assign reg_read_addr_2 = instr[9:7];
register_file reg_file(.clk(clk),.rst(reset),.reg_write_en(reg_write),
.reg_write_dest(reg_write_dest),
.reg_write_data(reg_write_data),
.reg_read_addr_1(reg_read_addr_1),
.reg_read_data_1(reg_read_data_1),
.reg_read_addr_2(reg_read_addr_2),
.reg_read_data_2(reg_read_data_2));
//.reg3(reg3),
//.reg4(reg4)); // sign extend
assign sign_ext_im = {{9{instr[6]}},instr[6:0]}; assign zero_ext_im =
{{9{1'b0}},instr[6:0]}; assign imm_ext = (sign_or_zero==1'b1) ? sign_ext_im :
zero_ext_im; // JR control
JR_Control
JRControl_unit(.alu_op(alu_op),.funct(instr[3:0]),.JRControl(JRControl)); // ALU control
unit
ALUContro
l ALU_Control_unit(.ALUOp(alu_op),.Function(instr[3:0]),.ALU_Control(ALU_
Control));
// multiplexer alu_src
assign read_data2 = (alu_src==1'b1) ? imm_ext : reg_read_data_2; // ALU
alu
alu_unit(.a(reg_read_data_1),.b(read_data2),.alu_control(ALU_Control),.res
ult(ALU_out),.zero(zero_flag)); // immediate shift 1
assign im_shift_1 = {imm_ext[14:0],1'b0};
//
assign no_sign_ext = ~(im_shift_1) + 1'b1;
// PC beq add assign PC_beq = (im_shift_1[15] == 1'b1) ? (pc2 - no_sign_ext):
(pc2 +im_shift_1); // beq control assign
beq_control = branch & zero_flag;
// PC_beq
assign PC_4beq = (beq_control==1'b1) ? PC_beq : pc2;
// PC_j
assign PC_j = {pc2[15],jump_shift_1};
// PC_4beqj
assign PC_4beqj = (jump == 1'b1) ? PC_j : PC_4beq;
// PC_jr
assign PC_jr = reg_read_data_1;
// PC_next
assign pc_next = (JRControl==1'b1) ? PC_jr : PC_4beqj;
// data memory
data_memory datamem(.clk(clk),.mem_access_addr(ALU_out),

.
mem_write_data(reg_read_data_2),.mem_write_en(mem_write),.mem_read( mem_r
ead),
.mem_read_data(mem_read_data));
// write back assign reg_write_data = (mem_to_reg == 2'b10) ? pc2:((mem_to_reg
== 2'b01)? mem_read_data: ALU_out);
// output
assign pc_out = pc_current; assign alu_result
= ALU_out; endmodule

Testbench
`timescale 1ns / 1ps

module tb_mips16; // Inputs reg clk; reg reset; //


Outputs wire [15:0] pc_out; wire [15:0]
alu_result;//,reg3,reg4; // Instantiate
the Unit Under Test (UUT) mips_16 uut (
.clk(clk),
.reset(reset),
.pc_out(pc_out),
.alu_result(alu_result)
//.reg3(reg3),
// .reg4(reg4)
);
initial begin clk =
0;
forever #10 clk = ~clk;
end
initial begin
// Initialize Inputs
//$monitor ("register 3=%d, register 4=%d", reg3,reg4); reset = 1;
// Wait 100 ns for global reset to finish
#100; reset =
0;
// Add stimulus here end
endmodule
SC-CPU along with Data-path and control. The ISA support is given in above table

Output
Important term

1] ISA (instruction set architecture)


ISA decides how to represent an instruction of a processor in Instruction memory, how the
instruction is oriented, what is the length of an instruction, in which way the instruction should be
decoded so that the CPU gets appropriate data.

2] Arithmetic & Logic Unit (ALU):

It is a very important hardware component of central processing unit of a computer. ALU is the
main hardware part where the operations get executed.

3] Register File:

In processor, ALU gets data from a Register Bank / Register File. As we have designed our
ISA, our register file should have 16 registers. And the design should be easy enough to choose
rs, rt, rd values.

4] Control Unit

Control unit is the circuit in processor which controls the flow of data and operation of ALU.
Initially an instruction is loaded in instruction memory. According to Opcode of that instruction,
control unit gets understood what the instruction wants to execute. Then it flows the data in
such a path so that ALU gets necessary data to execute.

5] Single cycle processor

Single cycle processor is a processor that carries out 1 instruction in a single clock cycle.

6] FPGA

Field Programmable Gate Arrays (FPGAs) are semiconductor devices that are

based around a matrix of configurable logic blocks (CLBs) connected via

programmable interconnects. FPGAs can be reprogrammed to desired application or

functionality requirements after manufacturing.


Program to calculate Fibonacci series

Fibonacci Series - Fibonacci series is a series of numbers, where the next number is

found by adding up the 2 number beore it.

The Fibonacci numbers are the numbers in the following integer sequence.

0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ……..

module fib(input clock, reset, input [5:0] n, output reg ready, output [15:0] value);
reg [15:0] previous, current; reg [5:0] counter;

// Reset the circuit


always @(posedge
reset) begin previous <=
16'd0; current <= 16'd1;
counter <= 16'd1; end

// Compute next Fibonacci


number always @(posedge
clock) begin
// Increment current index counter
<= counter + 1;

// Efficient adders are automatically


inferred current <= current + previous;
previous <= current;

if (counter == n) ready
<= 1;
end

// Read the value of the nth fibonacci number from the internal register assign
value = current;

endmodule

Output
Result

In this report, a 16-bit single-cycle MIPS processor is implemented in Verilog HDL.

You might also like