BUAA-CO P4设计文档
Splitter模块
| Sig | Type | Descript |
|---|---|---|
| Instr[31:0] | Output | 当前指令 |
| opcode | Output | Instr[31:26] |
| rs | Output | Instr[25:21] |
| rt | Output | Instr[20:16] |
| rd | Output | Instr[13:11] |
| shamt | Output | Instr[10:6] |
| func | Output | Instr[5:0] |
| offset/imm | Output | Instr[15:0] |
| base | Output | Instr[25:21] |
Controller模块
| Sig | Type | Descript |
|---|---|---|
| opcode[5:0] | Input | |
| func[5:0] | Input | |
| RegWrite | Output | GRF写使能 |
| RegDst | Output | 选择寄存器rt(0)/rd(1) |
| ALUsrc | Output | ALU选择寄存器(0)/立即数(1) |
| Branch | Output | 跳转指令信号 |
| MemWrite | Output | 内存写使能 |
| MemtoReg | Output | 选择输出 |
| jump | Output | j指令信号 |
| Writesp | Output | 写$sp信号 |
| Jumptosp | Output | jr至$sp信号 |
| EXTOp[1:0] | Output | 位拓展模式信号 |
| ALUOp[2:0] | Output | ALU模式信号 |
opcode与func解析真值表
| func | 100000 | 100010 | null | null | null | null | null | 001000 | null | |
| op | 000000 | 000000 | 001101 | 100011 | 101011 | 000100 | 001111 | 000000 | 000011 | |
| Command | add | sub | ori | lw | sw | beq | lui | jr | jal | |
| RegWrite | 1 | 1 | 1 | 1 | 0 | 0 | 1 | 0 | 0 | |
| RegDst | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
| ALUsrc | 0 | 0 | 1 | 1 | 1 | 0 | 1 | 0 | 0 | |
| Branch | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | |
| MemWrite | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | |
| MemtoReg | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | |
| jump | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | |
| Writesp | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | |
| Jumptosp | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | |
| EXTOp[1:0] | 00 | 00 | 00 | 01 | 01 | 01 | 10 | 00 | 00 | |
| ALUOp[2:0] | 000 | 001 | 010 | 000 | 000 | 001 | 010 | 000 | 000 |
- Controller模块可分为and-logic模块(真值表前三行,用于将opcode与func和指令联系)与or-logic模块(真值表其余部分,用于将指令和控制信号联系)
ALU模块
| ALU模式 | ALUOp[2:0] |
|---|---|
| 加法 | 000 |
| 减法 | 001 |
| 或 | 010 |
| 和 | 011 |
| 左移 | 100 |
| 101 | |
| 110 | |
| 111 |
- 使用3bit选择MUX选择ALU运算结果,为便于日后拓展功能,将ALUOp设置为3位
EXT模块
| EXT模式 | EXTOp[1:0] |
|---|---|
| 零扩展 | 00 |
| 符号扩展 | 01 |
| 移位至高16位 | 10 |
| 11 |
- 零扩展用于在lw/sw/beq指令中将立即数扩展为32位
- 移位至高16位用于lui指令
IFU模块
| Sig | Type | Descript |
|---|---|---|
| clk | Input | 时钟信号 |
| reset | Input | 异步复位信号 |
| Branch | Input | 跳转指令信号 |
| equal | Input | 相等信号 |
| imm[31:0] | Input | 输入立即数 |
| PC | Output | 记录当前指令地址 |
| Instr | Output | 从ROM中Addr处提取指令 |
-
beq = Branch && equalbeq == 0时,PC = PC + 4,beq == 1时,Addr = Addr + 4 + (imm<<2)
-
jump跳转指令jump == 1时,PC = GRF[sp]
-
既然ROM中0地址对应PC中的
0x00003000,且只需要用到12位,只需提取PC中的[11:2]即可作为ROM的取地信号- 不取[31:12]原因:指令地址只可能存在于
0x00003000与0x00003FFF之间 - 不取[1:0]原因:一行指令占据空间为4字节
- 不取[31:12]原因:指令地址只可能存在于
DM模块
| Sig | Type | Descript |
|---|---|---|
| Addr[31:0] | Input | |
| Data[31:0] | Input | |
| WE | Input | RAM写使能信号 |
| clk | Input | 时钟信号 |
| RE | Input | RAM读使能信号 |
| reset | Input | 异步复位信号 |
| MemtoReg | Input | 输出选择 |
| RegData | Output | RAM数据 |
MemtoReg == 0时,将ALU结果写入寄存器MemtoReg == 1时,将内存中数据写入寄存器
测试方案
1 | init: |
思考题
-
阅读下面给出的 DM 的输入示例中(示例 DM 容量为 4KB,即 32bit × 1024字),根据你的理解回答,这个 addr 信号又是从哪里来的?地址信号 addr 位数为什么是 [11:2] 而不是 [9:0] ?
- 来自ALU的输出,其中是ALU计算的基地址+偏移量所确定的内存地址。
- 因为内存地址与实际字存储的关系是四倍(即一个字占用四地址位)
-
思考上述两种控制器设计的译码方式,给出代码示例,并尝试对比各方式的优劣。
-
第一种:
1
2
3
4
5
6
7
8
9
10
11
12
13always @(*) begin
if(add | sub) begin
RegWrite = 1;
RegDst = 1;
end
......
......
if(jal) begin
jump = 1;
Writesp = 1;
end
end- 优势:可读性强,易扩展
- 劣势:代码量大
-
第二种:
1
2
3
4
5
6
7
8
9
10
11
12
13
14assign RegWrite = add | sub | ori | lw | lui | jal;
assign RegDst = add | sub;
assign ALUsrc = ori | lui | lw | sw;
assign Branch = beq;
assign MemWrite = sw;
assign MemtoReg = lw;
assign EXTOp[0] = beq | sw | lw;
assign EXTOp[1] = lui;
assign ALUOp[0] = sub | beq;
assign ALUOp[1] = ori | lui;
assign ALUOp[2] = 0;
assign jump = jal | jr;
assign Writesp = jal;
assign Jumptosp = jr;- 优势:代码量小
- 劣势:可读性稍差,对指令的单独调试比较难追踪
-
-
在相应的部件中,复位信号的设计都是同步复位,这与 P3 中的设计要求不同。请对比同步复位与异步复位这两种方式的 reset 信号与 clk 信号优先级的关系。
- 同步复位:clk优先级更高,clk触发前提下才会检测reset
- 异步复位:clk与reset优先级相同,两者上升沿时都会检测是否需要重置
-
C 语言是一种弱类型程序设计语言。C 语言中不对计算结果溢出进行处理,这意味着 C 语言要求程序员必须很清楚计算结果是否会导致溢出。因此,如果仅仅支持 C 语言,MIPS 指令的所有计算指令均可以忽略溢出。 请说明为什么在忽略溢出的前提下,addi 与 addiu 是等价的,add 与 addu 是等价的。
- addi与addiu,add与addu本身的区别只在于前者是对立即数做符号扩展,后者是对立即数做零扩展。C 语言本身不处理溢出,MIPS 指令也就无需区分这些指令在溢出检测、立即数扩展上的差异,所以 addi 与 addiu、add 与 addu 在忽略溢出时是等价的。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 炊煙雲海。!
评论

![[炽吾生平]初雪记](/img/cover_xue.jpg)