计算机组成原理(实验二):简单功能型处理器设计(simple_cpu)

目录

  • 前言
  • 1、接口定义
  • 2、需要实现的指令
    • 1) R-Type
    • 2) REGIMM
    • 3) J-Type
    • 4) I-Type
  • 3、指令译码表
      • 总译码表
      • ALUop译码表
      • Shiftop译码表
      • Write_strb译码表
  • 4、ALU模块&寄存器堆模块&移位器模块
  • 5、代码实现及逻辑框图
  • 6、算法设计思路&信号变化说明
    • 1) R-type运算指令
    • 2) R-Type移位指令
    • 3) R-Type跳转指令
    • 4) R-Type mov指令
    • 5) REGIMM指令
    • 6) J-Type指令
    • 7) I-Type分支指令
    • 8) I-Type运算指令
    • 9) I-Type访存指令
  • 总结


前言

本文将描述基于 MIPS-32 的简单功能型处理器的 Verilog 实现。
本文整理了所有需要实现的 M I P S − 32 MIPS-32 MIPS32 指令,共计 45 45 45 条;在构建单周期 c p u cpu cpu 时,我采用了按指令类别依次实现的方式,将在最后介绍;本文旨在分享我在实验中的想法,作者也是初学者,代码可能存在未知问题,欢迎指正。仅供参考,请勿复用!


1、接口定义

信号名 I/O 说明
rst Input 与处理器工作时钟同步的高电平复位信号
clk Input 处理器工作时钟
PC[31:0] Output 程序计数器, 复位后初值为32’d0
Instruction[31:0] Input 从内存(Memory)中读取至处理器的指令
Address[31:0] Output 数据访存指令使用的内存地址
MemWrite Output 内存访问的写使能信号(高电平有效)
Write_data[31:0] Output 内存写操作数据
Write_strb[3:0] Output 内存写操作字节有效信号(支持32/16/8-bit内存写)Write_strb[i] == 1表示Write_data[8 × (i + 1) - 1 : 8 × i ] 位会被写入内存的对应地址
MemRead Output 内存访问的读使能信号(高电平有效)
Read_data[31:0] Input 从内存中读取的数据

2、需要实现的指令

根据指令手册 The MIPS32 Instruction Set (Volume II) 内的指令

需要实现 45 45 45 个指令:
a d d i u , a d d u , s u b u , a n d , a n d i , n o r , o r , o r i , x o r , x o r i , s l t , s l t i , s l t u , s l t i u , s l l , s l l v , s r a , s r a v , s r l , s r l v , b n e , b e q , b g e z , b g t z , b l e z , b l t z , j , j a l , j r , j a l r , l b , l h , l w , l b u , l h u , l w l , l w r , s b , s h , s w , s w l , s w r , m o v n , m o v z , l u i addiu, addu, subu, and, andi, nor, or, ori, xor, xori, slt, slti, sltu, sltiu, sll, sllv, sra, \newline srav, srl, srlv, bne, beq, bgez, bgtz, blez, bltz, j, jal, jr, jalr, lb, lh, lw, lbu, lhu, lwl, lwr,\newline sb, sh, sw, swl, swr, movn, movz, lui addiu,addu,subu,and,andi,nor,or,ori,xor,xori,slt,slti,sltu,sltiu,sll,sllv,sra,srav,srl,srlv,bne,beq,bgez,bgtz,blez,bltz,j,jal,jr,jalr,lb,lh,lw,lbu,lhu,lwl,lwr,sb,sh,sw,swl,swr,movn,movz,lui

这些指令可以按照其执行的功能进行如下分类

类别 指令
R-Type 运算指令 addu, subu, and, or, xor, nor, slt, sltu
移位指令 sll, sra, srl, sllv, srav, srlv
跳转指令 jr, jalr
mov指令 movz, movn
REGIMM bltz, bgez
J-Type j, jal
I-Type 分支指令 beq, bne, blez, bgtz
计算指令 addiu, lui, andi, ori, xori, slti, sltiu
内存读指令 lb, lh, lw, lbu, lhu, lwl, lwr
内存写指令 sb, sh, sw, swl, swr

下面列出了所有需要实现的指令的 MIPS-32 \textbf{MIPS-32} MIPS-32 定义

1) R-Type

运算指令 opcode(6-bit) rs(5-bit) rt(5-bit) rd(5-bit) shamt(5-bit) func(6-bit)
addu 000000(SPECIAL) rs rt rd 00000 100001
subu 100011
and 100100
or 100101
xor 100110
nor 100111
slt 101010
sltu 101011
sll 00000 sa 000000
sra 000011
srl 000010
sllv rs 00000 000100
srav 000111
srlv 000110
jr 00000 00000 001000
jalr rd 001001
movz rt 001010
movn 001011

R − T y p e : o p c o d e [ 5 : 0 ] = = 6 ’ b 000000 R-Type:opcode[5:0] == 6’b000000 RType:opcode[5:0]==6’b000000
• func[5] == 1’b1:运算指令(ALU控制信号)
• func[5:3] == 3’b000:移位指令(移位器控制信号)
• {func[5:3], func[1]} == 4’b0010:跳转指令(PC变化信号)
• {func[5:3], func[1]} == 4’b0011:mov指令

各指令功能如下:(为了方便描述,使用 [ x ] [x] [x] 代表地址为 x x x 的通用寄存器, { x } \{x\} {x} 表示其存储的值)

指令 func 功能
ADDU 100001 r d ← r s + r t : rd ← rs + rt: rdrs+rt: { r s } \{rs\} {rs} { r t } \{rt\} {rt} 进行加法运算,结果保存到 [ r d ] [rd] [rd] (不进行溢出检查,总是将结果保存到目的寄存器)
SUBU 100011 r d ← r s − r t : rd ← rs - rt: rdrsrt: { r s } \{rs\} {rs} { r t } \{rt\} {rt} 进行减法运算,结果保存到 [ r d ] [rd] [rd] (不进行溢出检查,总是将结果保存到目的寄存器)
AND 100100 r d ← r s   A N D   r t : rd ← rs\ AND\ rt: rdrs AND rt: { r s } \{rs\} {rs} { r t } \{rt\} {rt} 进行逻辑“与”运算,结果保存到 [ r d ] [rd] [rd]
OR 100101 r d ← r s   O R   r t : rd ← rs\ OR\ rt: rdrs OR rt: { r s } \{rs\} {rs} { r t } \{rt\} {rt} 进行逻辑“或”运算,结果保存到 [ r d ] [rd] [rd]
XOR 100110 r d ← r s   X O R   r t : rd ← rs\ XOR\ rt: rdrs XOR rt: { r s } \{rs\} {rs} { r t } \{rt\} {rt} 进行逻辑“异或”运算,结果保存到 [ r d ] [rd] [rd]
NOR 100111 r d ← r s   N O R   r t : rd ← rs\ NOR\ rt: rdrs NOR rt: { r s } \{rs\} {rs} { r t } \{rt\} {rt} 进行逻辑“或非”运算,结果保存到 [ r d ] [rd] [rd]
SLT 101010 r d ← ( r s < r t ) : rd ←(rsrd(rs<rt): { r s } \{rs\} {rs} { r t } \{rt\} {rt} 进行有符号数比较,如果 { r s } \{rs\} {rs} 小于 { r t } \{rt\} {rt},那么将 1 1 1 保存到 [ r d ] [rd] [rd];否则将 0 0 0 保存到 [ r d ] [rd] [rd]
SLTU 101011 r d ← ( r s < r t ) : rd ←(rsrd(rs<rt): { r s } \{rs\} {rs} { r t } \{rt\} {rt} 进行无符号数比较,如果 { r s } \{rs\} {rs} 小于 { r t } \{rt\} {rt},那么将 1 1 1 保存到 [ r d ] [rd] [rd];否则将 0 0 0 保存到 [ r d ] [rd] [rd]
SLL 000000 r d ← r t < < s a ( l o g i c ) : rd ← rt << sa (logic) : rdrt<<sa(logic): { r t } \{rt\} {rt} 左移 s a sa sa 位,空出位置用 0 0 0 填充,结果保存到 [ r d ] [rd] [rd]
SRA 000011 r d ← r t > > s a ( a r i t h m e t i c ) : rd ← rt >> sa(arithmetic): rdrt>>sa(arithmetic): { r t } \{rt\} {rt} 向右移 s a sa sa 位,空出位置用 r t [ 31 ] rt[31] rt[31] 的值填充,结果保存到 [ r d ] [rd] [rd]
SRL 000010 r d ← r t > > s a ( l o g i c ) : rd ← rt >> sa (logic): rdrt>>sa(logic): { r t } \{rt\} {rt} 向右移 s a sa sa 位,空出位置用 0 0 0 填充,结果保存到 [ r d ] [rd] [rd]
SLLV 000100 r d ← r t < < r s [ 4 : 0 ] ( l o g i c ) : rd ← rt << rs[4:0] (logic): rdrt<<rs[4:0](logic): { r t } \{rt\} {rt} 向左移,空出位置用 0 0 0 填充,结果保存到 [ r d ] [rd] [rd];移位位数由 { r s } \{rs\} {rs} 的第 0 − 4   b i t 0-4\ bit 04 bit 确定
SRAV 000111 r d ← r t > > r s [ 4 : 0 ] ( a r i t h m e t i c ) : rd ← rt >> rs[4:0] (arithmetic): rdrt>>rs[4:0](arithmetic): { r t } \{rt\} {rt} 向右移,空出位置用 r t [ 31 ] rt[31] rt[31] 填充,结果保存到 [ r d ] [rd] [rd];移位位数由 { r s } \{rs\} {rs} 的第 0 − 4   b i t 0-4\ bit 04 bit 确定
SRLV 000110 r d ← r t > > r s [ 4 : 0 ] ( l o g i c ) : rd ← rt >> rs[4:0] (logic): rdrt>>rs[4:0](logic): { r t } \{rt\} {rt} 向右移,空出位置用 0 0 0 填充,结果保存到 [ r d ] [rd] [rd];移位位数由 { r s } \{rs\} {rs} 的第 0 − 4   b i t 0-4\ bit 04 bit 确定
JR 001000 p c ← r s : pc ← rs: pcrs: { r s } \{rs\} {rs} 赋给寄存器 P C PC PC,作为新的指令地址
JALR 001001 r d ← r e t u r n   a d d r e s s , p e ← r s : rd ← return\ address,pe ← rs: rdreturn addresspers: { r s } \{rs\} {rs} 赋给寄存器 P C PC PC,作为新的指令地址,同时将跳转指令后面第 2 2 2 条指令的地址作为返回地址保存到 [ r d ] [rd] [rd],如果没有在指令中指明 r d rd rd( r d rd rd 为零),那么默认将返回地址保存到寄存器 31 31 31
MOVZ 001010 i f   r t = 0   t h e n   r d ← r s : if\ rt = 0\ then\ rd ← rs: if rt=0 then rdrs: 如果 { r t } \{rt\} {rt} 为零,将 { r s } \{rs\} {rs} 赋给 { r d } \{rd\} {rd};否则保持 { r d } \{rd\} {rd} 不变
MOVN 001011 i f   r t ≠ 0   t h e n   r d ← r s : if\ rt ≠ 0\ then\ rd ← rs: if rt=0 then rdrs: 如果 { r t } \{rt\} {rt} 不为零,将 { r s } \{rs\} {rs} 赋给 { r d } \{rd\} {rd};否则保持 { r d } \{rd\} {rd} 不变

2) REGIMM

指令 opcode(6-bit) rs(5-bit) REG(5-bit) imm(16-bit)
bltz 000001(REGIMM) rs 00000 offset
bgez 00001

R E G I M M : o p c o d e [ 5 : 0 ] = = 6 ’ b 000001 REGIMM:opcode[5:0] == 6’b000001 REGIMM:opcode[5:0]==6’b000001

各指令功能如下:

转移地址为 o f f s e t offset offset 左移2位,并符号扩展为 32 32 32 位后加上 ( P C + 4 ) (PC+4) (PC+4)的结果。
转移目标地址: { { 14 { o f f s e t [ 15 ] } } ,   ( o f f s e t < < 2 ) ,   ′ 0 0 ′ } + ( p c + 4 ) \{\{14\{offset[15]\}\},\ (offset<< 2),\ '00'\}+(pc+4) {{14{offset[15]}}, (offset<<2), 00}+(pc+4)

指令 REG 功能
BLTZ 00000 i f   r s < 0   t h e n   b r a n c h : if\ rs<0\ then\ branch: if rs<0 then branch: 如果地址为 r s rs rs 的通用寄存器的值小于 0 0 0,那么发生转移
BGEZ 00001 i f   r s ≥ 0   t h e n   b r a n c h : if\ rs≥0\ then\ branch: if rs0 then branch: 如果地址为 r s rs rs 的通用寄存器的值大于等于 0 0 0,那么发生转移

3) J-Type

指令 opcode(6-bit) instr_index(26-bit)
j 000010 instr_index
jal 000011

J − T y p e : o p c o d e [ 5 : 1 ] = = 5 ’ b 00001 J-Type:opcode[5:1] == 5’b00001 JType:opcode[5:1]==5’b00001

各指令功能如下:

指令 opcode 功能
J 000010 p c ← { ( p c + 4 ) [ 31 , 28 ] ,   i n s t r _ i n d e x ,  ‘ 00 ’ } : pc ← \{(pc+4)[31,28],\ instr\_index,\ ‘00’\}: pc{(pc+4)[31,28], instr_index, ‘00’}: 转移到新指令地址,其中新指令地址的低 28 28 28 位是指令中的 i n s t r _ i n d e x instr\_index instr_index 字段左移两位的值,高 4 4 4 位是跳转指令后指令地址的高 4 4 4
JAL 000011 p c ← { ( p c + 4 ) [ 31 , 28 ] ,   i n s t r _ i n d e x ,  ‘ 00 ’ } : pc←\{(pc+4)[31,28],\ instr\_index,\ ‘00’\}: pc{(pc+4)[31,28], instr_index, ‘00’}: 转移到新指令地址,其中新指令地址的低 28 28 28 位是指令中的 i n s t r _ i n d e x instr\_index instr_index 字段左移两位的值,高 4 4 4 位是跳转指令后指令地址的高 4 4 4 位,同时将跳转指令后面第 2 2 2 条指令的地址作为返回地址保存到寄存器 31 31 31

4) I-Type

指令 opcode(6-bit) rs/base(5-bit) rt(5-bit) imm(16-bit)
beq 000100 rs rt offset
bne 000101
blez 000110 00000
bgtz 000111
addiu 001001 rt imm
lui 001111
andi 001100
ori 001101
xori 001110
slti 001010
sltiu 001011
lb 100000 base offset
lh 100001
lw 100011
lbu 100100
lhu 100101
lwl 100010
lwr 100110
sb 101000
sh 101001
sw 101011
swl 101010
swr 101110

I − T y p e : I-Type: IType:
• 分支指令:opcode[5:2] == 4’b0001
• 计算指令:opcode[5:3] == 3’b001
• 内存读指令:opcode[5] && ~opcode[3]
• 内存写指令:opcode[5] && opcode[3]

各指令功能如下:(为了方便描述,使用 [ x ] [x] [x] 代表地址为 x x x 的通用寄存器, { x } \{x\} {x} 表示其存储的值)

转移指令转移的新指令地址为 o f f s e t offset offset 左移 2 2 2 位后进行符号扩展并加上 P C + 4 PC+4 PC+4 后的结果。
转移目标地址: { { 14 { o f f s e t [ 15 ] } } ,   ( o f f s e t < < 2 ) ,   ′ 0 0 ′ } + ( p c + 4 ) \{\{14\{offset[15]\}\},\ (offset<< 2),\ '00'\}+(pc+4) {{14{offset[15]}}, (offset<<2), 00}+(pc+4)
访存指令加载的地址为符号扩展的 i m m i d i a t e + b a s e immidiate + base immidiate+base 地址指示的值。
指定的加载地址 { { 16 { i m m [ 15 ] } } ,   i m m } + { b a s e } \{\{16\{imm[15]\}\},\ imm\} + \{base\} {{16{imm[15]}}, imm}+{base}

指令 opcode 功能
BEQ 000100 i f   r s = r t   t h e n   b r a n c h : if\ rs=rt\ then\ branch: if rs=rt then branch: 如果 { r s } \{rs\} {rs} { r t } \{rt\} {rt} 相等,则发生转移
BNE 000101 i f   r s ≠ r t   t h e n   b r a n c h : if\ rs≠rt\ then\ branch: if rs=rt then branch: 如果 { r s } \{rs\} {rs} 不等于 { r t } \{rt\} {rt},则发生转移
BLEZ 000110 i f   r s ≤ 0   t h e n   b r a n c h : if\ rs≤0\ then\ branch: if rs0 then branch: 如果 { r s } \{rs\} {rs} 小于等于零,则发生转移
BGTZ 000111 i f   r s > 0   t h e n   b r a n c h : if\ rs>0\ then\ branch: if rs>0 then branch: 如果 { r s } \{rs\} {rs} 大于零,则发生转移
ADDIU 001001 r t ← r s + ( s i g n _ e x t e n d e d )   i m m e d i a t e : rt ← rs+(sign\_extended)\ immediate: rtrs+(sign_extended) immediate: { r s } \{rs\} {rs} 与指令中立即数符号扩展为 32 − b i t 32-bit 32bit 后的值进行加法运算,运算结果保存到 [ r t ] [rt] [rt] (不进行溢出检查,总是将结果保存到目的寄存器)
LUI 001111 { r t ← i m m e d i a t e ,   0 ′ b 16 } : \{rt ← immediate,\ 0'b16\}: {rtimmediate, 0b16}: 将指令中的 16 b i t 16bit 16bit 立即数保存到 [ r t ] [rt] [rt] 的高16位, [ r t ] [rt] [rt] 的低 16 16 16 位用 0 0 0 填充
ANDI 001100 r t ← r s   A N D   { 1 6 ′ b 0 ,   i m m e d i a t e } : rt ← rs\ AND\ \{16'b0,\ immediate\}: rtrs AND {16b0, immediate}: { r s } \{rs\} {rs} 与指令中立即数零扩展为 32 − b i t 32-bit 32bit 后的值进行逻辑“与”运算,运算结果保存到 [ r t ] [rt] [rt]
ORI 001101 r t ← r s   O R   { 1 6 ′ b 0 ,   i m m e d i a t e } : rt ← rs\ OR\ \{16'b0,\ immediate\}: rtrs OR {16b0, immediate}: { r s } \{rs\} {rs} 与指令中立即数零扩展为 32 − b i t 32-bit 32bit 后的值进行逻辑“或”运算,运算结果保存到 [ r t ] [rt] [rt]
XORI 001110 r t ← r s   X O R   { 1 6 ′ b 0 ,   i m m e d i a t e } : rt ← rs\ XOR\ \{16'b0,\ immediate\}: rtrs XOR {16b0, immediate}: { r s } \{rs\} {rs} 与指令中立即数零扩展为 32 − b i t 32-bit 32bit 后的值进行逻辑“异或”运算,运算结果保存到 [ r t ] [rt] [rt]
SLTI 001010 r t ← ( r s < { 1 6 ′ b 0 ,   i m m e d i a t e ) } : rt ← (rs < \{16'b0,\ immediate)\}: rt(rs<{16b0, immediate)}: 将指令中立即数零扩展为 32 − b i t 32-bit 32bit 后的值与 { r s } \{rs\} {rs} 进行有符号数比较,如果前者大于后者,那么将 1 1 1 保存到 [ r t ] [rt] [rt];否则将 0 0 0 保存到 [ r t ] [rt] [rt]
SLTIU 001011 r t ← ( r s < { 1 6 ′ b 0 ,   i m m e d i a t e ) } : rt ← (rs < \{16'b0,\ immediate)\}: rt(rs<{16b0, immediate)}: 将指令中立即数零扩展为 32 − b i t 32-bit 32bit 后的值与 { r s } \{rs\} {rs} 进行无符号数比较,如果前者大于后者,那么将 1 1 1 保存到 [ r t ] [rt] [rt];否则将 0 0 0 保存到 [ r t ] [rt] [rt]
LB 100000 r t ← m e m o r y [ b a s e + o f f s e t ] : rt ← memory[base+offset]: rtmemory[base+offset]: 从内存中指定的加载地址处读取 8 − b i t 8-bit 8bit,然后符号扩展至 32 32 32 位,保存到 [ r t ] [rt] [rt]
LH 100001 r t ← m e m o r y [ b a s e + o f f s e t ] : rt ← memory[base+offset]: rtmemory[base+offset]: 从内存中指定的加载地址处读取 16 − b i t 16-bit 16bit,然后符号扩展至 32 32 32 位,保存到 [ r t ] [rt] [rt] (有地址对齐要求,要求加载地址的最低位为 0 0 0)
LW 100011 r t ← m e m o r y [ b a s e + o f f s e t ] : rt ← memory[base+offset]: rtmemory[base+offset]: 从内存中指定的加载地址处读取 32 − b i t 32-bit 32bit,保存到 [ r t ] [rt] [rt]
LBU 100100 r t ← m e m o r y [ b a s e + o f f s e t ] : rt ← memory[base+offset]: rtmemory[base+offset]: 从内存中指定的加载地址处读取 8 − b i t 8-bit 8bit,然后零扩展至 32 32 32 位,保存到 [ r t ] [rt] [rt]
LHU 100101 r t ← m e m o r y [ b a s e + o f f s e t ] : rt ← memory[base+offset]: rtmemory[base+offset]: 从内存中指定的加载地址处读取 16 − b i t 16-bit 16bit,然后零扩展至 32 32 32 位,保存到 [ r t ] [rt] [rt] (有地址对齐要求,要求加载地址的最低位为 0 0 0)
LWL 100010 r t ← r t   M E R G E   m e m o r y [ b a s e + o f f s e t ] : rt ← rt\ MERGE\ memory[base+offset]: rtrt MERGE memory[base+offset]: 从内存中指定的加载地址处,找出该地址所在的存储字(将加载地址的后两位设为 0 0 0),从加载地址开始读取直到该存储字结束,将读取到的值保存到 { r t } \{rt\} {rt} 的首端, { r t } \{rt\} {rt} 的其余 b i t bit bit 保持不变(例如读取到 11111 11111 11111 { r t } \{rt\} {rt} 原来是 22222222 22222222 22222222,则操作后 { r t } \{rt\} {rt} 11111222 11111222 11111222)
LWR 100110 r t ← r t   M E R G E   m e m o r y [ b a s e + o f f s e t ] : rt ← rt\ MERGE\ memory[base+offset]: rtrt MERGE memory[base+offset]: 从内存中指定的加载地址处,找出该地址所在的存储字(将加载地址的后两位设为 0 0 0),从加载地址开始读取直到该存储字结束,将读取到的值零保存到 { r t } \{rt\} {rt} 的尾端, { r t } \{rt\} {rt} 的其余 b i t bit bit 保持不变(例如读取到 11111 11111 11111 { r t } \{rt\} {rt} 原来是 22222222 22222222 22222222,则操作后 { r t } \{rt\} {rt} 22211111 22211111 22211111)
SB 101000 m e m o r y [ b a s e + o f f s e t ] ← r t : memory[base+offset] ← rt: memory[base+offset]rt: { r t } \{rt\} {rt} 的最低字节存储到内存中的指定地址
SH 101001 m e m o r y [ b a s e + o f f s e t ] ← r t : memory[base+offset] ← rt: memory[base+offset]rt: { r t } \{rt\} {rt} 的最低两个字节存储到内存中的指定地址(有地址对齐要求,要求计算出来的存储地址的最低位为 0 0 0)
SW 101011 m e m o r y [ b a s e + o f f s e t ] ← r t : memory[base+offset] ← rt: memory[base+offset]rt: { r t } \{rt\} {rt} 存储到内存中的指定地址(有地址对齐要求,要求计算出来的存储地址的最低位为 0 0 0)
SWL 101010 类比指令LWL,非对齐存储指令,向左存储,将 { r t } \{rt\} {rt} 存储到内存中的指定地址
SWR 101110 类比指令LWR,非对齐存储指令,向右存储,将 { r t } \{rt\} {rt} 存储到内存中的指定地址

3、指令译码表

总译码表

指令类型
寄存器堆读 ALU 内存访问 跳转 寄存器堆写
raddr1 raddr2 A B ALUop Address MemRead MemWrite Write_Data Write_strb 跳转地址 地址更新条件 wen waddr wdata
R-Type运算指令 rs rt rdata1 rdata2 ALUop译码表 - - - - - - 0 1 rd ALU_result
R-Type移位指令 rs rt rdata2(shifter) sa(shifter) Shiftop译码表 - - - - - - 0 1 rd shifter_result
R-Type跳转指令 rs 5'b0 - - - - - - - - rdata1 1 func[0] rd/31 PC+8
R-Type mov指令 rs rt - - - - - - - - - 0 1 rd rdata1
REGIMM rs - rdata1 32'b0 SLT - - - - - {offset[15] (14个), (offset<< 2), '00'}+(pc+4) REG[0] nor Zero 0 - -
J-Type - - - - - - - - - - {(pc+4)[31,28], target, ‘00’} 1 opcode[0] 31 PC+8
I-Type分支指令 rs rt/5'b0 rdata1 rdata2/32'b0 ALUop译码表 - - - - - {offset[15] (14个), (offset<< 2), '00'}+(pc+4) opcode[1] xor opcode[0] xor Zero 0 - -
I-Type运算指令 rs - rdata1 immdiate ALUop译码表 - - - - - - 0 1 rt ALU_result
I-Type访存指令 base rt rdata1 immdiate ALUop译码表 ALU_result opcode[5] & (~opcode[3]) opcode[5] & opcode[3] rdata2 Write_strb译码表 - 0 0 - -

ALUop译码表

指令 opcode func ALUop 具体实现
addu 000000 100001 010 ADD/SUB: func[3:2] == 2'b00; ALUop = {func[1], 2'b10
subu 000000 100011 110
and 000000 100100 000 逻辑运算: func[3:2] == 2'b01; ALUop = {func[1], 1'b0, func[0]}
or 000000 100101 001
xor 000000 100110 100
nor 000000 100111 101
slt 000000 101010 111 比较运算: func[3:2] == 2'b10; ALUop = {~func[0], 2'b11}
addi 001000 - 010 ADD: opcode[2:1] == 2'b00; ALUop = {opcode[1], 2'b10}
addiu 001001
andi 001100 000 逻辑运算: opcode[2] == 1'b1 && opcode[1:0] != 2'b11; ALUop = {opcode[1], 1'b0, opcode[0]}
ori 001101 001
xori 001110 100
lui 001111 - 非运算类指令,需要单独处理
slti 001010 111 比较运算: opcode[2:1] == 2'b01; ALUop = {~opcode[0], 2'b11}
sltiu 001011 011

Shiftop译码表

指令 opcode func Shiftop 具体实现
sll 000000 000000 00 func[5:3] == 3’b000; Shiftop = func[1:0]
sra 000000 000011 11
srl 000000 000010 10
sllv 000000 000100 00
srav 000000 000111 11
srlv 000000 000110 10

Write_strb译码表

指令 opcode Write_strb 具体实现
sb 101000 0001 / 0010 / 0100 / 1000 4'b1000 >> (~ALU_result[1:0])
sh 101001 0011 / 1100 {{2{ALU_result[1]}}, {2{~ALU_result[1]}}}
sw 101011 1111 4'b1111
swl 101010 0111 / 0011 / 0001 {ALU_result[1]&ALU_result[0], ALU_result[1], ALU_result[1]|ALU_result[0], 1'b1}
swr 101110 1110 / 1100 / 1000 {1'b1, (~ALU_result[1]) | (~ALU_result[0]), (~ALU_result[1]), (~ALU_result[1]) & (~ALU_result[0])}

4、ALU模块&寄存器堆模块&移位器模块

以下是ALU代码:

`timescale 10 ns / 1 ns

`define DATA_WIDTH 	32
`define ope_AND		3'b000	//逻辑按位与
`define ope_OR		3'b001	//逻辑按位或
`define ope_XOR		3'b100	//逻辑按位异或
`define ope_NOR		3'b101	//逻辑按位或非
`define ope_ADD		3'b010	//算数加法
`define ope_SUB		3'b110	//算数减法
`define ope_SLT		3'b111	//有符号数整数比较
`define ope_SLTU	3'b011	//无符号数整数比较

module alu(
	input  [`DATA_WIDTH - 1:0]  A,
	input  [`DATA_WIDTH - 1:0]  B,
	input  [              2:0]  ALUop,
	output                      Overflow,
	output                      CarryOut,
	output                      Zero,
	output [`DATA_WIDTH - 1:0]  Result
);
	// TODO: Please add your logic design here
	wire [`DATA_WIDTH - 1:0] ADDSUB_A_B;
	wire CarryOut_origin;

	assign Overflow = (ALUop === `ope_ADD) ? ((A[31]) && (B[31])) && (~ADDSUB_A_B[31]) || ((~A[31]) && (~B[31]) && (ADDSUB_A_B[31]))
					       : ((ALUop === `ope_SUB || ALUop === `ope_SLT) && (B === 32'h80000000)) ? ~A[31]
					       : ((ALUop === `ope_SUB || ALUop === `ope_SLT) && (B != 32'h80000000)) ? ((A[31]) && (~B[31])) && (~ADDSUB_A_B[31]) 
					       	|| ((~A[31]) && (B[31]) && (ADDSUB_A_B[31]))
					       : 1'b0;//进行与、或操作时 Overflow 无定义
	assign {CarryOut_origin, ADDSUB_A_B} = {1'b0, A} + {1'b0, (ALUop === `ope_SUB || ALUop === `ope_SLT) ? ~B : B} + {31'b0, ALUop[2]};
	assign CarryOut = (ALUop === `ope_ADD) ? CarryOut_origin //加法运算的溢出位即为进位
			: (ALUop === `ope_SUB && B != 32'b0) ? ~CarryOut_origin //减法运算如果 B 不是全 0 且没有借位,都会溢出;因此溢出位为 1 代表没有借位
			: 0; //既不是加法又不是减法则赋一个无意义的值;或者进行减法且 B 为全 0 则赋为 0
	assign Zero = (Result === 32'b0) ? 1'b1 : 1'b0;
	assign Result = (ALUop === `ope_AND) ? (A & B)
		      : (ALUop === `ope_OR) ? (A | B)
		      : (ALUop === `ope_XOR) ? (A ^ B)
		      : (ALUop === `ope_NOR) ? (~(A | B))
		      : (ALUop === `ope_ADD || ALUop === `ope_SUB) ? ADDSUB_A_B
		      : (ALUop === `ope_SLT) ? ADDSUB_A_B[31] ^ Overflow
		      : (ALUop === `ope_SLTU) ? ((A < B) ? 1 : 0)
		      : 32'b0;
endmodule

以下是寄存器堆代码:

`timescale 10 ns / 1 ns

`define DATA_WIDTH 32
`define ADDR_WIDTH 5

module reg_file(
	input                       clk,
	input  [`ADDR_WIDTH - 1:0]  waddr,
	input  [`ADDR_WIDTH - 1:0]  raddr1,
	input  [`ADDR_WIDTH - 1:0]  raddr2,
	input                       wen,
	input  [`DATA_WIDTH - 1:0]  wdata,
	output [`DATA_WIDTH - 1:0]  rdata1,
	output [`DATA_WIDTH - 1:0]  rdata2
);

	// TODO: Please add your logic design here
	reg [`DATA_WIDTH - 1:0] rf[`DATA_WIDTH - 1:0];
	
	always@(posedge clk)begin
		if (waddr != 5'd0 && wen)
			rf[waddr] <= wdata;
	end
	assign rdata1 = (raddr1 != 5'd0) ? rf[raddr1] : 32'd0;
	assign rdata2 = (raddr2 != 5'd0) ? rf[raddr2] : 32'd0;
endmodule

以下是移位器代码:

`timescale 10 ns / 1 ns

`define DATA_WIDTH 32

module shifter (
	input  [`DATA_WIDTH - 1:0] A,
	input  [              4:0] B,
	input  [              1:0] Shiftop,
	output [`DATA_WIDTH - 1:0] Result
);
	// TODO: Please add your logic code here
	wire [`DATA_WIDTH - 1:0] signed_shift;

	assign signed_shift[31:0] = ({32{A[31]}} << (6'd32 - {1'b0, B[4:0]})) | (A >> B[4:0]);
	assign Result = (Shiftop === 2'b00) ? A << B
		      : (Shiftop === 2'b11) ? signed_shift
		      : (Shiftop === 2'b10) ? A >> B
		      : 1'b0;
endmodule

5、代码实现及逻辑框图

以下是我完成的的最终代码,仅供参考:(代码已通过仿真测试)

`timescale 10ns / 1ns

`define DATA_WIDTH 32
`define ADDR_WIDTH 5

//	OPCODE:		6-bit
`define SPECIAL		6'b000000
`define REGIMM		6'b000001
`define ADDIU		6'b001001
`define LUI		6'b001111
`define LB		6'b100000
`define LH		6'b100001
`define LBU		6'b100100
`define LHU		6'b100101
`define LWL		6'b100010
`define LWR		6'b100110
`define SB		6'b101000
`define SH		6'b101001
`define SW		6'b101011
`define SWL		6'b101010
`define SWR		6'b101110

//	FUNC:		6-bit
`define JR		6'b001000
`define JALR		6'b001001
`define MOVZ		6'b001010
`define MOVN		6'b001011

module simple_cpu(
	input             		clk,
	input             		rst,

	output reg [`DATA_WIDTH - 1:0]	PC,
	input  [`DATA_WIDTH - 1:0]	Instruction,

	output [`DATA_WIDTH - 1:0]	Address,
	output            		MemWrite,
	output [`DATA_WIDTH - 1:0]	Write_data,
	output [3:0]			Write_strb,

	input  [`DATA_WIDTH - 1:0]	Read_data,
	output            		MemRead
);

	// THESE THREE SIGNALS ARE USED IN OUR TESTBENCH
	// PLEASE DO NOT MODIFY SIGNAL NAMES
	// AND PLEASE USE THEM TO CONNECT PORTS
	// OF YOUR INSTANTIATION OF THE REGISTER FILE MODULE
	wire				RF_wen;
	wire [`ADDR_WIDTH - 1:0]	RF_waddr;
	wire [`DATA_WIDTH - 1:0]	RF_wdata;
	wire [`DATA_WIDTH - 1:0]	RF_rdata1;
	wire [`DATA_WIDTH - 1:0]	RF_rdata2;

	// TODO: PLEASE ADD YOUR CODE BELOW
	wire [5:0]			opcode;
	wire [`ADDR_WIDTH - 1:0]	rs;
	wire [`ADDR_WIDTH - 1:0]	rt;
	wire [`ADDR_WIDTH - 1:0]	rd;
	wire [4:0]			sa;
	wire [5:0]			func;
	wire [`DATA_WIDTH - 1:0]	zero_extend;
	wire [`DATA_WIDTH - 1:0]	signed_extend;
	wire [`DATA_WIDTH - 1:0]	shift_signed_extend;
	wire [2:0]			ALU_control;
	wire [`DATA_WIDTH - 1:0]	ALU_result;
	wire [`DATA_WIDTH - 1:0]	ALU_num1;
	wire [`DATA_WIDTH - 1:0]	ALU_num2;
	wire				Zero;
	wire [4:0]			Shift_num;
	wire [1:0]			Shift_op;
	wire [`DATA_WIDTH - 1:0]	Shift_result;
	wire				Jump;
	wire [`DATA_WIDTH - 1:0]	Jump_addr;
	wire				Branch;
	wire [`DATA_WIDTH - 1:0]	Branch_addr;
	wire [`DATA_WIDTH - 1:0]	load_data;
	wire [7:0]			byte_data;
	wire [15:0]			half_data;
	wire [`DATA_WIDTH - 1:0]	lwl_data;
	wire [`DATA_WIDTH - 1:0]	lwr_data;
	wire [`DATA_WIDTH - 1:0]	PC_4;

	assign	opcode 	= Instruction[31:26];
	assign	rs 	= Instruction[25:21];
	assign	rt 	= Instruction[20:16];
	assign	rd 	= Instruction[15:11];
	assign	sa	= Instruction[10:6];
	assign	func 	= Instruction[5:0];
	assign	zero_extend		= {16'b0, Instruction[15:0]};
	assign	signed_extend		= Instruction[15] ? {{16{1'b1}}, Instruction[15:0]} : {{16{1'b0}}, Instruction[15:0]};
	assign	shift_signed_extend	= Instruction[15] ? {{14{1'b1}}, Instruction[15:0], 2'b00} : {{14{1'b0}}, Instruction[15:0], 2'b00};

	assign 	ALU_control 	= (opcode == `SPECIAL && func[3:2] == 2'b00) ? {func[1], 2'b10}//ADD/SUB: R-Type: 运算指令-ADDU/SUBU
			   	: (opcode == `SPECIAL && func[3:2] == 2'b01) ? {func[1], 1'b0, func[0]}//AND/OR/XOR/NOR: R-Type: 运算指令-AND/OR/XOR/NOR
			   	: (opcode == `SPECIAL && func[3:2] == 2'b10) ? {~func[0], 2'b11}//SLT/SLTU: R-Type: 运算指令-SLT
				: (opcode == `REGIMM || opcode[5:1] == 5'b00011) ? 3'b111//SLT: REGIMM指令/I-Type: 分支指令-BLEZ/BGTZ
				: (opcode[5:1] == 5'b00010) ? 3'b110//SUB: I-Type: 分支指令-BEQ/BNE
				: (opcode[5:3] == 3'b001 && opcode[2:1] == 2'b00) ? {opcode[1], 2'b10}//ADD: I-Type: 计算指令-ADDI/ADDIU
				: (opcode[5:3] == 3'b001 && opcode[2] == 1'b1 && opcode[1:0] != 2'b11) ? {opcode[1], 1'b0, opcode[0]}//AND/OR/XOR: I-Type: 计算指令-ANDI/ORI/XORI
				: (opcode[5:3] == 3'b001 && opcode[2:1] == 2'b01) ? {~opcode[0], 2'b11}//SLT/SLTU: I-Type: 计算指令-SLTI/SLTIU
				: (opcode[5]) ? 3'b010//ADD: I-Type: 访存指令
			   	: 3'bXXX;//NOPE
	assign	ALU_num1	= (opcode[5:1] == 5'b00011) ? 0 : RF_rdata1;//I-Type: 分支指令-BLEZ/BGTZ : 其他指令
	assign	ALU_num2	= (opcode == `REGIMM) ? 32'b0//REGIMM指令
				: (opcode[5:1] == 5'b00011) ? RF_rdata1//I-Type: 分支指令-BLEZ/BGTZ
				: (opcode[5:3] == 3'b001 && opcode != `ADDIU) ? zero_extend//I-Type: 计算指令(除了ADDIU)
				: (opcode[5] == 1 || opcode == `ADDIU) ? signed_extend//I-Type: 访存指令/计算指令-ADDIU
				: RF_rdata2;//其他指令
	assign	Shift_num	= (func[2] == 0) ? sa : RF_rdata1[4:0];
	assign	Shift_op	= (opcode == `SPECIAL && func[5:3] == 3'b000) ? func[1:0] : 2'bXX;

	assign	Jump		= ((opcode == `SPECIAL && {func[5:3], func[1]} == 4'b0010) || opcode[5:1] == 5'b00001) ? 1//R-Type: 跳转指令/J-Type指令
				: 0;
	assign	Jump_addr	= (opcode == `SPECIAL && {func[5:3], func[1]} == 4'b0010) ? {RF_rdata1}//R-Type: 跳转指令
				: {PC_4[31:28], Instruction[25:0], 2'b00};//J-Type指令
	assign	Branch		= ((opcode == `REGIMM && (rt[0]^ALU_result[0]))//REGIMM指令(由于其与分支指令所跳转的地址一致,姑且合并处理,实际上是跳转操作)
				|| (opcode[5:2] == 4'b0001 && opcode[0]^Zero))//I-Type: 分支指令
				? 1 : 0;
	assign	Branch_addr	= shift_signed_extend + PC_4;

	assign	RF_wen		= (opcode == `REGIMM || opcode[5:2] == 4'b0001 || (opcode[5] && opcode[3])) ? 0//REGIMM指令/I-Type: 分支指令/I-Type: 内存写指令
				: (opcode == `SPECIAL && {func[5:3], func[1]} == 4'b0011) ? func[0]^(RF_rdata2 == 32'b0)//R-Type: mov指令
				: (opcode == `SPECIAL && func == `JR) ? 0//R-Type: 跳转指令-JR
				: (opcode[5:1] == 5'b00001) ? opcode[0]//J-Type指令
				: 1;
	assign	RF_waddr	= (opcode[5:3] == 3'b001 || opcode[5] & ((~opcode[3]))) ? rt//I-Type: 计算指令/I-Type: 内存读指令
				: (opcode[5:1] == 5'b00001 || (opcode == `SPECIAL && func == `JALR && rd == 0)) ? 31//J-Type指令/R-Type: 跳转指令-JALR(rd未指定)
				: rd;
	assign	RF_wdata	= (opcode == `SPECIAL && ((func == `MOVZ && RF_rdata2 == 32'b0) || (func == `MOVN && RF_rdata2 != 32'b0))) ? RF_rdata1//R-Type: mov指令
				: (opcode == `LUI) ? {Instruction[15:0], 16'b0}//I-Type: 计算指令-LUI
				: ((opcode == `SPECIAL && func[5] == 1'b1) || (opcode[5:3] == 3'b001)) ? ALU_result//R-Type: 运算指令/I-Type: 计算指令
				: (opcode == `SPECIAL && func[5:3] == 3'b000) ? Shift_result//R-Type: 移位指令
				: ((opcode == `SPECIAL && {func[5:3], func[1]} == 4'b0010) || opcode[5:1] == 5'b00001) ? PC + 8//R-Type: 跳转指令/J-Type指令
				: (opcode[5] && (~opcode[3])) ? load_data//I-Type: 内存读指令
				: 32'bx;

	assign	MemRead		= (opcode[5:3] == 3'b100) ? 1 : 0;//I-Type: 内存读指令
	assign	load_data	= (opcode == `LB) ? (byte_data[7] ? {{24{1'b1}}, byte_data} : {{24{1'b0}}, byte_data})//LB
				: (opcode == `LH) ? (half_data[15] ? {{16{1'b1}}, half_data} : {{16{1'b0}}, half_data})//LH
				: (opcode == `LBU) ? {{24{1'b0}}, byte_data}//LBU
				: (opcode == `LHU) ? {{16{1'b0}}, half_data}//LHU
				: (opcode == `LWL) ? lwl_data//LWL
				: (opcode == `LWR) ? lwr_data//LWR
				: Read_data;//LW
	assign	byte_data	= (ALU_result[1] & ALU_result[0]) ? Read_data[31:24]
				: (ALU_result[1] & ~ALU_result[0]) ? Read_data[23:16]
				: (~ALU_result[1] & ALU_result[0]) ? Read_data[15:8]
				: Read_data[7:0];
	assign	half_data	= (~ALU_result[1] & ~ALU_result[0]) ? Read_data[15:0] : Read_data[31:16];
	assign	lwl_data	= (ALU_result[1] & ALU_result[0]) ? Read_data[31:0]
				: (ALU_result[1] & ~ALU_result[0]) ? {Read_data[23:0], RF_rdata2[7:0]}
				: (~ALU_result[1] & ALU_result[0]) ? {Read_data[15:0], RF_rdata2[15:0]}
				: {Read_data[7:0], RF_rdata2[23:0]};
	assign	lwr_data	= (ALU_result[1] & ALU_result[0]) ? {RF_rdata2[31:8], Read_data[31:24]}
				: (ALU_result[1] & ~ALU_result[0]) ? {RF_rdata2[31:16],Read_data[31:16]}
				: (~ALU_result[1] & ALU_result[0]) ? {RF_rdata2[31:24], Read_data[31:8]}
				: Read_data[31:0];
	assign	Address		= {ALU_result[31:2], 2'b00};
	assign	MemWrite	= (opcode[5:3] == 3'b101) ? 1 : 0;//I-Type: 内存写指令
	assign	Write_data	= (opcode == `SB) ? (Write_strb[3] ? {RF_rdata2[7:0], 24'b0}
						  : Write_strb[2] ? {8'b0, RF_rdata2[7:0], 16'b0}
						  : Write_strb[1] ? {16'b0, RF_rdata2[7:0], 8'b0}
						  : {24'b0, RF_rdata2[7:0]})//SB
				: (opcode == `SH) ? ((Write_strb[3] && Write_strb[2]) ? {RF_rdata2[15:0], 16'b0}
						  : {16'b0, RF_rdata2[15:0]})//SH
				: (opcode == `SWL) ? (Write_strb[3] ? RF_rdata2
						   : Write_strb[2] ? {8'b0, RF_rdata2[31:8]}
						   : Write_strb[1] ? {16'b0, RF_rdata2[31:16]}
						   : {24'b0, RF_rdata2[31:24]})
				: (opcode == `SWR) ? (Write_strb[0] ? RF_rdata2
						   : Write_strb[1] ? {RF_rdata2[23:0], 8'b0}
						   : Write_strb[2] ? {RF_rdata2[15:0], 16'b0}
						   : {RF_rdata2[7:0], 24'b0})
				: RF_rdata2;
	assign	Write_strb	= (opcode[1:0] == 2'b00) ? (4'b1000 >> (~ALU_result[1:0]))//SB
				: (opcode[1:0] == 2'b01) ? {{2{ALU_result[1]}}, {2{~ALU_result[1]}}}//SH
				: (opcode[1:0] == 2'b11) ? 4'b1111//SW
				: (opcode[2:0] == 3'b010) ? {ALU_result[1]&ALU_result[0], ALU_result[1], ALU_result[1]|ALU_result[0], 1'b1}//SWL
				: {1'b1, (~ALU_result[1]) | (~ALU_result[0]), (~ALU_result[1]), (~ALU_result[1]) & (~ALU_result[0])};//SWR

	reg_file reg_file_module(
		.clk(clk),
		.waddr(RF_waddr),
		.raddr1(rs),
		.raddr2(rt),
		.wen(RF_wen),
		.wdata(RF_wdata),
		.rdata1(RF_rdata1),
		.rdata2(RF_rdata2)
	);
	alu alu_module(
		.A(ALU_num1),
		.B(ALU_num2),
		.ALUop(ALU_control),
		.Result(ALU_result),
		.Overflow(),
		.CarryOut(),
		.Zero(Zero)
	);
	shifter shifter_module(
		.A(RF_rdata2),
		.B(Shift_num),
		.Shiftop(Shift_op),
		.Result(Shift_result)
	);

	assign PC_4 	= PC + 4;
	always@(posedge clk) begin
		if (rst) begin 
			PC <= 32'b0;
		end
		else begin
			PC <= Jump ? Jump_addr : (Branch ? Branch_addr : PC_4);
		end
	end
endmodule

逻辑框图如下:(画的不好,请见谅)
计算机组成原理(实验二):简单功能型处理器设计(simple_cpu)_第1张图片

6、算法设计思路&信号变化说明

1) R-type运算指令

从寄存器堆读地址 r s rs rs r t rt rt 读出 R F _ r d a t a 1 RF\_rdata1 RF_rdata1 R F _ r d a t a 2 RF\_rdata2 RF_rdata2,分别作为运算数 A L U _ n u m 1 ALU\_num1 ALU_num1 A L U _ n u m 2 ALU\_num2 ALU_num2 并通过 A L U _ c o n t r o l ALU\_control ALU_control 确定 A L U _ o p ALU\_op ALU_op (确定的方法见ALUop译码表),进行运算,之后把运算结果 R e s u l t Result Result 写入到 r d rd rd,寄存器堆写使能为 1 1 1,写地址为 r d rd rd, 写数据为 R e s u l t Result Result

2) R-Type移位指令

从寄存器堆读地址 r s rs rs r t rt rt 读出 R F _ r d a t a 1 RF\_rdata1 RF_rdata1 R F _ r d a t a 2 RF\_rdata2 RF_rdata2,将 R F _ r d a t a 2 RF\_rdata2 RF_rdata2 作为被移位数,通过 S h i f t _ n u m Shift\_num Shift_num 选择 R F _ r d a t a 1 [ 4 : 0 ] RF\_rdata1[4:0] RF_rdata1[4:0] 或者 s a sa sa 作为移位位数,进行 S h i f t _ o p Shift\_op Shift_op 指示的运算(见 S h i f t o p Shiftop Shiftop 译码表),将结果赋给 S h i f t _ r e s u l t Shift\_result Shift_result

3) R-Type跳转指令

从寄存器堆读地址 r s rs rs 读出 R F _ r d a t a 1 RF\_rdata1 RF_rdata1,并赋值给 P C PC PC。这样的赋值是通过控制信号 J u m p Jump Jump 实现的:如果识别到 R − T y p e R-Type RType 跳转指令,将 J u m p Jump Jump 赋为 1 1 1,并将 R F _ r d a t a 1 RF\_rdata1 RF_rdata1 赋给 J u m p _ a d d r Jump\_addr Jump_addr。对于指令 J A L R JALR JALR,还需要将 P C + 8 PC+8 PC+8 保存到 r d rd rd 指示的位置,此时需要使寄存器堆写使能为 1 1 1,写地址为 r d rd rd,写数据为 P C + 8 PC+8 PC+8,如果没有指明 r d rd rd,即 r d rd rd 0 0 0(这是因为我们不能向零号寄存器写入,故 r d rd rd 0 0 0 即为未指定),写地址为 31 31 31

4) R-Type mov指令

读取 R F _ r d a t a 2 RF\_rdata2 RF_rdata2,并进行判断,如果 o p c o d e [ 0 ]   & &   R F _ r d a t a 2   ! = 3 2 ′ b 0 opcode[0]\ \&\&\ RF\_rdata2\ != 32'b0 opcode[0] && RF_rdata2 !=32b0 (MOVN) 或 ∼ o p c o d e [ 0 ]   & &   R F _ r d a t a 2   = = 3 2 ′ b 0 \sim opcode[0]\ \&\&\ RF\_rdata2\ == 32'b0 opcode[0] && RF_rdata2 ==32b0 (MOVZ),则将写使能置为 1 1 1,写地址为 r d rd rd,写数据为 R F r d a t a 1 RF_rdata1 RFrdata1

5) REGIMM指令

为了将 R F _ r d a t a 1 RF\_rdata1 RF_rdata1 0 0 0 比较,使用 A L U ALU ALU 进行 S L T SLT SLT 运算,让 A L U _ c o n t r o l ALU\_control ALU_control 在读取到REGIMM 指令时给出 A L U _ o p ALU\_op ALU_op S L T SLT SLT,使 A L U _ n u m 2 ALU\_num2 ALU_num2 0 0 0,进行运算,然后判断 R e s u l t Result Result 是否为 0 0 0,得出 B r a n c h Branch Branch 的值。 B r a n c h _ a d d r Branch\_addr Branch_addr 为指定值,由于它是两个信号的和,我将计算 B r a n c h _ a d d r Branch\_addr Branch_addr 的操作交给一个实例化的 A L U ALU ALU 模块,使用 A L U ALU ALU 的加法计算。

6) J-Type指令

利用之前 R − T y p e R-Type RType 跳转指令已经实现的 J u m p Jump Jump 信号,如果读取到 J − T y p e J-Type JType 指令, J u m p Jump Jump 赋为 1 1 1,并使 J u m p _ a d d r Jump\_addr Jump_addr 为指定值。注意 JAL 指令还要将 P C + 8 PC+8 PC+8 存到 31 31 31 号寄存器,寄存器堆写使能为 1 1 1,写地址为 31 31 31,写数据为 P C + 8 PC+8 PC+8

7) I-Type分支指令

BEQ 与 BNE 指令需要比较 R F _ r d a t a 1 RF\_rdata1 RF_rdata1 R F _ r d a t a 2 RF\_rdata2 RF_rdata2,这可以通过 A L U ALU ALU 进行减法,判断 A L U ALU ALU 输出的 Z e r o Zero Zero 的值来实现,转移到指定地址,这个是简单的。需要注意的是,BLEZ 与 BGTZ 指令判断 r s ≤ 0 rs\leq0 rs0 r d > 0 rd > 0 rd>0,这与 A L U ALU ALU S L T SLT SLT 判断的 < < < ≥ \geq 不同,实现时需要将 R F _ r d a t a 1 RF\_rdata1 RF_rdata1 放在 A L U _ n u m 2 ALU\_num2 ALU_num2,将 A L U _ n u m 1 ALU\_num1 ALU_num1 置为 0 0 0,之后只需要判断 Z e r o Zero Zero 即可,这个判断与上面的可以合并为 o p c o d e [ 0 ]   ˆ   Z e r o opcode[0]\ \^{}\ Zero opcode[0] ˆ Zero

8) I-Type运算指令

除了 LUI 指令以外的指令都可以通过 A L U ALU ALU 实现,只需要计算一下 A L U _ n u m 2 ALU\_num2 ALU_num2 即可。LUI 指令要将寄存器堆写使能置为 1 1 1,并将 { i m m ,   1 6 ′ b 0 } \{imm,\ 16'b0\} {imm, 16b0} 写入 r t rt rt 即可。注意 ADDIU 为符号扩展,其它为零扩展。

9) I-Type访存指令

由于这一部分确实不容易归纳,只能一个一个实现,认真阅读 M I P S MIPS MIPS 指令手册,理解每条指令要干什么,不是太难。


总结

为了更好地规划硬件线路,必须要预先了解每一个指令要做的事,做好译码工作。代码是建立在已经构筑好的逻辑框图上的,通过将每一类代码的实现框图进行合并得出总的逻辑框图,之后再根据逻辑框图进行信号定义与线连接,将会高效很多。

你可能感兴趣的:(Verilog,fpga开发)