P6 习题分析

wtd指令:

记temp1为GRF[rs]的32种循环移位的和 如: 123 + 231 + 321

temp2为GRF[rt]的32种循环移位的和

if (temp1 > temp2) 则 把1写入rd

else if (temp1 < temp2) 则 把 -1写入rd

else 把0写入rd

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/* 整体分析:在D级实现一个组合逻辑计算出temp1和temp2,进而确定回写内容 */
controller
wire wtd = (opcode_DEin == 6'b0 && func_DEin == 6'b000011) ? 1 : 0;

/* 生成控制信号 */
RegWrite_DEin = (wtd || ...) ? 1 : 0;
RegDst_DEin = (wtd || ...) ? 2'b01 : ... // 写入rd寄存器
/* 生成特判信号 */
wire isWtd_DEin = (wtd) ? 1 : 0;

hazardStall
wire wtd = (opcode_DEin == 6'b0 && func_DEin == 6'b000011) ? 1 : 0;

Tuse_RS = (wtd || ...) ? 0 : ... // 在D级使用rs数据
Tuse_RT = (wtd || ...) ? 0 : ... // 在D级使用rt数据
Tnew_DEin = (wtd || ...) ? 1 : ... // 在D级产生要回写的数据

cauculate( // 计算一个数的循环移位和(不考虑溢出)
input wire [31:0] A,
output wire [31:0] B
)
reg [31:0] ans;
reg [31:0] temp;
integer i;
always@(*) begin
ans = 32'b0;
temp = A;
for (i = 0; i < 32; i = i + 1) begin
temp = {temp[0], temp[31:1]};
ans = ans + temp;
end
end

mips
writeBack_DEin = (isWtd_DEin == 1 && (rs_sum > rt_sum)) ? 32'b1 :
(isWtd_DEin == 1 && (rs_sum < rt_sum)) ? (32'b0 - 32'b1) :
(isWtd_DEin == 1 && (rs_sum = rt_sum)) ? 32'b0 : ...

// 注意修改下游回写,避免呗覆盖
writeBack_EMin = (isWtd_DEout == 1 || ...) ? writeBack_DEout : ...

btd指令:

d = (GRF[rt] + GRF[rs])& 32’hfffffffe

d << 1

无条件跳转到pc + 4 + ( d[29:0] || 00 ) + offset

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/* 该指令是一条I指令 可以将其看作为必然会跳转的beq,只是在beq基础上需要加一段偏移 */
controller
wire btd = (opcode_DEin == 6'b111110) ? 1 : 0;

/* 修改控制信号 */
Branch_DEin = (btd || ...) ? 1 : 0;
EXTOp = (btd || ...) ? 2'b01 : ... // 符号拓展
/* 特判信号 */
isBtd_DEin = (btd) ? 1 : 0;

hazardStall
wire btd = (opcode_DEin == 6'b111110) ? 1 : 0;
Tuse_RS = (btd || ...) ? 1 : 0; // 在D级使用rs
Tuse_RT = (btd || ...) ? 1 : 0; // 在D级使用rt
Tnew_DEin = (btd || ...) ? `minTnew; // 不产生新数据

cmp
assign zero_DEin = (isBtd) ? 1 : 0;

mips
wire [31:0] d = ((A1_DEin + A2_DEin)& 32'hfffffffe) << 1;
wire [31:0] distance = {d[29:0], 2'b0};
assign shift = (isBtd_DEin == 1) ? (distance + immExt_DEin);

lwz指令:

lw一样读出WD,把它的低5位与GRF[rt]的低5位进行异或,其值为X

找到小于等于X的最大质数,记为Y

把WD写入GRF[Y]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// E级
wire stall_E = (isLwz_DEout == 1 && (rs_DEin == 质数 || rt_DEin == 质数)) ? 1 : 0;

// M级
wire stall_M = (isLwz_EMout == 1 && (RegAddr_MWin == rs_DEin || RegAddr_MWin == rt_DEin)) ? 1 : 0;

wire [4:0] xor_ans = WD[4:0] ^ A2[4:0];
wire [4:0] max_z = (xor_ans >= 31) ? 31 :
(xor_ans >= 29) ? 29 :
(xor_ans >= 23) ? 23 :
(xor_ans >= 19) ? 19 :
(xor_ans >= 17) ? 17 :
(xor_ans >= 13) ? 13 :
(xor_ans >= 11) ? 11 :
(xor_ans >= 7) ? 7 :
(xor_ans >= 5) ? 5 :
(xor_ans >= 3) ? 3 :
(xor_ans >= 2) ? 2 : 1;
assign RegAddr_MWin = (isLwz_EMout == 1) ? max_z : ...

lwc指令:

读出WDWD是偶数则写入rt寄存器 , WD是奇数则写入31号寄存器

1
2
3
4
5
6
controller 
assign RegDst = (lwc|| ...) ? 2'b00 : // 默认写入rt寄存器

mips
assign stall_E = (isLwc_E == 1 &s& (rs_D == 31 || rt_D == 31)) ? 1 : 0;
assign stall_M = (isLwc_M == 1 && RegAddr_M == 31 && (rs_D == 31 || rt_D == 31)) ? 1 : 0;

fmultu指令:

R型指令。具体操作为进行一个需要在乘除模块计算3个周期的计算指令,操作细节如下:

首先,对 GPR[rs]GPR[rt] 进行64位无符号乘法,结果记为 prod

prod 高32位为0,则把 prod[63:32] 保存到 HI 寄存器中,把 prod[31:0] 保存到 LO 寄存器中。

否则,我们找到 prod 中最高位1的出现位置 highbit_1prod 中最低位0的出现位置 lowbit_0 (可以证明,这种情况下 prod 中必定存在至少一个1和一个0) 。之后,记 reverse_bithighbit_1-lowbit_0 的绝对值,可以证明 reverse_bit 必定在 0∼63 内。最后,把 prod[reverse_bit] 进行翻转(0变成1,1变成0),将结果的高32位保存到 HI 寄存器中,将结果的低32位保存到 LO 寄存器中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
assign start_DEin = (fmultu) ? 1 : 0;
assign isFmultu_DEin = (fmultu) ? 1 : 0;

mult
reg [63:0] prod;
reg [5:0] highbit_1;
reg [5:0] lowbit_0;
reg [5:0] reverse_bit;
integer i;
always@(*) begin
if (isFmultu_DEout == 1) begin
hold_unsign = {{1'b0}, A} * {{1'b0}, B};
prod = hold_unsign[63:0];
if (prod[63:32] == 32'b0) begin
hi_hold = prod[63:32];
lo_hold = prod[31:0];
end
else begin
for (i = 63; i >= 0; i = i - 1) begin
if (prod[i] == 1) begin
highbit_1 = i;
break;
end
end
for (i = 0; i < 64; i = i + 1) begin
if (prod[i] == 0) begin
lowbit_0 = i;
break;
end
end
reverse_bit = (highbit_1 - lowbit_0 > 0) ? highbit_1 - lowbit_0 : lowbit_0 - highbit_1;
prod[reverse_bit] = !prod[reverse_bit];
hi_hold = prod[63:32];
lo_hold = prod[31:0];
end
end
end

always@(posedge clk) begin
if (isFmultu_DEout == 1) begin
pause <= 3;
end
end

sbc指令:

把GRF[rs]分成31-24,23-16,15-8,7-0四个部分,统计每个部分1的个数。如果GRF[rt]是奇数,则将这四个部分按照升序排序组成一个新的数字,写入rd寄存器;如果GRF[rt]是偶数,则将这四个部分按照降序排序组成一个新的数字写入rd寄存器。(排序是稳定排序)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
module sort(
input wire [31:0] A,
input wire way, // way == 1 升序排列 (1数量多的在高位)
output wire [31:0] B
);
reg [7:0] A[4];
reg [4:0] Num[4];
reg [7:0] holdA;
reg [4:0] holdN;
reg [31:0] B1;
reg [31:0] B2;
integer i;
integer j;

always@(*) begin
A[3] = A[31:24];
A[2] = A[23:16];
A[1] = A[15:8];
A[0] = A[7:0];
Num[3] = A[3][0] + A[3][1] + A[3][2] + A[3][3] + A[3][4] + A[3][5] + A[3][6] + A[3][7];
Num[2] = A[2][0] + A[2][1] + A[2][2] + A[2][3] + A[2][4] + A[2][5] + A[2][6] + A[2][7];
Num[1] = A[1][0] + A[1][1] + A[1][2] + A[1][3] + A[1][4] + A[1][5] + A[1][6] + A[1][7];
Num[0] = A[0][0] + A[0][1] + A[0][2] + A[0][3] + A[0][4] + A[0][5] + A[0][6] + A[0][7];

for (i = 3; i > 0; i = i - 1) begin
for (j = 3; j > 3 - i; j = j - 1) begin
if (Num[j] < Num[j - 1]) begin
holdN = Num[j];
holdA = A[j];
Num[j] = Num[j - 1];
A[j] = A[j - 1];
Num[j - 1] = holdN;
A[j - 1] = holdA;
end
end
end
B1 = {A[3], A[2], A[1], A[0]}; // 升序

for (i = 3; i > 0; i = i - 1) begin
for (j = 3; j > 3 - i; j = j - 1) begin
if (Num[j] > Num[j - 1]) begin
holdN = Num[j];
holdA = A[j];
Num[j] = Num[j - 1];
A[j] = A[j - 1];
Num[j - 1] = holdN;
A[j - 1] = holdA;
end
end
end
B2 = {A[3], A[2], A[1], A[0]}; // 降序

assign B = (way == 1) ? B1 : B2;
end

lwm指令:

按照lw的方式从内存中读出的数记作WD,把WD写入WD - GRF[rt]号寄存器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
controller 
wire lwm = (opcode_DEin == 6'b111110) ? 1 : 0;

/* 修改控制信号 */
RegWrite_DEin = (lwm || ...) ? 1 : 0;
MemRead_DEin = (lwm || ...) ? 1 : 0;
MemtoReg_DEin = (lwm || ...) ? 1 : 0;
word_DEin = (lwm || ...) ? 1 : 0;
EXTOp = (lwm || ...) ? 2'b01 : ... // 符号拓展
/* 特判信号 */
isLwm_DEin = (lwm) ? 1 : 0;

HazardStall
wire lwm = (opcode_DEin == 6'b111110) ? 1 : 0;
Tuse_RS = (lwm || ...) ? 1 : ...;
Tuse_RT = (lwm || ...) ? 2 : ...;
Tnew_DEin = (lwm || ...) ? 3 : ...;

mips
/* E级 */
stall_E = (isLwm_DEout === 1) ? 1 : 0;
/* M级 */
stall_M = (isLwm_EMout === 1 && RegAddr_MWin !== 5'b0 &&(RegAddr_MWin === rs_DEin || RegAddr_WMin === rt_DEin)) ? 1 : 0;
wire [31:0] lwm_sub = WD - A2_MWin;
RegAddr_MWin = (isLwm_EMout === 1) ? lwm_sub[4:0] : RegAddr_EMout;