改动
相比P3,需要增加的:
- 自行实现ROM、RAM
- 实例化&端口映射
- 改为同步复位
- 用initial对reg赋初值
- 对P3中集成alu进行拆分:增加
aluControl来进行operand1、operand2的选择 - 对grf的修改
- 现在默认RA1接rs,RA2接rt
- 若需读取二者以外的寄存器,可临时为grf添加
RA3、RD3,为aluControl添加rd3
- DM添加LoadType\SaveType,为lh、sh、lb、sb等指令的添加预留可扩展性
注意项
- case语句要写default
- 用综合的check syntax检查
- verilog默认数字为
十进制32位数:除了明确十进制数,一定带上格式 - 避免任何可能产生锁存器的地方
- 缩减异或:
对于一个 n 位的向量
A[n-1:0],表达式^A在逻辑上等价于:A[n-1] ^ A[n-2] ^ ... ^ A[1] ^ A[0] - 到底是要用
rs还是RsData?- 需要在命名和顶层连线时注意区分。
实例化
1 | // 格式: module_name instance_name ( .port_name(wire_name), ... ); |
可拓展
- dm相关
- 可增加
dmSel模块来模拟MUX对写入dm的地址和数据进行选择 - lb/sb的实现
- 可增加
层次设计
EXT(扩展单元)
- 核心任务 把16位立即数扩展到32位
- 整体设计
能够对立即数进行
零扩展/符号扩展 - 模块规格
信号名 方向 位宽 描述 immOrOffset I 16 待扩展的立即数 EXTop I 1 扩展方式选择信号:
1 - 符号扩展
0 - 零扩展immEXT O 32 扩展后的立即数
aluControl
- 整体设计 为alu选择operand1,operand2
- 模块规格
信号名 方向 位宽 描述 rs I 32 rs value rt I 32 rt value immEXT I 32 扩展后的立即数 shamt I 5 shamt aluControlSel I 3 选择信号
000:rs/rt
001:rs/immoperand1 O 32 operand1 operand2 O 32 operand2
ALU
- 整体设计
- 能够实现多种运算功能,并根据op选择对应功能
op 运算 0000 无符号 op1 + op20001 无符号 op1 - op20010 op1 & op20011 op1 | op20100 op2低16位加载至高位,低位补0
- 能够实现多种运算功能,并根据op选择对应功能
- 模块规格
信号名 方向 位宽 描述 op I 4 选择运算功能 operand1 I 32 operand1 operand2 I 32 operand2 result O 32 运算结果 equal O 1 判断是否相等
NPC
-
核心任务 计算下一周期PC应更新成的值
-
整体设计 - 顺序执行:
NPC = PC + 4- 分支跳转:NPC = (PC + 4) + (SignExtend(offset))- j跳转:NPC = PC31…28||instr_index||00 - jr跳转:NPC = GPR[rs] -
模块规格
信号名 方向 位宽 描述 equal I 1 判断reg rs、rt所存值是否相同 immEXT I 32 拓展后的立即数(offset) instr_index I 26 instr_index NPCop I 3 000:NPC = PC + 4
001:分支跳转
010:j
011:jrrd1OrRs I 32 rs储存的值 pc I 32 当前指令地址 npc O 32 pc更新值
IFU
- 核心任务:根据PC中的地址,从ROM中读出指令输出,同时更新PC
- 整体设计
-
地址转换逻辑:
- 地址偏移:pc - 0x00003000
- 将PC的字节地址转换为ROM的字地址
-
ROM:用1024个[31:0]reg来构建ROM
-
载入数据?
1
2
3initial begin
$readmemh("code.txt", imem);
end
-
- 模块规格
信号名 方向 位宽 描述 reset I 1 同步复位信号 clk I 1 时钟信号 npc I 32 pc更新值 Instruction O 32 指令机器码 pc O 32 当前pc
GRF(通用寄存器组)
-
核心任务:为ALU提供快速的数据源,并接收计算结果
-
整体设计
- 读数据:指令最多需要同时读取
两个不同地址的数据 -两个读端口 - 写数据
-
0 号寄存器的值始终保持为 0。其他寄存器初始值(复位后)均为 0,无需专门设置
- 读数据:指令最多需要同时读取
-
模块规格:
信号名 方向 位宽 描述 reset I 1 异步复位信号 clk I 1 时钟信号 RA1 I 5 读地址1 RA2 I 5 读地址2 WA I 5 写地址 WD I 32 写数据 RegWrite I 1 写使能信号 RD1 O 32 读数据1 RD2 O 32 读数据2 注:这里的“地址”指的是GRF中的第n个reg
DM(数据存储器)
- 核心任务
根据
CPU提供的地址,进行读或写操作。它连接了 CPU 的核心与外部数据存储。 - 整体设计
-
使用
RAM实现,容量为3072 × 32bit,应具有异步复位功能,复位值为0x00000000。 -
起始地址:
0x00000000。地址范围:0x00000000 ~ 0x00002FFF。 -
RAM 应使用
双端口模式,即设置 RAM 的Data Interface属性为Separate load and store ports。
-
- 模块规格
信号名 方向 位宽 描述 Address I 32 读/写地址 WriteData I 32 要写入的数据 MemWrite I 1 写使能信号 MemRead I 1 读使能信号 clk I 1 时钟信号 reset I 1 异步复位信号 PC I 32 当前指令的地址 LoadType I 2 load模式选择信号
2’b00:lw
2’b01:lhSaveType I 2 Save模式选择信号
2’b00:sw
2’b01:shMemData O 32 读出的数据
grfSel
- 核心任务 决定写入grf的地址和数据
- 模块设计
信号名 方向 位宽 描述 RegDst I 3 GRF写回地址选择信号:
001:rt
000:rd
010:rs
011:GPR[31]WDsel I 2 GRF写入数据选择信号:
00:ALU运算结果
01:DM读出的数据(lw)
10:PC + 4rs I 5 rs rt I 5 rt rd I 5 rd ALUresult I 32 ALU运算结果 MemData I 32 DM读出的数据 PC I 32 PC WA O 5 WA WD O 32 WD
instrSplitter
- 核心任务 对指令机器码进行拆分
- 模块设计
信号名 方向 位宽 描述 Instruction I 32 指令 opcode O 6 instr[31:26] rs O 5 instr[25:21] rt O 5 instr[20:16] rd O 5 instr[15:11] shamt O 5 instr[10:6] funct O 6 instr[5:0] instr_index I 26 instr[25:0] immOrOffset I 16 instr[15:0]
Controller
-
核心任务:根据当前正在执行的
指令输出对应控制信号 -
整体设计 解码逻辑 = 和逻辑 + 或逻辑
-
和逻辑:识别
- 将输入的机器码识别为相应指令
-
或逻辑:生成
- 根据输入指令生成对应的控制信号
- 控制信号表;
控制信号\指令 add sub ori lw sw beq lui jal jr RegWrite 1 1 1 1 0 0 1 1 0 aluControlSel 000 000 001 001 001 000 001 000 000 ALUop 0000 0001 0011 0000 0000 0000 0100 0000 0000 MemWrite 0 0 0 0 1 0 0 0 0 MemRead 0 0 0 1 0 0 0 0 0 EXTop 0 0 0 1 1 1 0 0 0 RegDst 000 000 001 001 000 000 001 011 000 WDsel 00 00 00 01 00 00 00 10 00 NPCop 000 000 000 000 000 001 000 010 011
-
-
模块规格
信号名 方向 位宽 描述 opcode I 6 指令[31:26]位 funct I 6 指令[5:0]位 RegWrite O 1 GRF写使能信号 aluControlSel O 3 alu操作数选择信号
000:rs/rt
001:rs/immALUop O 4 ALU运算模式选择信号 MemWrite O 1 DM写使能信号 MemRead O 1 DM读使能信号 EXTop O 1 EXT扩展模式选择信号 RegDst O 3 GRF写回地址选择信号:
001:rt
000:rd
010:rs
011:GPR[31]WDsel O 2 GRF写入数据选择信号:
00:ALU运算结果
01:DM读出的数据(lw)
10:PC + 4NPCop O 3 PC更新模式选择信号:
000:顺序执行
001:beq分支跳转
010:j/jal跳转
011:jr跳转
测试方案
工具
借用Mars_CO.jar进行检查。
使用
- 命令行进入Mars_CO.jar所在目录
- 测试文件也放在这个目录下
- 在命令行运行
1
java -jar Mars_CO.jar test.asm mc CompactLargeText coL1
思考题
-
阅读下面给出的 DM 的输入示例中(示例 DM 容量为 4KB,即 32bit × 1024字),根据你的理解回答,这个 addr 信号又是从哪里来的?地址信号 addr 位数为什么是 [11:2] 而不是 [9:0] ?

- 这个addr由alu给出(alu对
gpr(base)和(sign_ext)offset做加运算) - addr以字节为单位,对应到以字为单位的DM,故应除以4,即取[11:2]
- 这个addr由alu给出(alu对
-
思考上述两种控制器设计的译码方式,给出代码示例,并尝试对比各方式的优劣。
- 记录
指令对应的控制信号如何取值:- 优点:思考流畅,一次模拟一整条指令的运行过程即可;便于调试,找到出错指令对应分支进行检查即可
- 缺点:controll模块繁杂
- 记录
控制信号每种取值所对应的指令:- 优点:每个信号利用一个assign表达式描述即可,代码冗余少;
- 缺点:可读性差,较难找出错误在哪儿
- 记录
-
在相应的部件中,复位信号的设计都是同步复位,这与 P3 中的设计要求不同。请对比同步复位与异步复位这两种方式的 reset 信号与 clk 信号优先级的关系。
- 同步复位:clk优先
- 异步复位:reset优先
-
C 语言是一种弱类型程序设计语言。C 语言中不对计算结果溢出进行处理,这意味着 C 语言要求程序员必须很清楚计算结果是否会导致溢出。因此,如果仅仅支持 C 语言,MIPS 指令的所有计算指令均可以忽略溢出。 请说明为什么在忽略溢出的前提下,addi 与 addiu 是等价的,add 与 addu 是等价的。
-
add和addu执行的加法计算是完全一样的,唯一的区别在于add指令多了一个溢出检测和异常处理的步骤:if temp32 ≠ temp31 then SignalException(IntegerOverflow) else GPR[rd] ← temp31..0 endif故忽略溢出时add与addu等价。
-
addi和addiu同理
-