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


前言

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


1、接口定义

信号名I/O说明
rstInput与处理器工作时钟同步的高电平复位信号
clkInput处理器工作时钟
PC[31:0]Output程序计数器, 复位后初值为32’d0
Instruction[31:0]Input从内存(Memory)中读取至处理器的指令
Address[31:0]Output数据访存指令使用的内存地址
MemWriteOutput内存访问的写使能信号(高电平有效)
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 ] 位会被写入内存的对应地址
MemReadOutput内存访问的读使能信号(高电平有效)
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
REGIMMbltz, bgez
J-Typej, 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)
addu000000(SPECIAL)rsrtrd00000100001
subu100011
and100100
or100101
xor100110
nor100111
slt101010
sltu101011
sll00000sa000000
sra000011
srl000010
sllvrs00000000100
srav000111
srlv000110
jr0000000000001000
jalrrd001001
movzrt001010
movn001011

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功能
ADDU100001 r d ← r s + r t : rd ← rs + rt: rdrs+rt: { r s } \{rs\} {rs} { r t } \{rt\} {rt} 进行加法运算,结果保存到 [ r d ] [rd] [rd] (不进行溢出检查,总是将结果保存到目的寄存器)
SUBU100011 r d ← r s − r t : rd ← rs - rt: rdrsrt: { r s } \{rs\} {rs} { r t } \{rt\} {rt} 进行减法运算,结果保存到 [ r d ] [rd] [rd] (不进行溢出检查,总是将结果保存到目的寄存器)
AND100100 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]
OR100101 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]
XOR100110 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]
NOR100111 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]
SLT101010 r d ← ( r s < r t ) : rd ←(rs<rt): rd(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]
SLTU101011 r d ← ( r s < r t ) : rd ←(rs<rt): rd(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]
SLL000000 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]
SRA000011 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]
SRL000010 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]
SLLV000100 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 确定
SRAV000111 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 确定
SRLV000110 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 确定
JR001000 p c ← r s : pc ← rs: pcrs: { r s } \{rs\} {rs} 赋给寄存器 P C PC PC,作为新的指令地址
JALR001001 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
MOVZ001010 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} 不变
MOVN001011 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)
bltz000001(REGIMM)rs00000offset
bgez00001

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功能
BLTZ00000 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,那么发生转移
BGEZ00001 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)
j000010instr_index
jal000011

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功能
J000010 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
JAL000011 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)
beq000100rsrtoffset
bne000101
blez00011000000
bgtz000111
addiu001001rtimm
lui001111
andi001100
ori001101
xori001110
slti001010
sltiu001011
lb100000baseoffset
lh100001
lw100011
lbu100100
lhu100101
lwl100010
lwr100110
sb101000
sh101001
sw101011
swl101010
swr101110

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功能
BEQ000100 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} 相等,则发生转移
BNE000101 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},则发生转移
BLEZ000110 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} 小于等于零,则发生转移
BGTZ000111 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} 大于零,则发生转移
ADDIU001001 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] (不进行溢出检查,总是将结果保存到目的寄存器)
LUI001111 { 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 填充
ANDI001100 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]
ORI001101 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]
XORI001110 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]
SLTI001010 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]
SLTIU001011 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]
LB100000 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]
LH100001 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)
LW100011 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]
LBU100100 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]
LHU100101 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)
LWL100010 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)
LWR100110 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)
SB101000 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} 的最低字节存储到内存中的指定地址
SH101001 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)
SW101011 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)
SWL101010类比指令LWL,非对齐存储指令,向左存储,将 { r t } \{rt\} {rt} 存储到内存中的指定地址
SWR101110类比指令LWR,非对齐存储指令,向右存储,将 { r t } \{rt\} {rt} 存储到内存中的指定地址

3、指令译码表

总译码表

指令类型
寄存器堆读ALU内存访问跳转寄存器堆写
raddr1raddr2ABALUopAddressMemReadMemWriteWrite_DataWrite_strb跳转地址地址更新条件wenwaddrwdata
R-Type运算指令rsrtrdata1rdata2ALUop译码表------01rdALU_result
R-Type移位指令rsrtrdata2(shifter)sa(shifter)Shiftop译码表------01rdshifter_result
R-Type跳转指令rs5'b0--------rdata11func[0]rd/31PC+8
R-Type mov指令rsrt---------01rdrdata1
REGIMMrs-rdata132'b0SLT-----{offset[15] (14个), (offset<< 2), '00'}+(pc+4)REG[0] nor Zero0--
J-Type----------{(pc+4)[31,28], target, ‘00’}1opcode[0]31PC+8
I-Type分支指令rsrt/5'b0rdata1rdata2/32'b0ALUop译码表-----{offset[15] (14个), (offset<< 2), '00'}+(pc+4)opcode[1] xor opcode[0] xor Zero0--
I-Type运算指令rs-rdata1immdiateALUop译码表------01rtALU_result
I-Type访存指令basertrdata1immdiateALUop译码表ALU_resultopcode[5] & (~opcode[3])opcode[5] & opcode[3]rdata2Write_strb译码表-00--

ALUop译码表

指令opcodefuncALUop具体实现
addu000000100001010ADD/SUB: func[3:2] == 2'b00; ALUop = {func[1], 2'b10
subu000000100011110
and000000100100000逻辑运算: func[3:2] == 2'b01; ALUop = {func[1], 1'b0, func[0]}
or000000100101001
xor000000100110100
nor000000100111101
slt000000101010111比较运算: func[3:2] == 2'b10; ALUop = {~func[0], 2'b11}
addi001000-010ADD: opcode[2:1] == 2'b00; ALUop = {opcode[1], 2'b10}
addiu001001
andi001100000逻辑运算: opcode[2] == 1'b1 && opcode[1:0] != 2'b11; ALUop = {opcode[1], 1'b0, opcode[0]}
ori001101001
xori001110100
lui001111-非运算类指令,需要单独处理
slti001010111比较运算: opcode[2:1] == 2'b01; ALUop = {~opcode[0], 2'b11}
sltiu001011011

Shiftop译码表

指令opcodefuncShiftop具体实现
sll00000000000000func[5:3] == 3’b000; Shiftop = func[1:0]
sra00000000001111
srl00000000001010
sllv00000000010000
srav00000000011111
srlv00000000011010

Write_strb译码表

指令opcodeWrite_strb具体实现
sb1010000001 / 0010 / 0100 / 10004'b1000 >> (~ALU_result[1:0])
sh1010010011 / 1100{{2{ALU_result[1]}}, {2{~ALU_result[1]}}}
sw10101111114'b1111
swl1010100111 / 0011 / 0001{ALU_result[1]&ALU_result[0], ALU_result[1], ALU_result[1]|ALU_result[0], 1'b1}
swr1011101110 / 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

逻辑框图如下:(画的不好,请见谅)
请添加图片描述

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 指令手册,理解每条指令要干什么,不是太难。


总结

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

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值