敬请指正~
主存
指令内存ROM:运行时指令不能改变 只有一个读接口,根据地址返回对应的指令 只读,一般用来存储指令运行前将指令存放到ROM种
数据内存RAM:一个读接口一个写接口,读写不同时进行,故读写接口共用一个地址输入端
ROM:raddr、rdata、CE
数据初始化
reg[31:0]inst_rom[0:1023];
initial //法一:只能仿真,不能综合
begin
$readmemh(“ins.eme”,inst_rom); //h:十六进制,读文件“ins.men"中的数据放到inst_rom
end
/IP核-ROM,IP核:知识产权核,只能用,不能知道怎么实现
深度:多少条指令 宽度:每条指令几位
分号结束,每个数据间逗号分隔
module sim(
);
reg[5:0] addr;
wire[31:0] ins;
insrom ir(addr,ins);
initial
addr = 5'b0;
initial
$monitor($time,,"ins=%h",ins);
endmodule
//3
module rom(
input [31:0] addr,
output [31:0] data
);
reg[31:0] romdata;
always @(*)
case(addr[31:2]) //抛弃后两位地址
4'h0: romdata = 32'h11111111;
4'h1: romdata = 32'h22222222;
4'h2: romdata = 32'h33333333;
4'h3: romdata = 32'h44444444;
default: romdata = 32'h00000000;
endcase
assign data = romdata;
endmodule
PC
PC程序计数器,指向下一条指令的地址。
由于MIPS指令是32bit的,所以下一条指令的地址是PC+4,而不是PC+1。
另外,为了实现跳转,PC必须包含接受新地址的能力。
next_addr addr rst clk
module PC( //顺序执行,不考虑跳转
input rst,
input clk,
output reg [31:0] insAddr
);
always @(posedge clk)
begin
if (rst==1'b0)
insAddr<=32'h0;
else
insAddr<=insAddr+4;
end
endmodule
RAM
addr rdata wdata clk CE WE
addr:为读、写提供地址,共用地址端口
写:WE=1
//rom模块:
module rom(
input [31:0] addr,
output [31:0] data
);
reg[31:0] romdata;
always @(*)
case(addr)
4'h0:romdata=32'h34020002; //编写rom存储内容
4'h4:romdata=32'h8c030020;
4'h8:romdata=32'h34040001;
4'hc:romdata=32'h34050001;
8'h10:romdata=32'h00853020; //16进制10和14需要8位来存储
8'h14:romdata=32'h00052026;
default:romdata=32'h00000000;
endcase
assign data=romdata;
endmodule
//pc模块:
module pc(
input clk,
input rst,
output reg [31:0] insAddr
);
always @(posedge clk)
begin
if(rst==1'b0)
insAddr<=32'h0; //当rst=0时进行初始化,初始指令的地址为0
else
insAddr<=insAddr+4; //由于MIPS指令是32位,所以下一条指令的地址是PC+4
end
endmodule
//仿真程序
module rom_sim(
);
reg clk;
reg rst=1'b1;
wire[31:0] addr;
wire[31:0] data;
//时钟信号仿真
initial
begin
clk=1'b0;
forever
#2 clk=~clk;
end
//pc、rom模块实例化
pc mypc(clk,rst,addr);
rom myrom(addr,data);
initial
begin
#2 rst=1'b0;
#4 rst=1'b1;
end
//监视结果,输出rom存储内容
initial
$monitor($time,,"addr=%h;data=%h",addr,data);
initial
#30 $stop;
endmodule
//top模块:
module top2(
input clk,
input rst,
input [4:0] n,
output [11:0] result
);
wire [31:0] out;
assign result=out[11:0];
fib1 f(clk,rst,n,out);
initial
$monitor($time,,"top:result=%d",result);
endmodule
//alu模块:
module alu(
input [31:0] a,
input [31:0] b,
input [3:0] operation,
output [31:0] f,
output z
);
reg[31:0]result;
always@(*)
begin
case(operation)
4'b0000:result=32'b0;
4'b0001:result=a+b;
4'b0010:result=a-b;
4'b0011:result=a&b;
4'b0100:result=a|b;
4'b0101:result=a^b;
default:result=32'b0;
endcase
end
assign f=result;
assign z=~(|result);
initial
$monitor($time,,"alu:a=%h,b=%h,operation=%b",a,b,operation);
initial
$monitor($time,,"alu:f=%h,z=%b",f,z);
endmodule
//registers模块:
module registers(
input clk,
input oc,
input [4:0] raddr1,
input [4:0] raddr2,
input [4:0] waddr,
input [31:0] wdata,
input we, //使能端,读写信号
output [31:0] rdata1,
output [31:0] rdata2
);
reg [31:0] rdata1;
reg [31:0] rdata2;
reg [31:0] regts[1:31];
//读端口1
always @(*)
begin
if(oc == 1'b1)
begin
rdata1 <= 32'b0;
end
else if(raddr1 == 5'b00000) //$0号寄存器只保存0
begin
rdata1 <= 32'b0;
end
begin
rdata1 <= regts[raddr1];
end
end
//读端口2
always @(*)
begin
if(oc == 1'b1)
begin
rdata2 <= 32'b0;
end
else if(raddr2 == 5'b00000)
begin
rdata2 <= 32'b0;
end
begin
rdata2 <= regts[raddr2];
end
end
always @(posedge clk) //脉冲信号作用下才能写
begin
#1 if((we == 1'b1) &&(waddr != 5'b00000)) //判断使能端是否为1,是否为0号地址,0号寄存器不可写
begin
regts[waddr] <= wdata;
end
end
endmodule
//ram模块:
module ram(
input [31:0] addr,
input [31:0] wdata,
input clk,
input ce,
input we1,
output [31:0] rdata
);
reg [31:0] rdata;
reg [31:0] ram[0:30];
always @(*) //只要有输入就立即输出
begin
if(we1 == 1'b0) //使能端
begin
rdata <= ram[addr];
end
end
always @(posedge clk) //脉冲信号作用下才能写
begin
#1 if(we1 == 1'b1) //判断使能端是否为1
begin
ram[addr] <= wdata;
end
end
endmodule
//fib模块:
module fib1(
input clk,
input rst,
input [4:0] n,
output [31:0] result
);
wire [31:0] a,b,f;
reg [31:0] wdata,wd,ad;
wire [31:0]rd;
wire we = 1'b1;
wire ce,we1;
reg w1;
reg [4:0] ra1,ra2,wa;
reg [31:0] count;
parameter op = 4'b0001; //加法运算
//实例化寄存器
registers myregs(.clk(clk),.oc(~rst),.raddr1(ra1),.raddr2(ra2),.waddr(wa),.wdata(wdata),.we(we),.rdata1(a),.rdata2(b));
//实例化ALU
alu myalu1(a, b, op, f); //a b与rdata1(a),rdata2(b)连接
//实例化RAM
ram myram(.addr(ad), .wdata(wd), .clk(clk), .ce(ce), .we1(w1), .rdata(rd));
assign result = rd;
reg[1:0]status = 2'b00; //状态
always@(posedge clk)
begin
if(rst == 1'b0) //复位信号
begin
status <= 2'b00; //初始化为0
count <= 3; //从3开始算
end else
case(status)
2'b00:
begin
ra1 <= 5'b1;
ra2 <= 5'b10;
wa <= 5'b1; //1号寄存器
wdata <= 32'b1; //1写入1号寄存器
status <= 2'b01; //跳转到下一状态
end
2'b01:
begin
wa <= 5'b10;
wdata <= 32'b1;
status <= 2'b10;
end
2'b10:
begin
wa <= ra2+1;
wdata <= f;
status <= 2'b11;
count <= count + 1;
end
2'b11:
begin
if(count <= n)
begin
ra1 <= ra2; //ra1=ra1+1
ra2 <= wa; //ra2=ra2+1
status <= 2'b10;
end
end
endcase
if(count==n+1) //将结果写入ram零号单元
begin
ad <= 5'b0;
w1 <= 1'b1;
wd<=f;
count <= count + 1;
end
if(count==n+2) //将结果从ram零号单元读出
begin
ad<=5'b0;
w1<=1'b0;
end
end
initial
$monitor($time,,"fib:rst=%d,wdata=%d,count=%d",rst,wdata,count);
initial
$monitor($time,,"fib:result=%d",result);
endmodule
//仿真程序
module fib_sim(
output [11:0] result
);
//时钟信号仿真
parameter clk_period=10;
reg clk;
initial
begin
clk=1'b0;
forever
#(clk_period/2) clk=~clk;
end
reg rst=1'b1;
reg[4:0] n=5'b10000;
top2 t(.clk(clk),.rst(rst),.n(n),.result(result));
initial
begin
#2 rst=1'b0;
#4 rst=1'b1;
end
endmodule