2022北航计算机组成原理 Project 4


Verilog 语言设计单周期 CPU


设计草稿及模块安排

整体架构

mips

PC
IM
GRF
ALU
EXT
DM

Controlled
MUX


模块安排

mips

管脚名 位数 in/out 功能解释
clk 1 in 系统时钟信号
reset 1 in 复位信号

mips模块是整个系统的主模块,其主要承担整体架构中各分模块的线路连接任务。

PC

管脚名 位数 in/out 功能解释
clk 1 in 时钟信号
reset 1 in 复位信号,置1时pc = 0x00003000
next_pc 32 in 下一条指令的地址
pc 32 out 当前指令的地址

pc是程序执行指令的地址提供者,传入其的next_pc受跳转指令信号的影响。

IM

管脚名 位数 in/out 功能解释
pc 32 in 当前指令的地址
instr 32 out 根据pc取出的指令,注意0x00003000的地址偏移量

IM是指令存储器,读取code.txt文件中的多条32位指令,根据传入的pc取指令。

GRF

管脚名 位数 in/out 功能解释
clk 1 in 系统时钟信号
reset 1 in 复位信号,置1时,32个寄存器存储值归0
RegWrite 1 in 写寄存器使能信号
A1 5 in 需要读取的存储器1的地址
A2 5 in 需要读取的存储器2的地址
A3 5 in 需要写入的存储器的地址
WD 32 in 需要写入寄存器的数据
pc 32 in 当前指令的地址
RD1 32 out 读取的寄存器1中存储的32位数据
RD2 32 out 读取的寄存器2中存储的32位数据

GRF是寄存器文件,具有读写功能。

ALU

管脚名 位数 in/out 功能解释
A 32 in 操作数1
B 32 in 操作数2
ALUCtrl 3 in ALU运算操作选择信号:0–和;1–或;2–加;3–减
ALUResult 32 out 运算结果
ifequal 1 out 操作数1和操作数2相等时置1

ALU为算数运算单元,ALUCtrl指令控制执行何种运算。

EXT

管脚名 位数 in/out 功能解释
imm16 16 in 带扩展的16位立即数
extop 1 in 扩展操作选择信号:0–0扩展;1–符号扩展
imm32 32 out 扩展完毕后的32位立即数

EXT为数据位扩展模块,主要服务于I指令。

DM

管脚名 位数 in/out 功能解释
clk 1 in 系统时钟信号
reset 1 in 复位信号,置1时,数据存储器中数据全部归0
MemRead 1 in 读数据存储器使能信号
MemWrite 1 in 写数据存储器使能信号
pc 32 in 当前指令的地址
MemAddress 32 in 读出/写入数据的地址
dataIn 32 in 写入数据存储器的数据
dataOut 32 out 从数据存储器读出的数据

DM是数据存储器,具有读写功能。

Controller

管脚名 位数 in/out 功能解释
op 6 in 32位指令的26-31位
funct 6 in 32位指令的0-5位
RegDst 2 out 写寄存器地址的选择信号:0–rt;1–rd;2–$ra
ALUSrc 1 out ALU操作数2选择信号:0–RD2;1–imm32
WD_sel 1 out 写入寄存器的数据选择信号:0–ALUResult;1–加载至高位的imm16;2–数据存储器的读出;3–pc+4
ALUCtrl 3 out ALU运算操作选择信号:0–和;1–或;2–加;3–减
RegWrite 1 out 写寄存器使能信号
MemRead 1 out 读数据存储器使能信号
MemWrite 1 out 写数据存储器使能信号
extop 1 out 扩展操作选择信号:0–0扩展;1–符号扩展
branch_beq 1 out beq指令识别信号
branch_j_jal 1 out j,jal指令识别信号
branch_jr 1 out jr指令识别信号

Controller是控制(译码)器,根据 op 和 funct 识别是MIPS指令集中的何指令,并依此生成各模块和通路的控制信号。

MUX

管脚名 位数 in/out 功能解释
rt 5 in 32位指令的16-20位
rd 5 in 32位指令的11-15位
RD2 32 in 寄存器2中存储的数据
imm32 32 in 32位立即数
imm16 16 in 16位立即数
ALUResult 32 in ALU运算结果
dataOut 32 in 数据存储器读出的数据
pc 32 in 当前指令的地址
RegDst 2 in 写寄存器地址(A3_grf)的选择信号:0–rt;1–rd;2–$ra
ALUSrc 1 in ALU操作数2(B_alu)选择信号:0–RD2;1–imm32
WD_sel 1 in 写入寄存器的数据(WD_grf)选择信号:0–ALUResult;1–加载至高位的imm16;2–数据存储器的读出;3–pc+4
pc4 32 in pc+4
pc_beq 32 in beq指令将会跳转到的指令地址
pc_j_jal 32 in j,jal指令将会跳转到的指令地址
ifequal 1 in 来自ALU的判等信号
branch_beq 1 in beq指令识别信号
branch_j_jal 1 in j,jal指令识别信号
branch_jr 1 in jr指令识别信号
A3_grf 5 out 经选择后的写寄存器地址
B_alu 32 out 经选择后的ALU操作数2
WD_grf 32 out 经选择后的存储器写入数据
next_pc 32 out 根据跳转信号选择后的下一条指令地址

MUX是集成的选择模块,根据Controller等模块传入的控制信号和选择数据来选择各模块的某些输入信号。


指令及控制信号

指令名称 op funct RegDst ALUSrc WD_sel ALUCtrl RegWrite MemRead MemWrite extop branch_beq branch_j_jal branch_jr
add 000000 100000 1 0 0 2 1 0 0 1 0 0 0
sub 000000 100010 1 0 0 3 1 0 0 1 0 0 0
jr 000000 001000 0 0 0 2 0 0 0 1 0 0 1
ori 001101 \ 0 1 0 1 1 0 0 0 0 0 0
lw 100011 \ 0 1 2 2 1 1 0 1 0 0 0
sw 101011 \ 0 1 0 2 0 0 1 1 0 0 0
beq 000100 \ 0 0 0 3 0 0 0 1 1 0 0
lui 001111 \ 0 0 1 0 1 0 0 0 0 0 0
jal 000011 \ 2 0 3 0 1 0 0 0 0 1 0

设计思路

由于单个模块的控制已经在各个模块的安排中充分介绍,此思路主要概述如何在顶层模块mips中将单个模块组织起来。

首先应当明确,Controller 主要起到译码作用,MUX 根据Controller输出的译码结果选择控制指令。

而需要被选择的端口在当前支持的指令下有以下4个

  • GRF的写入地址:A3,由RegDst控制
  • GRF的写入数据:WD,由WD_sel控制
  • ALU的操作数2:B,由ALUSrc控制
  • 下一条指令地址:next_pc,由branch_beq ifequal,branch_j_jal,branch_jr联合控制

故MUX的输出只为GRF,ALU,PC提供输入。

而其他的通路值得注意的有

  • GRF的A1连接rs,A2连接rt
  • ALU的A连接GRF的RD1
  • DM的MemAddress连接ALU的ALUResult
  • DM的dataIn连接GRF的RD2

其余的控制指令和数据传输可根据名称对应互联。


测试方案

只要使 CPU 的 IM 读入十六进制汇编程序(存储在code.txt中),运行之后查看其存储器和寄存器中的数据,和 Mars 运行结果比较,就可以判定程序的对错。

###测试程序

  • ori指令

      ori $0, $0, 1
      ori $t1, $t1, 1
      ori $t1, $t1, 0
      ori $t2, $t2, 65535
      ori $t3, $t3, 65534
      ori $t4, $t4, 25779
    
  • lui指令

      lui $t1, 1
      lui $t2, 65535
      lui $t2, 65533
      lui $t3, 42538
    
  • sw指令

      ori $t1, $t1, 1
      lui $t2, 65535
      sw $t1, 0($0)
      sw $t2, 4($0)
      ori $t3, $t3, 28381
      sw $t3, 0($0)
      ori $t4, $t4, 4
      sw $t3, 120($t4)
    
  • lw指令

      ori $t1, $t1, 1
      lui $t2, 65535
      sw $t1, 0($0)
      sw $t2, 4($0)
      ori $t3, $t3, 28381
      ori $t4, $t4, 4
      sw $t3, 120($t4)
      ori $s0, $s0, 8
      lw $s1, 0($0)
      lw $s2, 0($t4)
      lw $s3, 116($s0)
    
  • add指令

      ori $s1, $s1, 1
      lui $s2, 65535
      add $t0, $s1, $s2
      add $t0, $t0, $s2
    
      lui $t1, 65535
      ori $t1, $t1, 65535
      add $s3, $s1, $t1
    
  • sub指令

      lui $t1, 65535
      ori $t1, $t1, 65535
      lui $t2, 65535
      ori $t2, $t2, 60000
      sub $s1, $t1, $t2
    
      ori $t3, 7227
      sub $s1, $s1, $t3
    
  • beq指令

      ori $t0, $t0, 1
      ori $t3, $t3, 2
    
      tag1:
        ori $t1, $t1, 63333
        add $t0, $t0, $t0
        beq $t0, $t3, tag1
    
      ori $s0, $s0, 4
      beq $t0, $s0, tag2
      ori $s0, $s0, 0
    
      tag2:
        lui $s0, 4
        addi $s0, $t0, $s0
      
      beq $s0, $t0, tag3
      ori $s0, $s0, 0
      ori $t0, $t0, 0
    
      tag3:
        nop
    
  • j指令

      ori $t1, $t1, 123
      j tag1
      ori $t1, $t2, 1
      tag1:
      add $t2, $t1, $0
      tag2:
      add $t2, $t2, 1
      j tag2
    
  • jal指令 jr指令

      ori $s0, $s0, 1
      ori $s1, $s1, 13828
      jal func
      
      ori $s0, $s0, 2
      ori $s1, $s1, 3
    
      func:
          add $s0, $s0, $s1
          lui $s1, 123
      jr $ra
    
  • 综合测试

ori $a0,$0,1999 
ori $a1,$a0,111 
lui $a2,12345
lui $a3,0xffff
nop
ori $a3,$a3,0xffff
addu $s0,$a0,$a1 
addu $s1,$a3,$a3
addu $s2,$a3,$s0
beq $s2,$s3,eee
subu $s0,$a0,$s2 
subu $s1,$a3,$a3
eee:
subu $s2,$a3,$a0
subu $s3,$s2,$s1
ori $t0,$0,0x0000
sw $a0,0($t0)
nop
sw $a1,4($t0)
sw $s0,8($t0)
sw $s1,12($t0)
sw $s2,16($t0)
sw $s5,20($t0)
lw $t1,20($t0)
lw $t7,0($t0)
lw $t6,20($t0)
sw $t6,24($t0)
lw $t5,12($t0)
jal end
ori $t0,$t0,1
ori $t1,$t1,1
ori $t2,$t2,2
beq $t0,$t2,eee
lui $t3,1111
jal out
end:
addu $t0,$t0,$t7
jr $ra
out:
addu $t0,$t0,$t3
ori $t2,$t0,0
beq $t0,$t2,qqq
lui $v0,10
qqq:
lui $v0,11
  • 机器码
340407cf
3485006f
3c063039
3c07ffff
00000000
34e7ffff
00858021
00e78821
00f09021
12530002
00928023
00e78823
00e49023
02519823
34080000
ad040000
00000000
ad050004
ad100008
ad11000c
ad120010
ad150014
8d090014
8d0f0000
8d0e0014
ad0e0018
8d0d000c
0c000c22
35080001
35290001
354a0002
110affec
3c0b0457
0c000c24
010f4021
03e00008
010b4021
350a0000
110a0001
3c02000a
3c02000b

思考题解答

阅读下面给出的 DM 的输入示例中(示例 DM 容量为 4KB,即 32bit × 1024字),根据你的理解回答,这个 addr 信号又是从哪里来的?地址信号 addr 位数为什么是 [11:2] 而不是 [9:0] ?
答:
如设计思路中所说,DM的Addr来自ALU的ALUResult,因为现有支持的指令仅lw和sw需访问DM存储器,其地址由ALU模块计算地址地址为rs的寄存器存储的值和符号扩展后的32位立即数之和得到。位数为[11:2]是因为DM中数据按字寻址,而计算得到地址是以字节为一个地址单位的,32位系统下1字为4字节,故取地址除以4即为32位数据的存储地址。

思考上述两种控制器设计的译码方式( 1.指令对应的控制信号如何取值;2.控制信号每种取值所对应的指令),给出代码示例,并尝试对比各方式的优劣。
答:
本设计方案采用的是第1种译码方式(见Controller模块);现给出第2种译码方式的部分示例(以ALUCtrl为例):

wire add,sub,jr,ori,lw,sw,beq,lui,jal;

assign add = (op==6'b000000 && funct==6'b100000) ? 1 : 0;
assign sub = (op==6'b000000 && funct==6'b100010) ? 1 : 0;
assign jr = (op==6'b000000 && funct==6'b001000) ? 1 : 0;
assign ori = (op==6'b001101) ? 1 : 0;
assign lw = (op==6'b100011) ? 1 : 0;
assign sw = (op==6'b101011) ? 1 : 0;
assign beq = (op==6'b000100) ? 1 : 0;
assign lui = (op==6'b001111) ? 1 : 0;
assign jal = (op==6'b000011) ? 1 : 0;

assign ALUCtrl = (add | lw | sw |jr) ? 2 :
                 (sub) ? 3 :
                 (ori) ? 1 : 0;

第1中译码方式在添加指令的时候较为方便,只需添加case中的一种情况,集中地选择控制信号,但指令与控制信号的整体对应关系不易看出,可读性一般。第2种译码方式虽然在修改时需要分散地添加指令识别信号,但写起来十分简洁,可读性较好。

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

C 语言是一种弱类型程序设计语言。C 语言中不对计算结果溢出进行处理,这意味着 C 语言要求程序员必须很清楚计算结果是否会导致溢出。因此,如果仅仅支持 C 语言,MIPS 指令的所有计算指令均可以忽略溢出。 请说明为什么在忽略溢出的前提下,addi 与 addiu 是等价的,add 与 addu 是等价的。提示:阅读《MIPS32® Architecture For Programmers Volume II: The MIPS32® Instruction Set》中相关指令的 Operation 部分 。
答:
根据RTL语言描述:addi、add与addiu、addu的区别在于当出现溢出时,addiu、addu不检查溢出,只取32位结果;addi、add开辟额外一个位的空间来检查溢出,若溢出则报告SignalException(IntegerOverflow)。


文章作者: Argithun
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Argithun !