概述
PC:
module PC(
input rst,
input clk,
input [31:0] next,
output reg [31:0] addr
);
always @(posedge clk)
if(rst)
addr<=32'h0
else
addr <=next;
initial
$monitor($time ,,"=====================================pc:addr=%h",addr);
initial
$monitor($time ,,"pc:next=%h",next);
endmodule
ROM:
module rom(
input[31:0] addr,
output reg [31:0] ins
);
always @(*)
begin
case(addr)
//立即数测试(I类指令,除了load,jalr指令)
32'h0:ins=32'h00100093;//addi x1,x0,1;
32'h4:ins=32'h00100093;//addi x2,x0,1;
32'h8:ins=32'h00100113;//slti x3,x2,3;
32'hc:ins=32'h00312193;//sltiu x4,x1,3;
32'h10:ins=32'h0030b213;//xori x5 ,x0,1;
32'h14:ins=32'h00104293;//ori x6,x1,0x789;
32'h18:ins=32'h7890e313;//andi x7,x1,10;
32'h1c:ins=32'h00a0f393;//slli x6,x1,1;
32'h20:ins=32'h00109313;//srli x7,x1,1;
32'h24:ins=32'h0010d393;//srai x8,x2,1;
32'h28:ins=32'h40115413;//lw x10,1(x0);
32'h2c:ins=32'h00102503;//lb x11,1(x0);
//R类测试
32'h30:ins=32'h00100583;//lbu x12,1(x0);
32'h34:ins=32'h00104603;// lh x13,1(x0);
32'h38:ins=32'h00101683;//lhu x14,1(x0);
32'h3c:ins=32'h00105703;// sw x4,4(x0);
32'h40:ins=32'h00402223;//sb x1,8(x0);
32'h44:ins=32'h00100423;// sh x3,12(x0);
32'h48:ins=32'h00301623;// beq x3,x4,4;
32'h4c:ins=32'h00418263;// bne x3,x4,4;
32'h50:ins=32'h00419263;// blt x3,x4,4;
32'h54:ins=32'h0041c263;//bltu x2,x4,4;
//store指令
32'h58:ins=32'h00416263;//bge x2,x4,4;
32'h5c:ins=32'h00415263;// bgeu x2,x4,4;
32'h60:ins=32'h00417263;// lui x3,10;
//load
32'h64:ins=32'h0000a1b7;//auipc x15,4,;
32'h68:ins=32'h00004797;//jal x10,4;
32'h6c:ins=32'h0040056f;// jalr x11,x3,4
32'h70:ins=32'h004185e7;// add x3,x2,x1;
32'h74:ins=32'h001101b3;//sub x10,x4,x3
//auipc
32'h78:ins=32'h40320533;//sll x11,x4,x3;
//B类指令
32'h7c:ins=32'h003215b3 ;//slt x12,x4,x3;
32'h80:ins=32'h00322633;//sltu x13,x2,x3;
32'h84:ins=32'h003136b3;// xor x14,x3,x4;
32'h88:ins=32'h0041c733;// srl x15,x4,x3;
32'h8c:ins=32'h003257b3;// bge x2,x4,12 下一条
32'h90:ins=32'h40325833;//sra x16,x4,x3;
//jalr
32'h94:ins=32'h0041e8b3;// or x17,x3,x4;
//jal
32'h98:ins=32'h0041f5b3;//and x11,x3,x4;
endcase
end
initial
$monitor($time ,,"rom:addr=%h,ins=%h",addr,ins);
endmodule
实验二(实现斐波那契数):
`timescale 1ns / 1ps
module rom(
input[31:0] addr,
output reg [31:0] ins
);
always @(*)
begin
case(addr)
32'h0:ins=32'h04002203;//lw x4,40h(x0);
32'h4:ins=32'h00300293;//addi x5,x0,3
32'h8:ins=32'h00100093;//addi x1,x0,1
32'hc:ins=32'h00100113;//addi x2,x0,1
32'h10:ins=32'h001101b3;
32'h14:ins=32'h000100b3;
32'h18:ins=32'h00018133;
32'h1c:ins=32'h001101b3;
32'h20:ins=32'hfff20213;
32'h24:ins=32'hfe42e8e3;
32'h28:ins=32'h08302023;//sw
endcase
end
initial
$monitor($time ,,"rom:addr=%h,ins=%h",addr,ins);
endmodule
分析指令(ID)相关模块代码:
ID:
`timescale 1ns / 1ps
module ID(
input [31:0] ins,
output [4:0] rs1,
output [4:0] rs2,
output [4:0] rd,
output [6:0] opcode,
output [11:0] imm12,//12位立即数
output [2:0] func,
output [19:0] imm20,//20位立即数
output dis//区分码,指令的第30位
);
assign opcode =ins[6:0];
assign rd =ins[11:7];
assign func =ins[14:12];
assign rs1 =ins[19:15];
assign rs2 =ins[24:20];
assign dis =ins[30];
wire I_type ,S_type,B_type, J_type,U_type,R_type;
//00x0011 I指令 ||1100111 jalr
assign I_type =(~ins[6]&~ins[5]&~ins[3]&~ins[2]&ins[1]&ins[0])|
((&ins[6:5])&~(|ins[4:3])&(&ins[2:0]));
//1100011 B指令
assign B_type =(&ins[6:5])&~(|ins[4:2])&(&ins[1:0]);
//0100011 S指令
assign S_type =~ins[6]&ins[5]&~(|ins[4:2])&(&ins[1:0]);
//1101111 J指令 jal
assign J_type =(&ins[6:5])&~ins[4]&(&ins[3:0]);
//0x10111 U指令
assign U_type =~ins[6]&ins[4]&~ins[3]&(&ins[2:0]);
//0110011 R指令
assign R_type =~ins[6]&(&ins[5:4])&~(|ins[3:2])&(&ins[1:0]);
assign imm12={12{I_type}}&ins[31:20]|
{12{B_type}}&{ins[31],ins[7],ins[30:25],ins[11:8]}|
{12{S_type}}&{ins[31:25],ins[11:7]};
assign imm20={20{U_type}}&ins[31:12]|
{20{J_type}}&{ins[31],ins[19:12],ins[20],ins[30:21]};
initial
$monitor($time ,,"ID:rs1=%b,rs2=%b,rd=%b",rs1,rs2,rd);
endmodule
ControlUnit:
module ControlUnit(
input [6:0] opcode,
input [2:0] func,
input dis,
input c,//满足B类跳转
output reg [1:0] pcs,//下一条指令地址来源
output reg rwe,//寄存器写使能端
output reg mwe,//RAM写使能端
output reg [2:0] mm,//RAM读写方式
output reg [3:0] aluOP,//运算类型
output reg isimm,//b是否是立即数
output reg is20,//b是否为20的立即数
output reg isfpc,//a来源于pc
output reg isfm,//rwdata是否来源于mem
output reg ispc4//rwdata是否来源于pc+4
);
always @(*)
begin
case(opcode)
7'b0110011://R类指令
begin
rwe=1'b1;//控制器(CU)产生aluOP信号给ALU,产生rwe信号(1'b1)给寄存器堆,产生pcs信号(2'b00)给数据选择器MUX。
pcs=2'b00;//R类指令不是跳转指令, pcs的值是2'b00
mwe=1'b0;
isimm=1'b0;//通过PC从ROM中读出R类指令
is20=1'b0;
isfpc=1'b0;
isfm=1'b0;
ispc4=1'b0;
if(dis)
begin
case(func)
3'b000:
aluOP=4'b0010;//sub
3'b101:
aluOP=4'b0110;//sra
endcase
end
else
begin
case(func)
3'b000:
aluOP=4'b0001;//add
3'b111:
aluOP=4'b0011;//and
3'b110:
aluOP=4'b0100;//or
3'b100:
aluOP=4'b0101;//xor
3'b001:
aluOP=4'b0111;//sll
3'b101:
aluOP=4'b1000;//srl
3'b010:
aluOP=4'b1001;//slt
3'b011:
aluOP=4'b1010;//sltu
endcase
end
end
7'b0010011://I类指令,除了load,jalr指令
begin
rwe=1'b1;//产生rwe信号(1'b1)给寄存器堆,产生pcs信号(2'b00)给数据选择器MUX
pcs=2'b00;//立即数指令不是跳转指令, pcs的值是2`b00
mwe=1'b0;
isimm=1'b1;//从ROM中读出立即数指令
is20=1'b0;
isfpc=1'b0;
isfm=1'b0;
ispc4=1'b0;
case(func)
3'b000:
aluOP=4'b0001;//addi
3'b111:
aluOP=4'b0011;//andi
3'b110:
aluOP=4'b0100;//ori
3'b100:
aluOP=4'b0101;//xori
3'b001:
aluOP=4'b0111;//slli
3'b101:
if(dis)
aluOP=4'b0110;//srai
else
aluOP=4'b1000;//srli
3'b010:
aluOP=4'b1001;//slti
3'b011:
aluOP=4'b1010;//sltui
endcase
end
7'b0000011://load指令
begin
rwe=1'b1;//产生rwe信号(1'b1)给寄存器堆,产生pcs信号(2'b00) 给数据选择器MUX
pcs=2'b00;
mwe=1'b0;
isimm=1'b1;//产生mm信号给数据存储器RAM
is20=1'b0;
isfpc=1'b0;
isfm=1'b1;
ispc4=1'b0;
case(func)
3'b000:
begin
mm=3'b000;
aluOP=4'b0001;//lb
end
3'b001:
begin
mm=3'b001;
aluOP=4'b0001;//lh
end
3'b010:
begin
aluOP=4'b0001;//lw
mm=3'b010;
end
3'b100:
begin
mm=3'b011;
aluOP=4'b0001;//lbu
end
3'b101:
begin
mm=3'b100;
aluOP=4'b0001;//lhu
end
endcase
end
7'b0100011://store指令
begin
rwe=1'b0;
pcs=2'b00;
mwe=1'b1;//产生mwe信号(1'b1)给RAM,产生pcs信号(2'b00)给数据选择器MUX
isimm=1'b1;//产生mm信号给数据存储器RAM
is20=1'b0;
isfpc=1'b0;
isfm=1'b0;
ispc4=1'b0;
case(func)
3'b000:
begin
mm=3'b101;
aluOP=4'b0001;//sb
end
3'b001:
begin
mm=3'b110;
aluOP=4'b0001;//sh
end
3'b010:
begin
aluOP=4'b0001;//sw
mm=3'b111;
end
endcase
end
7'b0110111://lui指令
begin
rwe=1'b1;//产生rwe信号(1'b1)给寄存器堆,产生pcs信号(2'b00)给数据选择器MUX
pcs=2'b00;
mwe=1'b0;
isimm=1'b1;
is20=1'b1;//ID还产生了20位的立即数imm20
isfpc=1'b0;
isfm=1'b0;
ispc4=1'b0;
aluOP=4'b1011;//lui
end
7'b0010111://auipc指令
begin
rwe=1'b1;//产生rwe信号(1'b1)给寄存器堆,产生pcs信号(2'b00)给数据选择器MUX
pcs=2'b00;
mwe=1'b0;
isimm=1'b1;
is20=1'b1;//ID还产生了20位的立即数imm20
isfpc=1'b1;//ALU有了a端数据(pc)
isfm=1'b0;
ispc4=1'b0;
aluOP=4'b1100;//auipc
end
7'b1100011://B指令
begin
rwe=1'b0;
mwe=1'b0;
isimm=1'b0;
is20=1'b0;
isfpc=1'b0;
isfm=1'b0;
ispc4=1'b0;
if(c==0)//CU根据c的值产生pcs信号给MUX,MUX进行2选1,将结果next传给PC
pcs=2'b00;
else
pcs=2'b01;
case(func)
3'b000:
begin
aluOP=4'b0010;//beq
end
3'b001:
begin
aluOP=4'b0101;//bne
end
3'b100:
begin
aluOP=4'b1001;//blt
end
3'b101:
begin
aluOP=4'b1101;//bge
end
3'b110:
begin
aluOP=4'b1010;//bltu
end
3'b111:
begin
aluOP=4'b1110;//bgeu
end
endcase
end
7'b1101111://jal指令
begin
rwe=1'b1;
pcs=2'b10;
mwe=1'b0;
isimm=1'b0;
is20=1'b0;
isfpc=1'b0;
isfm=1'b0;
ispc4=1'b1;//产生rwe信号(1`b1)给寄存器堆,产生ispc4信号(1`b1) 用来选择pc+4
end
7'b1100111://jalr指令
begin
rwe=1'b1;//控制器(CU)产生pcs信号(2`b11)给MUX,产生rwe信号(1`b1)给寄存器堆,产生ispc4信号(1`b1) 用来选择pc+4,产生isimm(1`b1)、is20(1`b0)、isfpc(1`b0)。
pcs=2'b11;
mwe=1'b0;
isimm=1'b1;
is20=1'b0;
isfpc=1'b0;
isfm=1'b0;
ispc4=1'b1;
aluOP=4'b1111;//jalr
end
endcase
end
endmodule
执行指令(EXE)相关模块代码:
REGS:
module REGS(
input clk,
input rwe,
input[4:0] rs1,
input[4:0] rs2,
output[31:0] Rdata1,
output[31:0] Rdata2,
input[4:0] rd,
input[31:0] rwdata
);
//31个 32位宽
reg[31:0] r[1:31];
assign Rdata1=(rs1==5'b00000)? 32'b0 : r[rs1];
assign Rdata2=(rs2==5'b00000)? 32'b0 : r[rs2];
always @(posedge clk)
if(rwe)//使能端为1,可写
if(rd!=5'b00000)
r[rd]<=rwdata;
initial
$monitor($time ,,"regs:Rdata1=%h, Rdata2=%h,rwdata=%h",Rdata1,Rdata2,rwdata);
endmodule
ALU:
`timescale 1ns / 1ps
module ALU(
input[3:0] aluOP,
input[31:0] a,
input[31:0] b,
output reg[31:0] f ,
output reg c
);
always @(*)
case(aluOP)
4'b0000: f=31'b0;
4'b0001: f=a+b; //add
4'b0010:
begin
f=a-b; //sub
c=~(|f);
end
4'b0011: f=a&b; //and
4'b0100: f=a|b; //or
4'b0101:
begin
f=a^b;//xor
if(f==0)
c=0;
else
c=1;
end
4'b0110: f=$signed(a)>>>b[4:0];//sra
4'b0111: f=a<<b[4:0];//sll
4'b1000: f=a>>b[4:0];//srl
4'b1001:
if($signed(a)<$signed(b))//slt
begin
f=32'b1;
c=1'b1;
end
else
begin
f=32'b0;
c=1'b0;
end
4'b1010:
if(a<b)//sltu
begin
f=32'b1;
c=1'b1;
end
else
begin
f=32'b0;
c=1'b0;
end
4'b1011: f=b<<12;//lui
4'b1100:
begin
f=b<<12;//auipc
f=f+a;
end
4'b1101:
if($signed(a)>=$signed(b))//bge
begin
c=1'b1;
end
else
begin
c=1'b0;
end
4'b1110:
if(a>=b)//bgeu
begin
c=1'b1;
end
else
begin
c=1'b0;
end
4'b1111: //jalr
begin
f=a+b;
f[0]=0;
end
endcase
initial
$monitor($time ,,"alu:a=%h, b=%h,f=%h",a,b,f);
initial
$monitor($time ,,"alu:f=%h",f);
endmodule
MUX:
module MUX(
input [1:0]pcs,
input [31:0] addr,
input [31:0] imm12,
input [31:0] imm20,
input [31:0] f,
output reg [31:0] next
);
always @(*)
begin
case(pcs)
2'b00:next=addr+4;
2'b01:next=(imm12<<1)+addr;
2'b10:next=(imm20<<1)+addr;
2'b11:next=f;
endcase
end
initial
$monitor($time ,,"MUX:next=%h",next);
Endmodule
RAM:
`timescale 1ns / 1ps
module ram(
input[5:0] addr,//2^6=64
input[31:0] wdata,
input clk,
input we,
output[31:0] rdata
);
//RAM
reg[31:0] r[0:63];
//读数据
assign rdata=r[addr];
//写入
always @(posedge clk)
begin
if(we)
begin
r[addr]<=wdata;
end
end
endmodule
newram:
module newram(
input[5:0] maddr,
input[31:0] mwdata,
input mwe,
input clk,
input[2:0] mm,
output[31:0] mdata
);
//操作
wire lb,lh,lw,lbu,lhu,sb,sh,sw;
//输入和输出
wire[31:0]temp_in;
wire[31:0]temp_out;
//用于输出处理
assign lb=~(|mm); //000
assign lh=~(|mm[2:1])&mm[0];//001
assign lw=(~mm[2]&mm[1]&~mm[0]);//010
assign lbu=(&mm[1:0])&~mm[2];//011
assign lhu=mm[2]&~(|mm[1:0]);//100
assign mdata = {32{lb}}&{{24{temp_out[7]}},temp_out[7:0]}|
{32{lh}}&{{16{temp_out[15]}},temp_out[15:0]}|
{32{lw}}&temp_out|
{32{lbu}}&{24'b0,temp_out[7:0]}|
{32{lhu}}&{16'b0,temp_out[15:0]};
//用于输入处理
assign sb=mm[2]&~mm[1]&mm[0];//101
assign sh=(&mm[2:1])&~mm[0];//110
assign sw=&mm[2:0];//111
assign temp_in=({{24'b0},{8{sb}}}|{{16'b0,{16{sh}}}}|{32{sw}})&mwdata;
ram ram1(.addr(maddr),.wdata(temp_in),.we(mwe),.clk(clk),.rdata(temp_out));
initial $monitor($time,,"ram:mm=%b,mwe=%b,maddr=%h,mwdata=%h,mdata=%h",mm,mwe,maddr,mwdata,mdata);
endmodule
IOManger:
`timescale 1ns / 1ps
module IOManger(
input [7:0]maddr,
input [2:0]mm,
input clk,
input we,
input [31:0]wdata,
input [5:0]n,
output [31:0] data,
output reg [31:0]result
);
wire [31:0] mwdata,mdata;
wire memEnable,mwe;
assign memEnable=~(|maddr[7:6]);
assign mwe =memEnable&we;
//实例化RAM
newram newram1 (
.maddr(maddr[5:0]),
.mm(mm),
.clk(clk),
.mwe(mwe),
.mdata(mdata),
.mwdata(mwdata)
);
//data是lw指令的输出结果,来源于两个,
assign data=maddr[6]?{26'h0,n}:mdata;
assign mwdata=wdata;
//当sw指令地址maddr[7]==1时,表示输出结果
always @(posedge clk)
if(we&&maddr[7])
result<=wdata;
initial
$monitor($time ,,"IOManger:maddr=%b,result=%h",maddr,result);
initial
$monitor($time ,,"IOManger:wdata=%b,data=%h",wdata,data);
endmodule
top:
module top(
input rst,
input clk,
input [5:0] n,
output [31:0]result
);
wire [31:0] next,addr,ins;
wire [4:0] rs1,rs2,rd;
wire [6:0] opcode;
wire [11:0] imm12;
wire [2:0] func;
wire [19:0] imm20;
wire [31:0] imm12_exp,imm20_exp,Rdata1,Rdata2,mwdata,mdata,f;
wire [1:0] pcs;
wire [2:0] mm;
wire [3:0] aluOP;
reg [31:0] rwdata,a,b;
wire dis,c,rwe,mwe,isimm,is20,isfpc,isfm,ispc4;
wire [7:0]IOaddr;
wire clk18;
assign imm12_exp={{20{imm12[11]}},imm12};
assign imm20_exp={{12{imm20[19]}},imm20};
always @(*)
begin
if(isimm)
if(is20)
b=imm20_exp;
else
b=imm12_exp;
else
b=Rdata2;
if(isfpc)
a=addr;
else
a=Rdata1;
if(ispc4)
rwdata=addr+4;
else
if(isfm)
rwdata=mdata;
else
rwdata=f;
end
assign mwdata=Rdata2;
assign IOaddr = f[7:0];
PC pc1(.rst(rst),. clk(clk),.next(next),.addr(addr));
rom rom1(.addr(addr),.ins(ins));
ID id1(.ins(ins),.rs1(rs1),.rs2(rs2),.rd(rd),.opcode(opcode),.imm12(imm12),.func(func),.imm20(imm20),.dis(dis));
ControlUnit cu1(.opcode(opcode),.func(func),.dis(dis),.c(c),.pcs(pcs),.rwe(rwe),.mwe(mwe),.mm(mm),.aluOP(aluOP),.isimm(isimm),.is20(is20),.isfpc(isfpc),.isfm(isfm),.ispc4(ispc4));
REGS regs1(.clk(clk),.rwe(rwe),.rs1(rs1),.rs2(rs2),.Rdata1(Rdata1),.Rdata2(Rdata2),.rd(rd),.rwdata(rwdata));
ALU alu1(.aluOP(aluOP),.a(a),.b(b),.f(f),.c(c));
IOManger iomanger1(.maddr(IOaddr),.mm(mm),.clk(clk),.we(mwe),.wdata(mwdata),.n(n),.data(mdata),.result(result));
MUX mux1(.pcs(pcs),.addr(addr),. imm12(imm12_exp),.imm20(imm20_exp),.f(f),.next(next));
endmodule
仿真文件:
module sim();
reg [5:0] n=6'b000111;
reg clk = 1'b0;
always #10
clk = ~clk;
reg rst = 1'b1;
top t1(.clk(clk),.rst(rst),.n(n));
initial
#11 rst = 1'b0;
endmodule
最后
以上就是糟糕小懒猪为你收集整理的CPU实验-risc-v37条实验的全部内容,希望文章能够帮你解决CPU实验-risc-v37条实验所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复