深圳大学研究生课程论文
基于 VHDL 语言的单周期 MIPS 微处理器设计
MIPS 单周期方案是 MIPS 子集最简单的实现方案,主要设计了 12 个模块和一个顶
层文件,实现的指令包括取字(lw),存字(sw),等值分支(beq),不等值则分支(bne),和
算术逻辑指令 add、sub、and、or、nor、逻辑左移(sll)、逻辑右移(srl)和小于则置位(slt),
立即数指令 ori、andi、addi, 跳转指令(J)共 16 条指令。以下是实现方案的各个模块。
一、 程序计数器(PC)
PC 其实就是一个 D 触发器,当复位信号(reset)来的时候,同时时钟也到了的时候,
把输入(pc_in)给输出(pc_out),复位的第一个输出是从 x’0000’开始,下面是这个模块的
实现代码:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity PC is
port( pc_in :
pc_out :
clk :
reset :
end PC;
in std_logic_vector(31 downto 0);
out std_logic_vector(31 downto 0);
in std_logic;
in std_logic);
architecture Behavioral of PC is
begin
process(clk,reset,pc_in)
begin
if reset='1' then pc_out<="00000000000000000000000000000000";
elsif clk='1' and clk'event
then pc_out <= pc_in;
end if;
end process;
end Behavioral;
二、 指令地址的计算模块
这个模块的功能是计算指令的地址,由于所选的指令原因,所以有三种指令地址来
源,首先是普通指令的递增,即 PC+4,执行完一条指令后跳转到下一条继续执行;第
二种是相等则分支和不等则分支指令,通过 ALU 的输出 Zero 和控制单元的控制信号
(Branch)相与判断是否选择分支目标地址,分支目标地址的计算方式是:PC+4 的值与符
号扩展并左移 2 位后的指令低 16 位的值相加;第三种是跳转指令 J,跳转指令是无条件
的不同于分支指令,32 位的地址的低 28 位来自 26 位立即数字段左移两位所得,高四位
为当前 PC+4 的最高四位(即顺序下条指令地址的 31:28 位)。下面是代码:
library IEEE;
第 1页 共 19页
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity PC_ADDR is
port(
pc_out :
Jump_addr :
Jump,Branch,Zero :
sh_l2 :
pc_in : out std_logic_vector(31 downto 0));
in std_logic_vector(31 downto 0);
in std_logic_vector(25 downto 0);
in std_logic;
in std_logic_vector(31 downto 0);
end PC_ADDR;
--Imm_ext shift left 2
architecture Behavioral of PC_ADDR is
constant N:integer:=1;
begin
process(pc_out,Jump_addr,sh_l2,Jump,Branch,Zero)
variable pcadd_out : std_logic_vector(31 downto 0);
variable Jump_addrout : std_logic_vector(31 downto 0);
variable and_out :
variable add_out :
std_logic;
std_logic_vector(31 downto 0);
--pc+4 out
--pc+4[31-28] & [28-0]
--branch and zero
--pc+4+sh_l2
begin
pcadd_out := pc_out + N;
and_out := Branch and Zero;
--add_out :=pc_out + N + sh_l2;
if Jump = '1' then
end if;
end process;
end Behavioral;
Jump_addrout := pcadd_out(31 downto 28) & Jump_addr(25 downto 0) & "00";
pc_in <= Jump_addrout;
then
elsif
and_out = '1'
add_out := pcadd_out + sh_l2;
pc_in <= add_out;
else
pc_in <= pcadd_out;
三、 指令存储器(Instr_Mem)模块
这个模块是一个指令存储器,在这里面共写了 16 条指令,通过 reset 初始化在指令
存储器里面,输出为指令的各个部分分别输出,即跳转立即数,opcode,funct,rs,rt,
rd,Imm,共有 7 个输出端口。下面是代码:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity InstrMem is
第 2页 共 19页
port( Readaddr : in std_logic_vector(31 downto 0);
Reset : in std_logic;
Instr_j : out std_logic_vector(25 downto 0);
Instr_opcode : out std_logic_vector(5 downto 0);
Instr_rs : out std_logic_vector(4 downto 0);
Instr_rt : out std_logic_vector(4 downto 0);
Instr_rd : out std_logic_vector(4 downto 0);
Instr_funct : out std_logic_vector(5 downto 0);
Instr_imm : out std_logic_vector(15 downto 0));
end InstrMem;
architecture Behavioral of InstrMem is
type RAM is array(0 to 31) of std_logic_vector(31 downto 0);
signal RAMS:RAM:=(others=>(others=>'0'));
signal Instr:std_logic_vector(31 downto 0);
begin
process(Reset,Readaddr,RAMS)
begin
if Reset = '1' then
RAMS(0)<=conv_std_logic_vector(0,6)&conv_std_logic_vector(18,5)&conv_std_logic
_vector(19,5)&conv_std_logic_vector(17,5)&conv_std_logic_vector(0,5)&conv_std_lo
gic_vector(32,6);
--add $s1,$s2,$s3 加指令
RAMS(1)<=conv_std_logic_vector(0,6)&conv_std_logic_vector(18,5)&conv_std_logi
c_vector(19,5)&conv_std_logic_vector(17,5)&conv_std_logic_vector(0,5)&conv_std_l
ogic_vector(34,6);
--sub $s1,$s2,$s3 减指令
RAMS(2)<=conv_std_logic_vector(12,6)&conv_std_logic_vector(18,5)&conv_std_log
ic_vector(17,5)&conv_std_logic_vector(100,16);
--andi $s1,$s2,100 与立即数指令
RAMS(3)<=conv_std_logic_vector(35,6)&conv_std_logic_vector(18,5)&conv_std_log
ic_vector(17,5)&conv_std_logic_vector(100,16);
--lw $s1,100($s2) 取字指令
RAMS(4)<=conv_std_logic_vector(43,6)&conv_std_logic_vector(18,5)&conv_std_log
ic_vector(17,5)&conv_std_logic_vector(100,16);
--sw $s1,100($s2) 存字指令
RAMS(5)<=conv_std_logic_vector(0,6)&conv_std_logic_vector(18,5)&conv_std_logi
c_vector(19,5)&conv_std_logic_vector(17,5)&conv_std_logic_vector(0,5)&conv_std_l
ogic_vector(36,6);
--and $s1,$s2,$s3 与指令
RAMS(6)<=conv_std_logic_vector(0,6)&conv_std_logic_vector(18,5)&conv_std_logi
第 3页 共 19页
c_vector(19,5)&conv_std_logic_vector(17,5)&conv_std_logic_vector(0,5)&conv_std_l
ogic_vector(37,6);
--or $s1,$s2,$s3 或指令
RAMS(7)<=conv_std_logic_vector(0,6)&conv_std_logic_vector(18,5)&conv_std_logi
c_vector(19,5)&conv_std_logic_vector(17,5)&conv_std_logic_vector(0,5)&conv_std_l
ogic_vector(39,6);
--nor $s1,$s2,$s3 或非指令
RAMS(8)<=conv_std_logic_vector(13,6)&conv_std_logic_vector(18,5)&conv_std_log
ic_vector(17,5)&conv_std_logic_vector(100,16);
--ori $s1,$s2,100 或立即数指令
RAMS(9)<=conv_std_logic_vector(0,6)&conv_std_logic_vector(0,5)&conv_std_logic
_vector(18,5)&conv_std_logic_vector(17,5)&conv_std_logic_vector(10,5)&conv_std_l
ogic_vector(0,6);
--sll $s1,$s2,10 逻辑左移指令
RAMS(10)<=conv_std_logic_vector(0,6)&conv_std_logic_vector(0,5)&conv_std_logi
c_vector(18,5)&conv_std_logic_vector(17,5)&conv_std_logic_vector(10,5)&conv_std
_logic_vector(2,6);
--srl $s1,$s2,10 逻辑右移指令
RAMS(11)<=conv_std_logic_vector(4,6)&conv_std_logic_vector(17,5)&conv_std_log
ic_vector(18,5)&conv_std_logic_vector(0,16);
--beq $s1,$s2,0 相等则分支指令
RAMS(12)<=conv_std_logic_vector(5,6)&conv_std_logic_vector(17,5)&conv_std_log
ic_vector(18,5)&conv_std_logic_vector(0,16);
--bne $s1,$s2,0 不等则分支指令
RAMS(13)<=conv_std_logic_vector(0,6)&conv_std_logic_vector(18,5)&conv_std_log
ic_vector(19,5)&conv_std_logic_vector(17,5)&conv_std_logic_vector(0,5)&conv_std_
logic_vector(42,6);
--slt $s1,$s2,$s3 小于则置 1 指令
RAMS(14)<=conv_std_logic_vector(8,6)&conv_std_logic_vector(18,5)&conv_std_log
ic_vector(17,5)&conv_std_logic_vector(100,16);
--addi $s1,$s2,100 加立即数指令
RAMS(15)<=conv_std_logic_vector(2,6)&conv_std_logic_vector(2500,26);
--j 10000
跳转指令
end if;
Instr <= RAMS(conv_integer(Readaddr(4 downto 0)));
第 4页 共 19页
end process;
Instr_j <= Instr(25 downto 0);
Instr_opcode <= Instr(31 downto 26);
Instr_rs <= Instr(25 downto 21);
Instr_rt <= Instr(20 downto 16);
Instr_rd <= Instr(15 downto 11);
Instr_imm <= Instr(15 downto 0);
Instr_funct <= Instr(5 downto 0);
end Behavioral;
四、 控制单元模块(Opcode_Ctrl)
指 令 的 [31-26] 部 分 的 opcode 产 生 一 系 列 的 控 , 其 中
RegDst,Jump,Branch,MemRead,ALUOp,MemWrite,ALUSrc,RegWrite 八个,通过 case 语
句来实现。下面是代码:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity Opcode_Ctrl is
port( Opcode :
in std_logic_vector(5 downto 0);
RegDst,Branch,MemRead,MemWrite,ALUSrc,MemtoReg,Jump,
RegWrite :
ALUOp :
end Opcode_Ctrl;
out std_logic;
out std_logic_vector(2 downto 0));
architecture Behavioral of Opcode_Ctrl is
begin
process(Opcode)
begin
--R
case Opcode is
when "000000" =>
RegDst<='1';ALUSrc<='0';MemtoReg<='0';RegWrite<='1';
MemRead<='0';MemWrite<='0';Branch<='0';ALUOp<="100";Jump<='0';
when "100011" =>
RegDst<='0';ALUSrc<='1';MemtoReg<='1';RegWrite<='1';
MemRead<='1';MemWrite<='0';Branch<='0';ALUOp<="000";Jump<='0';
when "101011" =>
RegDst<='0';ALUSrc<='1';MemtoReg<='1';RegWrite<='0';
MemRead<='0';MemWrite<='1';Branch<='0';ALUOp<="000";Jump<='0';
when "000100" =>
RegDst<='0';ALUSrc<='0';MemtoReg<='0';RegWrite<='0';
MemRead<='0';MemWrite<='0';Branch<='1';ALUOp<="010";Jump<='0';
when "000101" =>
RegDst<='0';ALUSrc<='0';MemtoReg<='0';RegWrite<='0';
--bne
--beq
--lw
--sw
第 5页 共 19页
--J
--ori
MemRead<='0';MemWrite<='0';Branch<='1';ALUOp<="011";Jump<='0';
when "000010" =>
RegDst<='0';ALUSrc<='1';MemtoReg<='0';RegWrite<='0';
MemRead<='0';MemWrite<='0';Branch<='0';ALUOp<="011";Jump<='1';
when "001101" =>
RegDst<='0';ALUSrc<='1';MemtoReg<='0';RegWrite<='1';
MemRead<='0';MemWrite<='0';Branch<='0';ALUOp<="101";Jump<='0';
when "001100" =>
RegDst<='0';ALUSrc<='1';MemtoReg<='0';RegWrite<='1';
MemRead<='0';MemWrite<='0';Branch<='0';ALUOp<="110";Jump<='0';
when "001000" =>
RegDst<='0';ALUSrc<='1';MemtoReg<='0';RegWrite<='1';
MemRead<='0';MemWrite<='0';Branch<='0';ALUOp<="111";Jump<='0';
when others => null ;
end case;
end process;
--andi
--addi
end Behavioral;
五、 多路复用模块(寄存器写端口的来源)
由于不同的指令的目标寄存器地址不同,R 指令的目标寄存器 rd,I 指令的目标寄
存器是 rt,通过 RegDet 控制信号实现目标寄存器的区分。下面是代码:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity DRMUX1 is
port(RegDst :
rt,rd :
DR : out std_logic_vector(4 downto 0));
in std_logic;
in std_logic_vector(4 downto 0);
end DRMUX1;
architecture Behavioral of DRMUX1 is
begin
DR <= rt when RegDst = '0'
else
rd when RegDst = '1';
end Behavioral;
六、寄存器堆(REG)
寄存器堆是一个 RAM 寄存器,里面存放的是 32 位的数据,指令通过 rs,rt,和 rd 字段
给出寄存器号的地址,读出或写入数据 。在寄存器堆里面,当复位信号来的时候,初
始化 17,18,19 三个寄存器为,里面的值分别是 2,3,4。各条指令使用的指令寄存器
都是这三个。下面是代码:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
第 6页 共 19页
entity REG is
port(SR1,SR2,DR : in std_logic_vector(4 downto 0);
CLK,RST : in std_logic;
Reg_In : in std_logic_vector(31 downto 0);
RegWrite : in std_logic;
Readdate1,Readdate2 : out std_logic_vector(31 downto 0));
end REG;
architecture Behavioral of REG is
type RAM is array (31 downto 0) of std_logic_vector(31 downto 0);
signal Regs : RAM :=(others =>(others =>'1'));
begin
--初始化寄存器堆
process(CLK,RST,Reg_In)
begin
if RST='1' then
Regs(17) <= "00000000000000000000000000000010";
Regs(18) <= "00000000000000000000000000000011";
Regs(19) <= "00000000000000000000000000000100";
--初始化 17 号寄存器
--初始化 18 号寄存器
--初始化 19 号寄存器
elsif CLK='1' and CLK'event then
if RegWrite='1' then
Regs(CONV_INTEGER(DR)) <= Reg_In;
end if;
end if;
END process;
Readdate1 <= Regs(CONV_INTEGER(SR1));
Readdate2 <= Regs(CONV_INTEGER(SR2));
end Behavioral;
七、 符号扩展单元,同时对其左移两位(codeext)
这个模块的功能是对指令的 16 位立即数进行符号扩展,扩转时要注意 16 位最高位
是’0’还是’1’,当为’0’ 时高 16 位为 x”000”,当为’1’时高 16 位位 x”ffff”;输出有两个,
一个是扩展后的 32 数据,用于立即数指令,另一个是左移两个,作为分支指令的地址
来源。下面是代码:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
第 7页 共 19页
entity CodeExt is
port(Imm : in std_logic_vector(15 downto 0);
Imm_Ext : inout std_logic_vector(31 downto 0);
out std_logic_vector(31 downto 0));
sh_l2 :
end CodeExt;
--32 位左移 2 位后的输出
architecture Behavioral of CodeExt is
begin
Imm_Ext <= x"0000" & Imm when Imm(15)='0'
else x"FFFF" & Imm;
sh_l2 <= Imm_Ext(29 downto 0) & "00" ;
end Behavioral;
八、 ALU 多路选择模块
这个模块的功能是选择 ALU 的一个输入,这个输入有两个来源,其中一个是立即
数扩转成的 32 位数据,在立即数指令中使用,另外一个是寄存器堆的第二个输出,在 R
类型指令和分支指令中使用,控制信号是 ALUSrc 和指令的 funct 字段。下面是代码:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity ALUMUX2 is
port(Readdate2,Imm_Ext :
ALUSrc :
ALU_InB : out std_logic_vector(31 downto 0));
in std_logic_vector(31 downto 0);
in std_logic;
end ALUMUX2;
architecture Behavioral of ALUMUX2 is
begin
ALU_InB <= Readdate2 when ALUSrc='0'
Imm_Ext when ALUSrc='1';
else
end Behavioral;
九、ALUCtrl 模块
这个模块的功能是由控制信号 ALUOp 实现控制 ALU 操作,不同的指令要求不同
的 ALU 操作,由 Opcode 所得的 ALUOp 控制。下面是代码:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity ALU_Ctrl is
port(
ALUOp :
in std_logic_vector(2 downto 0);
第 8页 共 19页