您的位置:首页 > 理论基础

计算机组成实验-第5章_R指令设计实现

2013-04-09 11:26 393 查看
/*主要问题,result=AopB,如果所有的always都是posedge clk触发,则会出现不同步的问题,因为A和B的值从寄存器取出进行运算得到结果之后,结果需要等到下一个时钟周期才能写入result:
第一个时钟周期的操作是解析指令,将A和B的值从寄存器堆中取出,并且计算得到ALUoper的值。
第二个时钟周期:计算result的值。
这样result会比A和B晚一个时钟周期。
因此,将ALUnit中的always改成*触发,这样:
第一个时钟周期的操作是解析指令,将A和B的值从寄存器堆中取出,并且计算得到ALUoper的值,一旦三个值得到,计算结果会立刻写入result(得益于ALUnit中的always循环没有停顿)。
*/
//住模块代码
module Rtype(clk, rst, instru, Adat, Bdat, result);
input clk;
input rst;
input [31:0] instru;
output[31:0] result, Adat, Bdat;//Adat, Bdat为对应的两个操作数寄存器rs和rt,result对应rd
wire [31:0] result;

wire [31:0] Wdat, Adat, Bdat, ALUout;
wire [2:0] ALUoper;

RegFile s1(clk, instru[25:21], instru[20:16], instru[15:11],result, Adat, Bdat, 1);//生成子模块实例
ALUctr s2(clk, 2'b10,instru[5:0],ALUoper);
ALUnit s3(clk, Adat, Bdat, ALUoper, result, zero);

endmodule
module RegFile(clk, rs, rt, rd, result, A, B, RegWrite);//构建寄存器堆,并存取。
input clk;
input [4:0] rs, rt, rd;
input [31:0] result;
input RegWrite;
output [31:0] A, B;
reg [31:0] A, B;

//下边是对应寄存器堆
reg[31:0] Szero, Sat, Sv0, Sv1, Sa0, Sa1, Sa2, Sa3;//0-7
reg[31:0] St0, St1, St2, St3, St4, St5, St6, St7;//8-15, Temp
reg[31:0] Ss0, Ss1, Ss2, Ss3, Ss4, Ss5, Ss6, Ss7;//16-23, Saved
reg[31:0] St8, St9, Sk0, Sk1, Sgp, Ssp, Sfp, Sra;//24-31

//以下初值仅用于测试
initial begin
Szero = 0; Sat=1; Sv0=2; Sv1=3; Sa0=4; Sa1=5; Sa2=6; Sa3=7;
St0=8; St1=9; St2=10; St3=11; St4=12; St5=13; St6=14; St7=15;
Ss0=16; Ss1=17; Ss2=18; Ss3=19; Ss4=20; Ss5=21; Ss6=22; Ss7=23;
St8=24; St9=25; Sk0=26; Sk1=27; Sgp=28; Ssp=29; Sfp=30; Sra=31;
end

//根据寄存器号取对应寄存器值(rs和rt)
always @(posedge clk) begin
case (rs)
0:A=0; //$zero
1:A=Sat;
2:A=Sv0;
3:A=Sv1;
4:A=Sa0;
5:A=Sa1;
6:A=Sa2;
7:A=Sa3;
8:A=St0;
9:A=St1;
10:A=St2;
11:A=St3;
12:A=St4;
13:A=St5;
14:A=St6;
15:A=St7;
16:A=Ss0;
17:A=Ss1;
18:A=Ss2;
19:A=Ss3;
20:A=Ss4;
21:A=Ss5;
22:A=Ss6;
23:A=Ss7;
24:A=St8;
25:A=St9;
26:A=Sk0;
27:A=Sk1;
28:A=Sgp;
29:A=Ssp;
30:A=Sfp;
31:A=Sra;
endcase

case (rt)
0:B=0;//$zero
1:B=Sat;
2:B=Sv0;
3:B=Sv1;
4:B=Sa0;
5:B=Sa1;
6:B=Sa2;
7:B=Sa3;
8:B=St0;
9:B=St1;
10:B=St2;
11:B=St3;
12:B=St4;
13:B=St5;
14:B=St6;
15:B=St7;
16:B=Ss0;
17:B=Ss1;
18:B=Ss2;
19:B=Ss3;
20:B=Ss4;
21:B=Ss5;
22:B=Ss6;
23:B=Ss7;
24:B=St8;
25:B=St9;
26:B=Sk0;
27:B=Sk1;
28:B=Sgp;
29:B=Ssp;
30:B=Sfp;
31:B=Sra;
endcase

//write reg rd
if (RegWrite == 1)
case (rd)
0:Szero=0;
1:Sat=result;
2:Sv0=result;
3:Sv1=result;
4:Sa0=result;
5:Sa1=result;
6:Sa2=result;
7:Sa3=result;
8:St0=result;
9:St1=result;
10:St2=result;
11:St3=result;
12:St4=result;
13:St5=result;
14:St6=result;
15:St7=result;
16:Ss0=result;
17:Ss1=result;
18:Ss2=result;
19:Ss3=result;
20:Ss4=result;
21:Ss5=result;
22:Ss6=result;
23:Ss7=result;
24:St8=result;
25:St9=result;
26:Sk0=result;
27:Sk1=result;
28:Sgp=result;
29:Ssp=result;
30:Sfp=result;
31:Sra=result;
endcase
end
endmodule
//根据function field的值进行计算
module ALUnit(clk, A, B, ALUoper, result, zero);
input clk;
input [31:0] A, B;
input [2:0] ALUoper;

output zero;
reg zero;
output [31:0] result;
reg [31:0] result;

always @(*) begin/*always @(posedge clk) begin 会有延迟,计算结果不能立刻写入result,也不能立刻写入寄存器堆。*/
case (ALUoper)
3'b000: result = A & B;
3'b001: result = A | B;
3'b010: result = A + B;
3'b110: result = A - B;
3'b111: result = (A<B)?1:0;
default: result = A + B;//Add
endcase
zero = (A==B)?1:0;
end
endmodule
//为什么有些地方always @ (*)会出问题。。

module ALUctr(clk, ALUop, Func, op);
input clk;
input [1:0] ALUop;
input [5:0] Func;
output [2:0] op;
reg[2:0] op;

always @(posedge clk) begin// 如果改成always @(*) begin会出现不同步的问题。
case (ALUop[1])
1'b0:case (ALUop[0])
1'b0:op<=3'b010;
1'b1:op<=3'b110;
endcase
1'b1:case (Func)
6'b100000:op<=3'b010;
6'b100010:op<=3'b110;
6'b100100:op<=3'b000;
6'b100101:op<=3'b001;
6'b101010:op<=3'b111;
endcase
endcase
end
endmodule

//测试代码,可以再仿真中修改数字显示的格式(二进制、十进制等),还可以修改时间窗口的长短。
module test;
reg clk = 1'b0;
reg rst = 1'b0;
reg [31:0] I = 32'b00000000000000000000000000000000;
wire [31:0] A;
wire [31:0] B;
wire [31:0] result;
parameter PERIOD = 20;//时钟周期长短
parameter real DUTY_CYCLE = 0.5;
parameter OFFSET = 0;
initial    // Clock process for clk
begin
#OFFSET;
forever//10ns,clk会翻转一次
begin
clk = 1'b0;
#(PERIOD-(PERIOD*DUTY_CYCLE)) clk = 1'b1;
#(PERIOD*DUTY_CYCLE);
end
end
Rtype UUT (
.clk(clk),
.rst(rst),
.instru(I),
.Adat(A),
.Bdat(B),
.result(result));//将A作为子模块输入,对应子模块里边的Adat
initial begin
// -------------  Current Time:  105ns
#105;
rst = 1'b1;
// -------------------------------------
// -------------  Current Time:  405ns
#300;
I = 32'b00000001101010001000000000100000;
// -------------------------------------
// -------------  Current Time:  1405ns
#1000;
I = 32'b00000001110010011000100000100010;
// -------------------------------------
// -------------  Current Time:  2405ns
#1000;
I = 32'b00000001111010101001000000100100;
// -------------------------------------
// -------------  Current Time:  3405ns
#1000;
I = 32'b00000011000010111001100000100101;
// -------------------------------------
// -------------  Current Time:  4405ns
#1000;
I = 32'b00000011001011001010000000101010;
// -------------------------------------
end

endmodule
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: