658 lines
19 KiB
Verilog
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
|
|
|
|
//#############################################################
|