从子模块开始,按照向上的逻辑依次展示每一个模块代码如下:
immprocess.sv:根据immpro的控制信号处理立即数
module immprocess(input logic[31:0]instr,
input logic[2:0]immpro,
output logic[31:0]y);
always_comb
case(immpro)
3'b001:y={{20{instr[31]}},instr[31:20]};
3'b010:y={{20{instr[31]}},instr[31:25],instr[11:7]};
3'b011:y={{19{instr[31]}},instr[31],instr[7],instr[30:25],instr[11:8],1'b0};
3'b100:y={instr[31:12],12'b0};
3'b101:y={{11{instr[31]}},instr[31],instr[19:12],instr[20],instr[30:21],1'b0};
default:y=32'b0;
endcase
endmodule
adder.sv:一个加法器
module adder(input logic[31:0]a,
input logic[31:0]b,
output logic[31:0]y);
assign y = a+b;
endmodule
mux2.sv:一个2:1的选择器
module mux2#(parameter WIDTH = 8)
(input logic[WIDTH-1:0]d0,
input logic[WIDTH-1:0]d1,
input logic s,
output logic[WIDTH-1:0]y);
assign y = s?d1:d0;
endmodule
flopr.sv:处理下一个PC的模块
module flopr#(parameter WIDTH = 8)
(input logic clk,
input logic reset,
input logic[WIDTH-1:0]d,
output logic[WIDTH-1:0]q);
always_ff@(posedge clk,posedge reset)
if (reset)
q <= 0;
else
q <= d;
endmodule
regfile.sv:寄存器文件,对寄存器进行操作
module regfile(input logic clk,
input logic we3,
input logic[4:0] ra1,
input logic[4:0] ra2,
input logic[4:0] wa3,
input logic[31:0]wd3,
output logic[31:0]rd1,
output logic[31:0]rd2,
output logic[31:0]rf[31:0]
);
//three ported register file
// read two ports combinationally
// write third port on rising edge of clk
// register 0 hardwired to0
// note:for pipelined processor,write third port on falling edge of clk
always_ff@(posedge clk)
if (we3)
rf[wa3] <= wd3;
assign rd1 = (ra1!= 0)?rf[ra1]:0;
assign rd2 = (ra2!= 0)?rf[ra2]:0;
endmodule
alu.sv:根据alucontrol的信号决定alu进行何种运算
module alu(input logic [31:0] srca,
input logic [31:0] srcb,
input logic [3:0] alucontrol,
output logic [31:0] aluout,
output logic zero,
output logic smaller);
always_comb
case (alucontrol)
4'b0010: aluout = srca + srcb;
4'b0110: aluout = srca - srcb;
4'b0000: aluout = srca & srcb;
4'b0001: aluout = srca | srcb;
4'b0111: aluout = (srca < srcb) ? 32'd1 : 32'd0;
4'b0011: aluout = srca >> srcb;
4'b0100: aluout = srca << srcb;
4'b0101: aluout = srca ^ srcb;
4'b1000: aluout = srca >>> srcb;
default: aluout = 32'b0;
endcase
assign zero = (aluout == 32'b0);
assign smaller = (srca < srcb);
endmodule
datapath.sv:包含对alu与register整体处理的模块
module datapath(input logic clk,
input logic reset,
input logic memtoreg,
input logic branch_beq,
input logic branch_bne,
input logic branch_blt,
input logic alusrc,
input logic regwrite,
input logic jump,
input logic [3:0]alucontrol,
input logic [2:0]immpro,
input logic isonlyimm,
output logic [31:0] pc,
input logic [31:0] instr,
output logic [31:0] aluout,
output logic [31:0] writedata,
input logic [31:0] readdata,
output logic[31:0]rf[31:0]
);
logic[31:0]pcnext,pcnextbr_beq,pcnextbr_bne,pcnextbr_blt,pcplus4,pcbranch;
logic[31:0]signimm;
logic[31:0]srca,srcb;
logic[31:0]result_1,result;
logic zero,pcsrc_beq,pcsrc_bne,pcsrc_blt,smaller;
assign pcsrc_beq=zero & branch_beq;
assign pcsrc_bne=(~zero) & branch_bne;
assign pcsrc_blt=smaller & branch_blt;
immprocess immp(.instr(instr),
.immpro(immpro),
.y(signimm));
adder pcadd1(
.a(pc),
.b(32'b100),
.y(pcplus4)
);
adder pcadd2(
.a(pc),
.b(signimm),
.y(pcbranch)
);
mux2#(.WIDTH(32)) pcbrmux_beq(
.d0(pcplus4),
.d1(pcbranch),
.s(pcsrc_beq),
.y(pcnextbr_beq)
);
mux2#(.WIDTH(32)) pcbrmux_bne(
.d0(pcnextbr_beq),
.d1(pcbranch),
.s(pcsrc_bne),
.y(pcnextbr_bne)
);
mux2#(.WIDTH(32)) pcbrmux_blt(
.d0(pcnextbr_bne),
.d1(pcbranch),
.s(pcsrc_blt),
.y(pcnextbr_blt)
);
mux2#(.WIDTH(32)) pcmux(
.d0(pcnextbr_blt),
.d1(pcbranch),
.s(jump),
.y(pcnext)
);
//nextPC logic
flopr#(.WIDTH(32)) pcreg(
.clk(clk),
.reset(reset),
.d(pcnext),
.q(pc)
);
regfile rfile(
.clk(clk),
.we3(regwrite),
.ra1(instr[19:15]),
.ra2(instr[24:20]),
.wa3(instr[11:7]),
.wd3(result),
.rd1(srca),
.rd2(writedata),
.rf(rf)
);
//ALU logic
mux2#(.WIDTH(32)) srcbmux(
.d0(writedata),
.d1(signimm),
.s(alusrc),
.y(srcb)
);
alu alu(
.srca(srca),
.srcb(srcb),
.alucontrol(alucontrol),
.aluout(aluout),
.zero(zero),
.smaller(smaller)
);
// register file logic
mux2#(.WIDTH(32)) resmux(
.d0(aluout),
.d1(readdata),
.s(memtoreg),
.y(result_1)
);
mux2#(.WIDTH(32)) resimm(
.d0(result_1),
.d1(signimm),
.s(isonlyimm),
.y(result)
);
endmodule
controller.sv:控制器,根据输入的机器码决定一系列控制信号
module controller(input logic [6:0]opcode,
input logic [6:0]funct7,
input logic [2:0]funct3,
output logic [2:0]immpro,
output logic isonlyimm,
output logic memtoreg,
output logic memwrite,
output logic branch_beq,
output logic branch_bne,
output logic branch_blt,
output logic alusrc,
output logic regwrite,
output logic jump,
output logic [3:0]alucontrol
);
logic [15:0]controls;
always_comb
case(opcode)
7'b0110011://处理R指令
case(funct7)
7'b0000000:
case(funct3)
3'b000:controls=16'b1_0_0_0_0_0_0_0_0010_000_0;//add
3'b001:controls=16'b1_0_0_0_0_0_0_0_0100_000_0;//sll
3'b010:controls=16'b1_0_0_0_0_0_0_0_0111_000_0;//slt
3'b100:controls=16'b1_0_0_0_0_0_0_0_0101_000_0;//xor
3'b101:controls=16'b1_0_0_0_0_0_0_0_0011_000_0;//srl
3'b110:controls=16'b1_0_0_0_0_0_0_0_0001_000_0;//or
3'b111:controls=16'b1_0_0_0_0_0_0_0_0000_000_0;//and
default:controls=16'bx_x_x_x_x_x_x_x_xxxx_xxx_x;
endcase
7'b0100000:
case(funct3)
3'b000:controls=16'b1_0_0_0_0_0_0_0_0110_000_0;//sub
3'b101:controls=16'b1_0_0_0_0_0_0_0_1000_000_0;//sra
default:controls=16'bx_x_x_x_x_x_x_x_xxxx_xxx_x;
endcase
default:controls=16'bx_x_x_x_x_x_x_x_xxxx_xxx_x;
endcase
7'b0010011://第一类I指令
case(funct3)
3'b000:controls=16'b1_1_0_0_0_0_0_0_0010_001_0;//addi
3'b110:controls=16'b1_1_0_0_0_0_0_0_0001_001_0;//ori
3'b111:controls=16'b1_1_0_0_0_0_0_0_0000_001_0;//andi
default:controls=16'bx_x_x_x_x_x_x_x_xxxx_xxx_x;
endcase
7'b0000011://lw指令
controls=16'b1_1_0_0_0_0_1_0_0010_001_0;//lw
7'b0100011://sw指令
controls=16'b0_1_0_0_0_1_0_0_0010_010_0;//sw
7'b1100111://jalr指令
controls=16'b1_1_0_0_0_0_0_1_0010_001_0;//jalr
7'b1100011://B指令
case(funct3)
3'b000:controls=16'b0_0_1_0_0_0_0_0_0110_011_0;//beq
3'b001:controls=16'b0_0_0_1_0_0_0_0_0110_011_0;//bne
3'b100:controls=16'b0_0_0_0_1_0_0_0_0110_011_0;//blt
default:controls=16'bx_x_x_x_x_x_x_x_xxxx_xxx_x;
endcase
7'b1101111://J指令
controls=16'b0_0_0_0_0_0_0_1_0010_101_0;//jal
7'b0110111:
controls=16'b1_1_0_0_0_0_0_0_0010_100_1;//lui
default:controls=16'bx_x_x_x_x_x_x_x_xxxx_xxx_x;
endcase
assign {regwrite,alusrc,branch_beq,branch_bne,branch_blt,memwrite,memtoreg,jump,alucontrol,immpro,isonlyimm} = controls;
endmodule
risc.sv:单周期RISC-V处理器对机器码处理整体实现
module risc(input logic clk,
input logic reset,
output logic[31:0]pc,
input logic[31:0]instr,
output logic memwrite,
output logic[31:0]aluout,
output logic[31:0]writedata,
input logic[31:0]readdata,
output logic[31:0]rf[31:0])
;
logic memtoreg,alusrc,regwrite,jump,branch_beq,branch_bne,branch_blt,isonlyimm;
logic [3:0]alucontrol;
logic [2:0]immpro;
controller c(
.opcode(instr[6:0]),
.funct7(instr[31:25]),
.funct3(instr[14:12]),
.immpro(immpro),
.isonlyimm(isonlyimm),
.memtoreg(memtoreg),
.memwrite(memwrite),
.branch_beq(branch_beq),
.branch_bne(branch_bne),
.alusrc(alusrc),
.regwrite(regwrite),
.jump(jump),
.alucontrol(alucontrol),
.branch_blt(branch_blt)
);
datapath dp(
.clk(clk),
.reset(reset),
.memtoreg(memtoreg),
.branch_beq(branch_beq),
.branch_bne(branch_bne),
.branch_blt(branch_blt),
.alusrc(alusrc),
.regwrite(regwrite),
.jump(jump),
.alucontrol(alucontrol),
.immpro(immpro),
.isonlyimm(isonlyimm),
.pc(pc),
.instr(instr),
.aluout(aluout),
.writedata(writedata),
.readdata(readdata),
.rf(rf)
);
endmodule
imem.sv:指令存储器
module imem(input logic[5:0] a,
output logic[31:0]rd);
/*
logic[31:0]RAM[63:0];
initial
$readmemh("C:\Users\DELL\Desktop\单周期RISC-V处理器设计\memfile.dat",RAM);
*/
// 不要声明很大的数组,FPGA板子放不下
//基本测试,用于跑simulation出一个较好的波形图
logic[31:0]RAM[0:18] = { // 注意!指令存储器容量最多只有64个字!
32'h00500113,
32'h00c00193,
32'hff718393,
32'h0023e233,
32'h0041f2b3,
32'h004282b3,
32'h02728663,
32'h0041a233,
32'h00020463,
32'h00000293,
32'h0023a233,
32'h005203b3,
32'h402383b3,
32'h0471a223,
32'h05002103,
32'h008000ef,
32'h00100113,
32'h04202a23,
32'hfe000ee3 // beq $0,$0,self,跳转到自己,终止执行后续指令
};
/*
//求1到100和的测试,用于跑BASYS板子
logic[31:0]RAM[0:11] = { // 注意!指令存储器容量最多只有64个字!
32'h000003b7,
32'h00038393,
32'h00000437,
32'h06340413,
32'h000004b7,
32'h00048493,
32'h00944863,
32'h00148493,
32'h009383b3,
32'hff5ff0ef,
32'h04702a23,
32'hfe000ee3 // beq $0,$0,self,跳转到自己,终止执行后续指令
};
*/
assign rd = RAM[a]; // 注意!指令存储器容量最多只有64个字!
endmodule
dmem.sv:数据存储器
module dmem(input logic clk,
input logic we,
input logic[31:0]a,
input logic[31:0]wd,
output logic[31:0]rd);
// 不要声明很大的数组,FPGA板子放不下
logic[31:0]RAM[63:0]; // 注意!数据存储器容量最多只有64个字!
assign rd = RAM[a[7:2]]; // word aligned
always_ff@(posedge clk)
if (we)
RAM[a[7:2]] <= wd;
endmodule
以上是所必需的基本模块,下面的模块分别用于跑板子和跑simulation。
(一)跑simulation所需的模块:
top.sv:用于跑simulation的顶层模块
module top(input logic clk,
input logic reset,
output logic success_led,
output logic fail_led,
output logic[31:0] pc
);
logic[31:0]readdata,instr,dataadr,writedata;
logic memwrite;
logic[31:0]rf[31:0];
//instantiate processor and memories
imem imem(
.a(pc[7:2]),
.rd(instr)
);
risc risc(
.clk(clk),
.reset(reset),
.pc(pc),
.instr(instr),
.memwrite(memwrite),
.aluout(dataadr),
.writedata(writedata),
.readdata(readdata),
.rf(rf)
);
dmem dmem(
.clk(clk),
.we(memwrite),
.a(dataadr),
.wd(writedata),
.rd(readdata)
);
// 加入两个led指示灯。当写入存储器地址84且数据是7时,点亮success_led灯
// 如果第1次写入的地址不是80,点亮fail_led灯
always_ff @(posedge clk,posedge reset)
if (reset)
begin
success_led <= 1'b0;
fail_led <= 1'b0;
end
else if (memwrite == 1'b1)
begin
if (dataadr == 84 & writedata == 7)
success_led <= 1'b1;
else if (dataadr != 80)
fail_led <= 1'b1;
end
endmodule
testbench.sv:用于跑simulation的仿真波形图
`timescale 1ns / 1ps
module testbench();
logic clk;
logic reset;
logic success_led;
logic fail_led;
logic [31:0]pc;
// instantiate device to be tested
top dut(
.clk(clk),
.reset(reset),
.success_led(success_led),
.fail_led(fail_led),
.pc(pc)
);
// initialize test
initial
begin
reset = 1;
#10;
reset = 0;
end
// generate clock to sequence tests
always
begin
clk = 1;
#1;
clk = 0;
#1;
end
// check results
always@(posedge clk)
begin
if (success_led)
begin
$display("Simulation succeeded");
end
if (fail_led)
begin
$display("Simulation failed");
end
end
endmodule
(二)跑板子所需的模块
display_sum.sv:用于让板子显示最后求和得到的结果
`timescale 1ns / 1ps
module display_sum(
input clk,
input [31:0]num,
output logic [10:0] disp_7seg
);
logic [1:0] sel=0;
logic [19:0]count=0;
logic [3:0] num1,num2,num3,num4,disp_number;
parameter T1MS=50000;
always@(posedge clk)
begin
count<=count+1;
if(count==T1MS)
begin
count<=0;
sel<=sel+1;
if(sel==4)
sel<=0;
end
end
assign num1=num/1000%10;
assign num2=num/100%10;
assign num3=num/10%10;
assign num4=num%10;
always_comb
case(disp_number)
4'd0: disp_7seg[6:0] = 7'b0000001;
4'd1: disp_7seg[6:0] = 7'b1001111;
4'd2: disp_7seg[6:0] = 7'b0010010;
4'd3: disp_7seg[6:0] = 7'b0000110;
4'd4: disp_7seg[6:0] = 7'b1001100;
4'd5: disp_7seg[6:0] = 7'b0100100;
4'd6: disp_7seg[6:0] = 7'b0100000;
4'd7: disp_7seg[6:0] = 7'b0001111;
4'd8: disp_7seg[6:0] = 7'b0000000;
4'd9: disp_7seg[6:0] = 7'b0000100;
default: disp_7seg[6:0] = 7'b1111111;
endcase
always_comb
case(sel)
0: begin disp_7seg[10:7] = 4'b1110; disp_number = num4; end
1: begin disp_7seg[10:7] = 4'b1101; disp_number = num3; end
2: begin disp_7seg[10:7] = 4'b1011; disp_number = num2; end
3: begin disp_7seg[10:7] = 4'b0111; disp_number = num1; end
default:begin disp_7seg[10:7] = 4'b1111; disp_number = 4'd0; end
endcase
endmodule
top_show_sum.sv:跑板子所需的顶层模块
`timescale 1ns / 1ps
module top_show_sum(input logic clk,
input logic reset,
output logic [10:0] disp_7seg
);
logic[31:0]readdata,instr,pc,dataadr,writedata;
logic[31:0]rf[31:0];
logic memwrite;
//instantiate processor and memories
imem imem(
.a(pc[7:2]),
.rd(instr)
);
risc risc(
.clk(clk),
.reset(reset),
.pc(pc),
.instr(instr),
.memwrite(memwrite),
.aluout(dataadr),
.writedata(writedata),
.readdata(readdata),
.rf(rf)
);
dmem dmem(
.clk(clk),
.we(memwrite),
.a(dataadr),
.wd(writedata),
.rd(readdata)
);
display_sum dis(
.clk(clk),
.num(rf[7]),
.disp_7seg(disp_7seg)
);
endmodule
约束文件(可以根据自己需求自行修改调整):
set_property PACKAGE_PIN W5 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports clk]
set_property PACKAGE_PIN V17 [get_ports reset]
set_property IOSTANDARD LVCMOS33 [get_ports reset]
set_property PACKAGE_PIN W4 [get_ports {disp_7seg[10]}]
set_property PACKAGE_PIN V4 [get_ports {disp_7seg[9]}]
set_property PACKAGE_PIN U4 [get_ports {disp_7seg[8]}]
set_property PACKAGE_PIN U2 [get_ports {disp_7seg[7]}]
set_property PACKAGE_PIN W7 [get_ports {disp_7seg[6]}]
set_property PACKAGE_PIN W6 [get_ports {disp_7seg[5]}]
set_property PACKAGE_PIN U8 [get_ports {disp_7seg[4]}]
set_property PACKAGE_PIN V8 [get_ports {disp_7seg[3]}]
set_property PACKAGE_PIN U5 [get_ports {disp_7seg[2]}]
set_property PACKAGE_PIN V5 [get_ports {disp_7seg[1]}]
set_property PACKAGE_PIN U7 [get_ports {disp_7seg[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {disp_7seg[10]}]
set_property IOSTANDARD LVCMOS33 [get_ports {disp_7seg[9]}]
set_property IOSTANDARD LVCMOS33 [get_ports {disp_7seg[8]}]
set_property IOSTANDARD LVCMOS33 [get_ports {disp_7seg[6]}]
set_property IOSTANDARD LVCMOS33 [get_ports {disp_7seg[7]}]
set_property IOSTANDARD LVCMOS33 [get_ports {disp_7seg[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {disp_7seg[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {disp_7seg[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {disp_7seg[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {disp_7seg[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {disp_7seg[0]}]
PS:(1)注意跑板子与跑仿真图之间切换时,imem.sv中的测试指令集机器码也要切换;
(2)跑板子时将跑仿真图所需的两个模块(top.sv与testbench.sv)disable掉,跑仿真图时同理;
(3)板子只会显示最后的计算结果,可以创新让板子显示出每一次迭代后求和的计算结果(在本人下一个“多周期RISC-V处理器实现”中有实现这个效果)
(4)记得文件路径不要带中文,否则跑不了板子!!!(本人因为这个耗了一晚上时间捏)