计组P4设计文档

P4建议:翻译P3设计即可,注意新加指令

源代码:solor-wind/BUAA_CO (github.com)

设计要求

  • 处理器为 32 位单周期处理器,不考虑延迟槽,应支持的指令集为: add, sub, ori, lw, sw, beq, lui, jal, jr, nop ,其中:

    • nop 为空指令,机器码 0x00000000,不进行任何有效行为(修改寄存器等)。

    • add, sub 按无符号加减法处理(不考虑溢出)。

  • 需要采用模块化层次化设计。顶层文件为 mips.v,有效的驱动信号要求包括且仅包括同步复位信号 reset时钟信号 clk,接口定义如下:

1
2
3
4
module mips(
input clk,
input reset
);

模块规格

顶层设计
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
module mips(
input clk,
input reset
);

//CON
wire [31:0] Instr;
wire [1:0] j_ctrl;//跳转指令,0为正常+4 1为beq 2为jal 3为jr
wire grf_write;//grf写入信号
wire [1:0] grf_reg;//选择grf写入的寄存器
wire [1:0] grf_data;//选择grf写入数据来源
wire [1:0] ALU_op;//运算选择
wire [1:0] ALU_data_op;//运算数选择
wire MemWrite;//数据写入信号
//PC
wire [31:0] j_addr;//PC跳转地址
wire [31:0] pc;//PC
//ALU
wire [31:0] ALU_out;//ALU运算结果
//reg
wire [4:0] RegAddr;//写入的寄存器
wire [31:0] WD;//写入的数据
wire [31:0] RD1;//读出的寄存器数据1
wire [31:0] RD2;//读出的寄存器数据2
//ALU
wire [31:0] b;//运算数2
//DM
wire [31:0] DM_out;//DM读出的数据
//decode
wire [15:0] im_of;
wire [5:0] Func;
wire [4:0] rd;
wire [4:0] rt;
wire [4:0] rs_base;
wire [5:0] Op_code;
wire [25:0] index;
assign im_of=Instr[15:0];
assign Func=Instr[5:0];
assign rd=Instr[15:11];
assign rt=Instr[20:16];
assign rs_base=Instr[25:21];
assign Op_code=Instr[31:26];
assign index=Instr[25:0];


assign j_addr=(j_ctrl==2'b00)?(pc+4):
(j_ctrl==2'b01)?(pc+4+{{14{im_of[15]}},im_of,2'b0})://beq
(j_ctrl==2'b10)?({pc[31:28],index,2'b0})://jal
RD1;//jr
assign RegAddr=(grf_reg==2'b00)?rd:
(grf_reg==2'b01)?rt:
5'b11111;//写入$ra
assign WD=(grf_data==2'b00)?ALU_out:
(grf_data==2'b01)?DM_out://lw
(grf_data==2'b10)?{im_of,{16{1'b0}}}://lui
pc+4;//写入$ra
assign b=(ALU_data_op==0)?RD2:
(ALU_data_op==1)?{{16{1'b0}},im_of}://ori
{{16{im_of[15]}},im_of};//lw,sw

controller con(Instr,j_ctrl,grf_write,grf_reg,grf_data,ALU_op,ALU_data_op,MemWrite,ALU_out);
PC Pc(clk,reset,j_addr,pc);
IM im(pc,Instr);
GRF grf(clk,reset,grf_write,RegAddr,WD,rs_base,rt,RD1,RD2);
ALU alu(ALU_op,RD1,b,ALU_out);
DM dm(clk,reset,MemWrite,ALU_out,RD2,DM_out);

always@(posedge clk)begin
if(grf_write==1&&reset!=1)begin
$display("@%h: $%d <= %h", pc, RegAddr, WD);
end
if(MemWrite==1&&reset!=1)begin
$display("@%h: *%h <= %h", pc, ALU_out, RD2);
end
end
/*
integer fp;
initial begin

fp = $fopen("info.txt","w");
end
*/

endmodule
IFU(取指令单元)
  • 内部包括 PC(程序计数器)、IM(指令存储器)及相关逻辑。

  • PC 用寄存器实现,应具有异步复位功能,复位值为起始地址。

  • 起始地址:0x00003000

  • 地址范围:0x00003000 ~ 0x00006FFF。

  • IM 用 ROM 实现,容量为 4096 × 32bit。

  • IM 实际地址宽度仅为 12 位,需要使用恰当的方法将 PC 中储存的地址同 IM 联系起来。

PC(Moore型状态机)
变量 方向 位宽 解释 来源/去向
clk in 1 时钟信号 顶层输入
rst in 1 同步复位信号 顶层输入
j_addr in 32 跳转指令地址 pc、Instr
addr out 32 下一条指令地址 IM
IM

reg [31:0] IM [0:4095]

变量 方向 位宽 解释 来源/去向
addr in 32 指令地址 j_addr
Instr out 32 指令机器码 很多
GRF(通用寄存器组,也称为寄存器文件、寄存器堆)
  • 用具有写使能的寄存器实现,寄存器总数为 32 个,应具有异步复位功能。

  • 0 号寄存器的值始终保持为 0。其他寄存器初始值(复位后)均为 0,无需专门设置。

变量 方向 位宽 解释 来源/去向
clk in 1 时钟信号 顶层输入
rst in 1 同步复位信号 顶层输入
WE in 1 写使能信号 Control
RegAddr in 5 GRF 5 位写入地址 rd/rt/$ra
WD in 32 GRF 32 位写入数据 ALU/DM/im_of/pc
A1 in 5 读出数据的寄存器编号 rs_base
A2 in 5 读出数据的寄存器编号 rt
RD out 32 GRF 32 位读出数据 ALU
RD2 out 32 GRF 32 位读出数据 ALU
ALU(算术逻辑单元)

?比较按无符号还是有符号?

  • 提供 32 位加、减、或运算及大小比较功能。

  • 加减法按无符号处理(不考虑溢出)。

变量 方向 位宽 解释 来源/去向
op in 2 功能选择 Control
a in 32 操作数1 RD1
b in 32 操作数2 RD2/im_of
out out 32 结果 WD/MemAddr/con
DM(数据存储器)
  • 使用 RAM 实现,容量为 3072 × 32bit,应具有异步复位功能,复位值为 0x00000000。

  • 起始地址:0x00000000

  • 地址范围:0x00000000 ~ 0x00002FFF。

  • RAM 应使用双端口模式,即设置 RAM 的 Data Interface 属性为 Separate load and store ports

reg [31:0] DM [0:3071]

变量 方向 位宽 解释 来源/去向
clk in 1 时钟信号 顶层输入
rst in 1 同步复位信号 顶层输入
MemWrite in 1 DM 写入控制信号 Control
MemAddr in 32 DM 32 位写入地址 ALU
MemData in 32 DM 32 位写入数据 RD2
MemData out 32 DM 32 位输出数据 WD
EXT(扩展单元)
  • 可以使用 Logisim 内置的 Bit Extender。
Controller(控制器)
  • 使用与或门阵列构造控制信号的具体方法见后文叙述。

  • 也可以通过其它方式构造控制信号,同学们可以自行探索。

指令解读
指令 31-26 25-21 20-16 15-11 10-6 5-0 解释
add 000000 rs rt rd 00000 100000 rd=rs+rt
sub 000000 rs rt rd 00000 100010 rd=rs-rt
ori 001101 rs rt im im im rt=rs|im
lw 100011 base rt offset offset offset rt=mem(base+of)
sw 101011 base rt offset offset offset mem(base+of)=rt
beq 000100 rs rt offset offset offset PC+=4+of00?
lui 001111 00000 rt im im im rt=im(0*16)
jal 000011 index index index index index 较为复杂
jr 000000 rs 0 0 0 001000 PC=rs

jal:$31=PC+4,PC=PC[31:28]+index00

控制器
变量 方向 位宽 解释
Instr in 32 指令机器码
ALU_out in 32 比较结果
ctrl out 2 PC,0(beq),1(jal),2(jr)
WE out 1 GRF,写使能信号
GRF_op1 out 2 GRF,控制写入地址来源,0(rd),1(rt),2($ra)
GRF_op2 out 2 GRF,控制写入数据来源,0(ALU),1(DM),2(im_of),3(index)
op out 2 ALU,运算选择0(+),1(-),2(|),3(==)
ALU_op out 2 ALU,控制运算数来源(0,rt,1,0-im,2,sign-of)
MemWrite out 1 DM,写入控制信号

思考题

  1. 阅读下面给出的 DM 的输入示例中(示例 DM 容量为 4KB,即 32bit × 1024字),根据你的理解回答,这个 addr 信号又是从哪里来的?地址信号 addr 位数为什么是 [11:2] 而不是 [9:0] ?

    66.png

    ALU的运算结果;截取高位实现右移2位的效果(lw、sw均为字操作,地址是4的倍数)

  2. 思考上述两种控制器设计的译码方式,给出代码示例,并尝试对比各方式的优劣。

    地方

    指令

指令对应的控制信号:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
assign ctrl=(beq&&ALU_out==0)?1:
(jal)?2:
(jr)?3:0;
assign WE=(add||sub||ori||lw||lui||jal);
assign GRF_op1=(ori||lw||lui)?1://rt
(jal)?2:0;//$ra
assign GRF_op2=(jal)?3:
(lui)?2:
(lw)?1:0;
assign op=(beq)?3:
(ori)?2:
(sub)?1:0;
assign ALU_op=(lw||sw)?2:
(ori||lui)?1:0;
assign MemWrite=(sw);

控制信号每种取值对应的指令:

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
wire add,sub,ori,lw,sw,beq,lui,jal,jr;
assign add=(Op_code==6'b000000&&Func==6'b100000);
assign sub=(Op_code==6'b000000&&Func==6'b100010);
assign ori=(Op_code==6'b001101);
assign lw=(Op_code==6'b100011);
assign sw=(Op_code==6'b101011);
assign beq=(Op_code==6'b000100);
assign lui=(Op_code==6'b001111);
assign jal=(Op_code==6'b000011);
assign jr=(Op_code==6'b000000&&Func==6'b001000);


assign ctrl=(beq&&ALU_out==0)?1:
(jal)?2:
(jr)?3:0;
assign WE=(add||sub||ori||lw||lui||jal);
assign GRF_op1=(ori||lw||lui)?1://rt
(jal)?2:0;//$ra
assign GRF_op2=(jal)?3:
(lui)?2:
(lw)?1:0;
assign op=(beq)?3:
(ori)?2:
(sub)?1:0;
assign ALU_op=(lw||sw)?2:
(ori||lui)?1:0;
assign MemWrite=(sw);

优劣:第一种比较直接,控制信号直接由指令决定,但可读性差

第二种可读性好,但指令条数增多后代码冗余

  1. 在相应的部件中,复位信号的设计都是同步复位,这与 P3 中的设计要求不同。请对比同步复位异步复位这两种方式的 reset 信号与 clk 信号优先级的关系。

    同步复位:clk>reset

    异步复位:reset>clk

  2. C 语言是一种弱类型程序设计语言。C 语言中不对计算结果溢出进行处理,这意味着 C 语言要求程序员必须很清楚计算结果是否会导致溢出。因此,如果仅仅支持 C 语言,MIPS 指令的所有计算指令均可以忽略溢出。 请说明为什么在忽略溢出的前提下,addi 与 addiu 是等价的,add 与 addu 是等价的。提示:阅读《MIPS32® Architecture For Programmers Volume II: The MIPS32® Instruction Set》中相关指令的 Operation 部分。

    与addiu相比,addi将32位扩展为33位并判断是否溢出,但忽略溢出后只关注前32位,因此相当于没拓展,和addiu相同

    add与addu同理

测试方案

机器码转指令的

运行C语言代码(code_instruction.c),1为从文件输入,输出到文件;2为单个指令翻译

自动生成数据点的代码

待开发,目前只有手敲代码(

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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
.data
.space 0x3000
.text
ori $0,$0,0
ori $2,$0,2
ori $3,$0,3
ori $4,$0,4
ori $5,$0,5
ori $6,$0,6
ori $7,$0,7
ori $8,$0,8
ori $9,$0,9
ori $10,$0,10
ori $11,$0,11
ori $12,$0,12
ori $13,$0,13
ori $14,$0,14
ori $15,$0,15
ori $16,$0,16
ori $17,$0,17
ori $18,$0,18
ori $19,$0,19
ori $20,$0,20
ori $21,$0,21
ori $22,$0,22
ori $23,$0,23
ori $24,$0,24
ori $25,$0,25
ori $26,$0,26
ori $27,$0,27
ori $28,$0,28
ori $29,$0,29
ori $30,$0,30
ori $31,$0,0x310c


ori $0,$0,1#$0应始终为0
ori $2,$0,65535
ori $3,$0,0
ori $4,$0,12
lui $5,65535
lui $6,0
lui $7,8
add $8,$5,$2#-1
lui $9,32767
add $9,$9,$2#intmax
add $10,$9,$8
sub $10,$8,$9#-intmax-1
add $10,$0,$10
sub $11,$2,$4#65523
sub $12,$4,$2#-65523
add $13,$11,$12#0
sub $14,$5,$5#0

lui $18,0
ori $18,$18,0x2ffc
sw $10,($18)
sw $11,12280($0)
sw $12,-4($4)#8
lw $15,8($0)#$12,-65533
lw $16,12284($0)#$10,-intmax-1
lw $17,12280($0)#11,65523

loop:
lui $21,0
ori $21,$21,1
add $19,$19,$21
beq $19,$20,loop#$19=21跳出

sub $22,$0,$20#$22=-20
loop2:
beq $22,$20,loop2
add $22,$0,$20
beq $22,$20,end
nop
end:
add $23,$23,$21

loop3:
jr $ra
jal loop3#往前跳
jal loop4#往后跳
loop4:
beq $24,$21,end2
add $24,$0,$21
add $25,$0,$ra
jr $25
end2:
jal end2#原地蹦跶

计组P4设计文档
https://solor-wind.github.io/2024/01/23/计组P4设计文档/
作者
gpf
发布于
2024年1月23日
许可协议