标签里没有Verilog很尴尬。。。用Verilog写一个Single Cycle Processor,主模块是processor。小模块有:
datapath, controller, ALUController, data memory, instruction memory,
register file,ALU, FlipFlop, ImmGen。一共九个小模块。这些模块我都写出来了,但是找不到错误在哪里,希望有人帮下忙。其实是很基础的东西,但是工作量会比较大所以悬赏也会比较多。可以确定没有问题的模块有Datapath,Controller,ALUController。顺便说下我用的是Vivado
大体的设计图如下:
还有:
processor的testbench如下
`timescale 1ns / 1ps
module tb_processor ();
/** Clock & reset **/
reg clk , rst ;
wire [31:0] tb_Result;
processor processor_inst(
.clk (clk),
.reset (rst),
.Result (tb_Result)
);
always begin
#10;
clk = ~clk;
end
initial begin
clk = 0;
@( posedge clk );
rst = 1;
@( posedge clk );
rst = 0;
end
integer point =0;
always @(*)
begin
#20;
if (tb_Result == 32'h00000000) // and
begin
point = point + 1;
end
#20;
if (tb_Result == 32'h00000001) // addi
begin
point = point + 1;
end
#20;
if (tb_Result == 32'h00000002) // addi
begin
point = point + 1;
end
#20;
if (tb_Result == 32'h00000004) // addi
begin
point = point + 1;
end;
#20;
if (tb_Result == 32'h00000005) // addi
begin
point = point + 1;
end;
#20;
if (tb_Result == 32'h00000007) // addi
begin
point = point + 1;
end
#20;
if (tb_Result == 32'h00000008) //addi
begin
point = point + 1;
end
# 20;
if (tb_Result == 32'h0000000b)// addi
begin
point = point + 1;
end
# 20;
if (tb_Result == 32'h00000003) // add
begin
point = point + 1;
end
# 20;
if (tb_Result == 32'hfffffffe) // sub
begin
point = point + 1;
end;
# 20;
if (tb_Result == 32'h00000000) // and
begin
point = point + 1;
end;
# 20;
if (tb_Result == 32'h00000005) // or
begin
point = point + 1;
end;
# 20;
if (tb_Result == 32'h00000001)// SLT
begin
point = point + 1;
end;
#20;
if (tb_Result == 32'hfffffff4) // NOR
begin
point = point + 1;
end
#20;
if (tb_Result == 32'h000004D2) // andi
begin
point = point + 1;
end
#20;
if (tb_Result == 32'hfffff8d7) // ori
begin
point = point + 1;
end
#20;
if (tb_Result == 32'h00000001) // SLT
begin
point = point + 1;
end;
# 20;
if (tb_Result == 32'hfffffb2c) // nor
begin
point = point + 1;
end;
# 20;
if (tb_Result == 32'h00000030) // sw
begin
point = point + 1;
end;
# 20;
if (tb_Result == 32'h00000030) // l
begin
point = point + 1;
end;
# 20;
if (tb_Result == 32'h00000030) // lw
begin
point = point + 1;
end;
$display ("%s%d","The number of correct test cases is:" , point);
end
initial begin
#430;
$finish ;
end
endmodule
正确的结果应该是这样↓
我自己的结果是这样↓
下面发我所有模块的代码
processor:
`timescale 1ns / 1ps
module processor
(
input clk, reset,
output [31:0] Result
);
wire reg_write1;
wire mem2reg1;
wire alu_src1;
wire mem_write1;
wire mem_read1;
wire [3:0]alu_cc1;
wire [6:0]opcode1;
wire [6:0]funct71;
wire [2:0]funct31;
wire [31:0] alu_result1;
wire [1:0]ALUOp1;
data_path un(
.clk(clk),
.reset(reset),
.alu_result(alu_result1),
.reg_write(reg_write1),
.mem2reg(mem2reg1),
.alu_src(alu_src1),
.mem_write(mem_write1),
.mem_read(mem_read1),
.alu_cc(alu_cc1),
.opcode(opcode1),
.funct7(funct71),
.funct3(funct31)
);
Controller uni(
.Opcode(opcode1),
.ALUSrc(alu_src1),
.MemtoReg(mem2reg1),
.RegWrite(reg_write1),
.MemRead(mem_read1),
.MemWrite(mem_write1),
.ALUOp(ALUOp1)
);
ALUController u(
.ALUOp(ALUOp1),
.Funct7(funct71),
.Funct3(funct31),
.Operation(alu_cc1)
);
assign Result = alu_result1;
endmodule
Datapath:
`timescale 1ns / 1ps
module data_path #(
parameter PC_W = 8,
parameter INS_W = 32,
parameter RF_ADDRESS = 5,
parameter DATA_W = 32,
parameter DM_ADDRESS = 9,
parameter ALU_CC_W = 4
)(
input clk ,
input reset ,
input reg_write ,
input mem2reg ,
input alu_src ,
input mem_write,
input mem_read,
input [ALU_CC_W -1:0] alu_cc ,
output [6:0] opcode ,
output [6:0] funct7,
output [2:0] funct3 ,
output [DATA_W -1:0] alu_result );
wire [PC_W -1:0] pc , pc_next;
wire [INS_W -1:0] instruction;
wire [DATA_W -1:0] l_alu_result;
wire [DATA_W -1:0] reg1 , reg2;
wire [DATA_W -1:0] l_read_data;
wire [DATA_W -1:0] l_reg_wr_data;
wire [DATA_W -1:0] srcb ;
wire [DATA_W -1:0] extimm;
assign pc_next = pc + 4;
FlipFlop pcreg(clk , reset , pc_next , pc);
Instr_mem instruction_mem (pc , instruction );
assign opcode = instruction [6:0];
assign funct7 = instruction [31:25];
assign funct3 = instruction [14:12];
RegFile rf(
.clk ( clk ),
.reset ( reset ),
.rg_wrt_en ( reg_write ),
.rg_wrt_addr ( instruction [11:7] ),
.rg_rd_addr1 ( instruction [19:15] ),
.rg_rd_addr2 ( instruction [24:20] ),
.rg_wrt_data ( l_reg_wr_data ),
.rg_rd_data1 ( reg1 ),
.rg_rd_data2 ( reg2 ));
assign l_reg_wr_data = mem2reg ? l_read_data : l_alu_result;
ImmGen ext_imm (instruction , extimm );
assign srcb = alu_src ? extimm : reg2;
alu_32 alu_module( .A_in(reg1), .B_in(srcb), .ALU_Sel(alu_cc),
.ALU_Out(l_alu_result), .Carry_Out(), .Zero(), .Overflow ());
assign alu_result = l_alu_result;
DataMem data_mem(.addr(l_alu_result[DM_ADDRESS -1:2]) , .read_data(l_read_data),
.write_data(reg2), .MemWrite(mem_write), .MemRead(mem_read) );
endmodule
FlipFlop:
`timescale 1ns / 1ps
module FlipFlop(
clk , reset,
d ,
q
);
input [7:0]d;
input clk;
input reset;
output reg [7:0]q;
always @(posedge clk) begin
if (reset)
q <= 0;
else
q <= d;
end
endmodule****
instruction memory:
**`timescale 1ns / 1ps**
// Module definition
module Instr_mem(
input [7:0] addr ,
output wire [31:0] instruction
);
reg [31:0] Instruction_memory [0:63];
initial
begin
Instruction_memory[0] = 32'h00007033;
Instruction_memory[1] = 32'h00100093;
Instruction_memory[2] = 32'h00200113;
Instruction_memory[3] = 32'h00308193;
Instruction_memory[4] = 32'h00408213;
Instruction_memory[5] = 32'h00510293;
Instruction_memory[6] = 32'h00610313;
Instruction_memory[7] = 32'h00718393;
Instruction_memory[8] = 32'h00208433;
Instruction_memory[9] = 32'h404404b3;
Instruction_memory[10] = 32'h00317533;
Instruction_memory[11] = 32'h0041e5b3;
Instruction_memory[12] = 32'h0041a633;
Instruction_memory[13] = 32'h007346b3;
Instruction_memory[14] = 32'h4d34f713;
Instruction_memory[15] = 32'h8d35e793;
Instruction_memory[16] = 32'h4d26a813;
Instruction_memory[17] = 32'h4d244893;
Instruction_memory[18] = 32'h02b02823;
Instruction_memory[19] = 32'h03002603;
end
assign instruction = Instruction_memory[addr];
endmodule
RegFile:
`timescale 1ns / 1ps
// Module definition
module RegFile(
clk , reset , rg_wrt_en ,
rg_wrt_addr ,
rg_rd_addr1 ,
rg_rd_addr2 ,
rg_wrt_data ,
rg_rd_data1 ,
rg_rd_data2
);
input clk;
input reset;
input rg_wrt_en;
input [4:0] rg_rd_addr1;
input [4:0] rg_rd_addr2;
output [31:0] rg_rd_data1;
output [31:0] rg_rd_data2;
input [4:0] rg_wrt_addr;
input [31:0] rg_wrt_data;
reg [31:0] register_file [0:31];
assign rg_rd_data1 = register_file[rg_rd_addr1];
assign rg_rd_data2 = register_file[rg_rd_addr2];
integer i;
always @(posedge clk or reset) begin
if (reset) begin
for (i = 0; i < 32; i = i + 1)
register_file[i] <= 0;
end else begin
if (rg_wrt_en)
register_file[rg_wrt_addr] <= rg_wrt_data;
end
end
endmodule
ImmGen:
`timescale 1ns / 1ps
module ImmGen(
InstCode ,
ImmOut
);
input [31:0] InstCode;
output reg [31:0] ImmOut;
always @(InstCode)
begin
case (InstCode[6:0])
7'b0000011 /*I-type load*/ :
ImmOut = {InstCode[31]? {20{1'b1}}:20'b0 , InstCode[31:20]};
7'b0010011 /*I-type addi*/ :
ImmOut = {InstCode[31]? {20{1'b1}}:20'b0 , InstCode[31:20]};
7'b0100011 /*S-type store*/ :
ImmOut = {InstCode[31]? {20{1'b1}}:20'b0 , InstCode[31:25], InstCode[11:7]};
7'b0010111 /*U-type AUIPC*/ :
ImmOut = {InstCode[31:12], 12'b0};
default
ImmOut = {32'b0};
endcase
end
endmodule
ALU:
`timescale 1ns / 1ps
module alu_32(
input [31:0] A_in ,B_in ,
input [3:0] ALU_Sel ,
output [31:0] ALU_Out ,
output reg Carry_Out ,
output Zero ,
output reg Overflow = 1'b0
);
reg [31:0] ALU_Result;
reg [32:0] temp;
reg [32:0] twos_com;
assign ALU_Out = ALU_Result;
assign Zero = (ALU_Result == 0);
always @(*)
begin
Overflow = 1'b0;
Carry_Out = 1'b0;
case(ALU_Sel)
4'b0000:
ALU_Result = A_in & B_in;
4'b0001:
ALU_Result = A_in | B_in;
4'b0010:
begin
ALU_Result = $signed(A_in) + $signed(B_in);
temp = {1'b0, A_in} + {1'b0, B_in};
Carry_Out = temp[32];
if ((A_in[31] & B_in[31] & ~ALU_Out[31]) |
(~A_in[31] & ~B_in[31] & ALU_Out[31]))
Overflow = 1'b1;
else
Overflow = 1'b0;
end
4'b0110:
begin
ALU_Result = $signed(A_in) - $signed(B_in) ;
twos_com = ~(B_in) + 1'b1;
if ((A_in[31] & twos_com[31] & ~ALU_Out[31]) |
(~A_in[31] & ~twos_com[31] & ALU_Out[31]))
Overflow = 1'b1;
else
Overflow = 1'b0;
end
4'b0111:
ALU_Result = ($signed(A_in) < $signed(B_in ))?32 'd1:32'd0;
4'b1100:
ALU_Result = ~(A_in | B_in);
4'b1111:
ALU_Result = (A_in==B_in )?32'd1:32'd0 ;
default: ALU_Result = A_in + B_in ;
endcase
end
endmodule
data memory:
`timescale 1ns / 1ps
module DataMem(MemRead, MemWrite, addr, write_data, read_data);
input wire MemRead;
input wire MemWrite;
input wire [8:0] addr;
input [31:0] write_data;
output reg [31:0] read_data;
reg [31:0] memory [0:127];
integer i;
initial
begin
read_data = 0;
for (i = 0; i < 128; i = i + 1) begin
memory[i] = i; end
end
always @(*)
begin
if (MemWrite)
memory[addr] = write_data;
if (MemRead)
read_data = memory[addr];
end
endmodule
Controller:
`timescale 1ns / 1ps
module Controller(
Opcode,
ALUSrc, MemtoReg, RegWrite, MemRead, MemWrite,
ALUOp
);
input [6:0] Opcode;
output reg ALUSrc;
output reg MemtoReg;
output reg RegWrite;
output reg MemRead;
output reg MemWrite;
output reg [1:0] ALUOp;
always @(*)
begin
case(Opcode)
7'b0110011: begin
MemtoReg = 1'b0;
MemWrite = 1'b0;
MemRead = 1'b0;
ALUSrc = 1'b0;
RegWrite = 1'b1;
ALUOp = 2'b10;
end
7'b0010011: begin
MemtoReg = 1'b0;
MemWrite = 1'b0;
MemRead = 1'b0;
ALUSrc = 1'b1;
RegWrite = 1'b1;
ALUOp = 2'b00;
end
7'b0000011: begin
MemtoReg = 1'b1;
MemWrite = 1'b0;
MemRead = 1'b1;
ALUSrc = 1'b1;
RegWrite = 1'b1;
ALUOp = 2'b01;
end
7'b0100011: begin
MemtoReg = 1'b0;
MemWrite = 1'b1;
MemRead = 1'b0;
ALUSrc = 1'b1;
RegWrite = 1'b0;
ALUOp = 2'b01;
end
default: begin
MemtoReg = 1'b0;
MemWrite = 1'b0;
MemRead = 1'b0;
ALUSrc = 1'b0;
RegWrite = 1'b1;
ALUOp = 2'b00;
end
endcase
end
endmodule
ALUController:
`timescale 1ns / 1ps
module ALUController(
ALUOp, Funct7, Funct3, Operation
);
input [1:0] ALUOp;
input [6:0] Funct7;
input [2:0] Funct3;
output reg [3:0] Operation;
wire [11:0] ALU_In;
assign ALU_In = {Funct7, Funct3, ALUOp};
always @(ALU_In)
casex (ALU_In)
12'b000000011110: Operation = 4'b0000;
12'b000000011010: Operation = 4'b0001;
12'b000000010010: Operation = 4'b1100;
12'b000000001010: Operation = 4'b0111;
12'b000000000010: Operation = 4'b0010;
12'b010000000010: Operation = 4'b0110;
12'bxxxxxxx11100: Operation = 4'b0000;
12'bxxxxxxx11000: Operation = 4'b0001;
12'bxxxxxxx10000: Operation = 4'b1100;
12'bxxxxxxx01000: Operation = 4'b0111;
12'bxxxxxxx00000: Operation = 4'b0010;
12'bxxxxxxx01001: Operation = 4'b0010;
12'bxxxxxxx01001: Operation = 4'b0010;
default: Operation = 4'b0000;
endcase
endmodule