RISC-V_cpu/CPU.v

658 lines
19 KiB
Verilog

`default_nettype none
module processor( input clk, reset, //
output [31:0] PC, //
input [31:0] instruction, //
output WE, //
output [31:0] address_to_mem, //
output [31:0] data_to_mem, //
input [31:0] data_from_mem
);
wire [31:0] pc_adress;
assign PC = pc_adress;
wire [31:0] pc_adress_next;
assign WE = data_mem_write_enabled;
wire reg_we;
wire [4:0] reg_address_read1;
wire [4:0] reg_address_read2;
wire [4:0] reg_address_write;
wire [31:0] reg_data_in;
wire [31:0] reg_data_out1;
wire [31:0] reg_data_out2;
wire mem_to_reg;
wire alu_src_select; // select ? rd2 : imm
wire [3:0] alu_code;
wire [31:0] alu_src_a;
wire [31:0] alu_src_b;
wire [31:0] alu_result;
wire alu_zero_flag;
wire data_mem_write_enabled;
wire [31:0] data_mem_address;
wire [31:0] data_mem_read_data;
wire [31:0] data_mem_write_data;
assign WE = data_mem_write_enabled;
assign address_to_mem = data_mem_address;
assign data_to_mem = data_mem_write_data;
assign data_mem_read_data = data_from_mem;
wire [31:0] imm_decoded;
wire [2:0] imm_control;
wire [31:0] next_address_nojump;
wire [31:0] next_address_jump;
wire branch_beq;
wire branch_jal;
wire branch_jalr;
wire pc_jump;
wire auipc;
control_unit_module control_unit( instruction, branch_beq, branch_jal, branch_jalr, reg_we, mem_to_reg, data_mem_write_enabled, alu_src_select, auipc, imm_control, alu_code);
mux2_1 pc_mux(next_address_nojump, next_address_jump, pc_jump, pc_adress_next);
pc_adder_module pc_adder(pc_adress, next_address_nojump);
register pc(pc_adress_next, clk, reset, pc_adress);
assign pc_jump = (alu_zero_flag && branch_beq) || branch_jal || branch_jalr; // <---
wire [31:0]jump_adder_output;
adder_module32 jump_adder(imm_decoded, pc_adress, jump_adder_output);
mux2_1 jump_adder_jalr(jump_adder_output, alu_result, branch_jalr, next_address_jump);
// program_counter pc(clk, pc_adress);
// inst_mem instruction_memory(pc_adress[7:0], instruction);
// data_mem data_memory(clk, data_mem_write_enabled, data_mem_address, data_mem_write_data, data_mem_read_data);
assign reg_address_read1 = instruction[19:15];
assign reg_address_read2 = instruction[24:20];
assign reg_address_write = instruction[11:7];
assign data_mem_address = alu_result;
assign data_mem_write_data = reg_data_out2;
register_unit_32x32 registers(clk, reg_we, reg_data_in, reg_address_read1, reg_address_read2, reg_address_write, reg_data_out1, reg_data_out2);
immDecode decored(instruction[31:7], imm_control, imm_decoded);
mux2_1 auipc_mux(reg_data_out1, pc_adress, auipc, alu_src_a);
mux2_1 alu_srcrc_mux(reg_data_out2, imm_decoded, alu_src_select, alu_src_b);
aluModule alu(alu_code, alu_src_a, alu_src_b, alu_result, alu_zero_flag);
wire [31:0] mux_connection;
mux2_1 jump_alu_mux(alu_result, next_address_nojump, branch_jal || branch_jalr, mux_connection);
mux2_1 register_write_data_mux(mux_connection, data_mem_read_data, mem_to_reg, reg_data_in);
endmodule
module aluModule( input [3:0] code, input [31:0] srcA, srcB, output reg [31:0] result, output zeroFlag );
always @(*)
case (code)
'b 0100: begin // add
result <= srcA + srcB;
end
'b 1100: begin // sub
result <= srcA - srcB;
end
'b 0001: begin // div
result <= srcA / srcB;
end
'b 1001: begin // mod
result <= srcA % srcB;
end
'b 0010: begin // and
result <= srcA & srcB;
end
'b 0110: begin // or
result <= srcA | srcB;
end
'b 1010: begin // less
result <= $signed(srcA) < $signed(srcB);
end
'b 1011: begin // greater of equal
result <= srcA >= srcB;
end
'b 0111: begin // <<
result[31:0] <= (srcA[31:0] << srcB[4:0]);
end
'b 1110: begin // >>
result[31:0] <= (srcA[31:0] >> srcB[4:0]);
end
'b 0011: begin // >>>
result[31:0] <= ((srcA >>> srcB) | ('h FFFFFFFF << (32 - srcB[4:0])));
// result <= srcA >>> srcB;
end
'b 1111: begin // ignore src a
result <= srcB;
end
default: begin
result <= 0;
end
endcase
assign zeroFlag = result == 0;
endmodule
module immDecode( input [31:7] in, input [2:0] imm_control, output reg [31:0] out );
// control
// lw & addi & jalr -> 000
// sw -> 001
// beq -> 010
// jal -> 011
// lui -> 100
always @(*) begin
if (imm_control[2:0] == 'b 000) begin
out[31:12] <= {21{in[31]}};
out[11:0] <= in[31:20];
end else if (imm_control[2:0] == 'b 001) begin
out[31:12] <= {21{in[31]}};
out[11:5] <= in[31:25];
out[4:0] <= in[11:7];
end else if (imm_control[2:0] == 'b 010) begin
out[31:13] <= {19{in[31]}};
out[12] <= in[31];
out[11] <= in[7];
out[10:5] <= in[30:25];
out[4:1] <= in[11:8];
out[0] <= 0;
end else if (imm_control[2:0] == 'b 011) begin
out[31:21] <= {11{in[31]}};
out[20] <= in[31];
out[19:12] <= in[19:12];
out[11] <= in[20];
out[10:1] <= in[30:21];
out[0] <= 0;
end else if (imm_control[2:0] == 'b 100) begin
out[31:12] <= in[31:12];
out[11:0] <= 0;
end
end
endmodule
module register( input [31:0] in, input clk, reset, output reg [31:0] out );
initial begin
out[31:0] = 0;
end
always @(posedge clk) begin
if (reset)
out[31:0] = 0;
else
out = in;
end
endmodule
module mux2_1(input [31:0]d0, d1, input select, output [31:0]y );
assign y = select ? d1 : d0;
endmodule
module mux4_1(input [31:0]d0, d1, d2, d3, input [1:0]select, output [31:0]y );
assign y = select[0] ? (select[1] ? d3 : d1) : (select[1] ? d2 : d0);
endmodule
module register_unit_32x32(input clk, write_enabled, input [31:0] datain, input [4:0] address1, address2, address3, output [31:0] dataout1, dataout2 );
reg [31:0] registers[31:0];
always @(posedge clk) begin
if (write_enabled && address3 != 0)
registers[address3] <= datain;
end
integer dump_counter;
initial begin
dump_counter = 0;
registers[0] = 32'b0;
registers[1] = 32'b0;
registers[2] = 32'b0;
registers[3] = 32'b0;
registers[4] = 32'b0;
registers[5] = 32'b0;
registers[6] = 32'b0;
registers[7] = 32'b0;
registers[8] = 32'b0;
registers[9] = 32'b0;
registers[10] = 32'b0;
registers[11] = 32'b0;
registers[12] = 32'b0;
registers[13] = 32'b0;
registers[14] = 32'b0;
registers[15] = 32'b0;
registers[16] = 32'b0;
registers[17] = 32'b0;
registers[18] = 32'b0;
registers[19] = 32'b0;
registers[20] = 32'b0;
registers[21] = 32'b0;
registers[22] = 32'b0;
registers[23] = 32'b0;
registers[24] = 32'b0;
registers[25] = 32'b0;
registers[26] = 32'b0;
registers[27] = 32'b0;
registers[28] = 32'b0;
registers[29] = 32'b0;
registers[30] = 32'b0;
registers[31] = 32'b0;
end
// always #2 begin
// $writememh($sformatf("./regdump/reg_%0d.hex", dump_counter), registers, 0, 31);
// dump_counter = dump_counter + 1;
// end
assign dataout1 = registers[address1];
assign dataout2 = registers[address2];
endmodule
module program_counter(input clk, output reg [31:0] address );
initial begin
address[31:0] = 32'b0;
end
always @(posedge clk) begin
address[31:0] <= address[31:0] + 1;
end
endmodule
module control_unit_module( input [31:0] instruction,
output reg
branch_beq,
branch_jal,
branch_jalr,
reg_write,
mem_to_reg,
mem_write,
alu_src_select,
auipc,
output reg [2:0] imm_control,
output reg [3:0] alu_control
);
wire [6:0] optcode;
assign optcode[6:0] = instruction[6:0];
wire [2:0]funct3 = instruction[14:12];
wire [6:0]funct7 = instruction[31:25];
always @(*) begin
// lw
if (optcode == 'b0000011 && funct3 == 'b010) begin
alu_src_select <= 1;
alu_control <= 'b 0100;
mem_write <= 0;
mem_to_reg <= 1;
reg_write <= 1;
branch_beq <= 0;
branch_jal <= 0;
branch_jalr <= 0;
auipc <= 0;
imm_control <= 'b 000;
end
// sw
else if (optcode == 'b0100011 && funct3 == 'b010) begin
alu_src_select <= 1;
alu_control <= 'b 0100;
mem_write <= 1;
mem_to_reg <= 0;
reg_write <= 0;
branch_beq <= 0;
branch_jal <= 0;
branch_jalr <= 0;
auipc <= 0;
imm_control <= 'b 001;
end
// add
else if (optcode == 'b0110011 && funct3 == 'b000 && funct7 == 'b0000000) begin
alu_src_select <= 0;
alu_control <= 'b 0100;
mem_write <= 0;
mem_to_reg <= 0;
reg_write <= 1;
branch_beq <= 0;
branch_jal <= 0;
branch_jalr <= 0;
auipc <= 0;
imm_control <= 'b 000;
end
// addi
else if (optcode == 'b0010011 && funct3 == 'b000) begin
alu_src_select <= 1;
alu_control <= 'b 0100;
mem_write <= 0;
mem_to_reg <= 0;
reg_write <= 1;
branch_beq <= 0;
branch_jal <= 0;
branch_jalr <= 0;
auipc <= 0;
imm_control <= 'b 000;
end
// sub
else if (optcode == 'b0110011 && funct3 == 'b000 && funct7 == 'b0100000) begin
alu_src_select <= 0;
alu_control <= 'b 1100;
mem_write <= 0;
mem_to_reg <= 0;
reg_write <= 1;
branch_beq <= 0;
branch_jal <= 0;
branch_jalr <= 0;
auipc <= 0;
imm_control <= 'b 000;
end
// slt
else if (optcode == 'b0110011 && funct3 == 'b010 && funct7 == 'b0000000) begin
alu_src_select <= 0;
alu_control <= 'b 1010;
mem_write <= 0;
mem_to_reg <= 0;
reg_write <= 1;
branch_beq <= 0;
branch_jal <= 0;
branch_jalr <= 0;
auipc <= 0;
imm_control <= 'b 000;
end
// or
else if (optcode == 'b0110011 && funct3 == 'b110 && funct7 == 'b0000000) begin
alu_src_select <= 0;
alu_control <= 'b 0110;
mem_write <= 0;
mem_to_reg <= 0;
reg_write <= 1;
branch_beq <= 0;
branch_jal <= 0;
branch_jalr <= 0;
auipc <= 0;
imm_control <= 'b 000;
end
// and
else if (optcode == 'b0110011 && funct3 == 'b111 && funct7 == 'b0000000) begin
alu_src_select <= 0;
alu_control <= 'b 0010;
mem_write <= 0;
mem_to_reg <= 0;
reg_write <= 1;
branch_beq <= 0;
branch_jal <= 0;
branch_jalr <= 0;
auipc <= 0;
imm_control <= 'b 000;
end
// beq
else if (optcode == 'b1100011 && funct3 == 'b000) begin
alu_src_select <= 0;
alu_control <= 'b 1100;
mem_write <= 0;
mem_to_reg <= 0;
reg_write <= 0;
branch_beq <= 1;
branch_jal <= 0;
branch_jalr <= 0;
auipc <= 0;
imm_control <= 'b 010;
end
// jal
else if (optcode == 'b1101111) begin
alu_src_select <= 0;
alu_control <= 'b 0000;
mem_write <= 0;
mem_to_reg <= 0;
reg_write <= 1;
branch_beq <= 0;
branch_jal <= 1;
branch_jalr <= 0;
auipc <= 0;
imm_control <= 'b 011;
end
// jalr
else if (optcode == 'b1100111 && funct3 == 'b000) begin
alu_src_select <= 1;
alu_control <= 'b 0100;
mem_write <= 0;
mem_to_reg <= 0;
reg_write <= 0;
branch_beq <= 0;
branch_jal <= 0;
branch_jalr <= 1;
auipc <= 0;
imm_control <= 'b 000;
end
// div
else if (optcode == 'b0110011 && funct3 == 'b100 && funct7 == 'b0000001) begin
alu_src_select <= 0;
alu_control <= 'b 0001;
mem_write <= 0;
mem_to_reg <= 0;
reg_write <= 1;
branch_beq <= 0;
branch_jal <= 0;
branch_jalr <= 0;
auipc <= 0;
imm_control <= 'b 000;
end
// rem
else if (optcode == 'b0110011 && funct3 == 'b110 && funct7 == 'b0000001) begin
alu_src_select <= 0;
alu_control <= 'b 1001;
mem_write <= 0;
mem_to_reg <= 0;
reg_write <= 1;
branch_beq <= 0;
branch_jal <= 0;
branch_jalr <= 0;
auipc <= 0;
imm_control <= 'b 000;
end
// blt
else if (optcode == 'b1100011 && funct3 == 'b100) begin
alu_src_select <= 0;
alu_control <= 'b 1011;
mem_write <= 0;
mem_to_reg <= 0;
reg_write <= 0;
branch_beq <= 1;
branch_jal <= 0;
branch_jalr <= 0;
auipc <= 0;
imm_control <= 'b 010;
end
// lui
else if (optcode == 'b0110111) begin
alu_src_select <= 1;
alu_control <= 'b 1111;
mem_write <= 0;
mem_to_reg <= 0;
reg_write <= 1;
branch_beq <= 0;
branch_jal <= 0;
branch_jalr <= 0;
auipc <= 0;
imm_control <= 'b 100;
end
// auipc
else if (optcode == 'b0010111) begin
alu_src_select <= 1;
alu_control <= 'b 0100;
mem_write <= 0;
mem_to_reg <= 0;
reg_write <= 1;
branch_beq <= 0;
branch_jal <= 0;
branch_jalr <= 0;
auipc <= 1;
imm_control <= 'b 100;
end
// sll
else if (optcode == 'b0110011 && funct3 == 'b001 && funct7 == 'b0000000) begin
alu_src_select <= 0;
alu_control <= 'b 0111;
mem_write <= 0;
mem_to_reg <= 0;
reg_write <= 1;
branch_beq <= 0;
branch_jal <= 0;
branch_jalr <= 0;
auipc <= 0;
imm_control <= 'b 000;
end
// srl
else if (optcode == 'b0110011 && funct3 == 'b101 && funct7 == 'b0000000) begin
alu_src_select <= 0;
alu_control <= 'b 1110;
mem_write <= 0;
mem_to_reg <= 0;
reg_write <= 1;
branch_beq <= 0;
branch_jal <= 0;
branch_jalr <= 0;
auipc <= 0;
imm_control <= 'b 000;
end
// sra
else if (optcode == 'b0110011 && funct3 == 'b101 && funct7 == 'b0100000) begin
alu_src_select <= 0;
alu_control <= 'b 0011;
mem_write <= 0;
mem_to_reg <= 0;
reg_write <= 1;
branch_beq <= 0;
branch_jal <= 0;
branch_jalr <= 0;
auipc <= 0;
imm_control <= 'b 000;
end else begin
alu_src_select <= 0;
alu_control <= 'b 0000;
mem_write <= 0;
mem_to_reg <= 0;
reg_write <= 0;
branch_beq <= 0;
branch_jal <= 0;
branch_jalr <= 0;
auipc <= 0;
imm_control <= 'b 000;
end
end
endmodule
module pc_adder_module(input [31:0]prev_address, output [31:0]next_address);
assign next_address = prev_address + 4;
endmodule
module adder_module32(input [31:0]in1, input [31:0]in2, output [31:0]out);
assign out[31:0] = in1[31:0] + in2[31:0];
endmodule
`default_nettype wire
//#############################################################
// TEST MODULES
module data_mem (input clk, we,
input [31:0] address, wd,
output [31:0] rd);
reg [31:0] RAM[63:0];
integer dump_counter;
initial begin
dump_counter = 0;
$readmemh ("memfile_data.hex",RAM,0,63);
end
// always #1 begin
// $writememh($sformatf("./memdump/mem_%0d.hex", dump_counter), RAM, 0, 63);
// dump_counter = dump_counter + 1;
// end
assign rd=RAM[address[31:2]]; // word aligned
always @ (posedge clk)
if (we)
RAM[address[31:2]]<=wd;
endmodule
//-------------------------------------------------------------------
module inst_mem (input [5:0] address,
output [31:0] rd);
reg [31:0] RAM[63:0];
initial begin
$readmemh ("Hladuvka_Ondrej_prog1.hex",RAM,0,63);
end
assign rd=RAM[address]; // word aligned
endmodule
module top ( input clk, reset,
output [31:0] data_to_mem, address_to_mem,
output write_enable);
wire [31:0] pc, instruction, data_from_mem;
inst_mem imem(pc[7:2], instruction);
data_mem dmem(clk, write_enable, address_to_mem, data_to_mem, data_from_mem);
processor CPU(clk, reset, pc, instruction, write_enable, address_to_mem, data_to_mem, data_from_mem);
endmodule
module testbench();
reg clk;
reg reset;
wire [31:0] data_to_mem, address_to_mem;
wire write_enable;
top simulated_system (clk, reset, data_to_mem, address_to_mem, write_enable);
initial begin
$dumpfile("test");
$dumpvars;
reset<=1; # 2; reset<=0;
#1000;
$writememh ("memfile_data_after_simulation.hex",simulated_system.dmem.RAM,0,63);
$finish;
end
// generate clock
always begin
clk<=1; # 1; clk<=0; # 1;
end
endmodule
//#############################################################