软件:Quartus II
Altera公司的综合性CPLD/FPGA开发软件,原理图、VHDL、VerilogHDL以及AHDL(Altera Hardware 支持Description Language)等多种设计输入形式,内嵌自有的综合器以及仿真器,可以完成从设计输入到硬件配置的完整PLD设计流程。
语言: VHDL(Very-High-Speed Integrated Circuit Hardware Description Language 超高速集成电路硬件描述语言)
一种用于电路设计的高级语言。出现在在80年代的后期,最初是由美国国防部开发出来供美军用来提高设计的可靠性和缩减开发周期的一种使用范围较小的设计语言 。VHDL主要用于描述数字系统的结构,行为,功能和接口。除了含有许多具有硬件特征的语句外,VHDL的语言形式、描述风格以及语法是十分类似于一般的计算机高级语言。
整个系统可划分为控制器、寄存器、ALU、通用寄存器组、数据选择器、相关时序部件及组合逻辑部件等。
整个CPU系统以控制器为中心,负责指令的译码及发出各种相关控制信号。节拍发生器控制着整个系统的时钟信号,系统的相关部件在统一的节拍控制下发挥自己的作用。IR为指令寄存器,负责存储即将执行的下一条指令,AR为地址寄存器,存放被访问存储单元的地址。PC为程序计数器,存放现行指令的地址,具有计数功能。ALU负责处理相关数据运算操作。寄存器组负责存放相关操作数和中间临时变量。多路数据选择器在相关控制信号的作用下将相关数据输入ALU处理。
此处先列举指令,稍后的表格中有功能说明
①单字单操作数指令:DEC,SHL,JR,JRC,JRNZ
②单字双操作数指令:ADD,AND,CMP,MVRR,ADC,LDRR,STRR,LDRR,STRR
③单字无操作数指令:CLC,STC
④双字单操作数指令:JMPA
⑤双字双操作数指令:MVRD
指令的基本执行周期为: 读取指令 -->分析指令–> 执行指令
根据指令的执行周期,将16条指令分为A、B类
完成通用寄存器之间的数据运算或传送
完成一次内存读写操作
在编码的时候以指令操作码的最高2位来区分 A、B组指令,最高两位为”11”则为B组,否则为A组。
在控制器方面我们选用了组合逻辑控制器方案。使用节拍来标记每条指令的执行步骤。由指令而定,在我们的系统种不同的执行步骤只有5个,故使用3位节拍。
组合逻辑控制器主要由4个部件组成:
程序计数器
:保存指令在内存中的地址
指令寄存器
,保存从内存读来的指令内容,在指令执行过程中提供指令本身的主要信息
节拍发生器
,用于标记出每条指令的各执行步骤的相对次序关系
控制逻辑
,它根据指令内容和指令的执行步骤及其他一些条件信号,形成并提供出计算机各部件当前时刻要用到的控制信号
CPU执行指令时,把指令从存储器中取出来。
利用PC
存储指令地址来给出指令地址,从存储器
得到的指令再存储到IR
中,再利用ALU
计算出下一条指令的地址。
在得到了指令字之后,将转入指令译码阶段。
根据不同的指令给出各种控制信号。根据指令从相应的源数据寄存器中取出操作数,为下一步的指令执行做好准备。
指令译码由controller完成。
经过指令译码操作,正在处理的指令需要使用ALU
执行何种操作以及由信号alu_func[2…0]确定下来。
经过bus_mux
,ALU
需要使用的操作数也已经准备好。
在指令执行阶段之后, CPU 指令处理将进入到存储器访问阶段。
在本节设计的CPU 中,通过LDRR、STRR指令来访问存储器。读写由CONTROLLER
给出的wr信号来控制,数据地址为ALU
的计算结果alu_out[7…0]。
完成了指令执行阶段和存储器访问阶段后,进入到结果写回阶段。
要写入的数据为ALU
的计算结果alu_out[7…0]或存储器的数据。寄存器
的使能信号ren_en由CONTROLLER
给出以控制是否执行写入操作。
算术逻辑单元是CPU的执行单元,是所有中央处理器的核心组成部分。在计算机中,ALU是专门执行算术和逻辑运算的数字电路。组合逻辑部件,对两个16位的输入及进位输入Cin可进行由3位控制信号控制。
组合逻辑器件,其输入包括:源寄存器数据,目标寄存器数据,带符号位扩展的偏移地址,PC,以及从内存读取的立即数、跳转地址等数据。在3位控制信号的控制下它进行ALU 模块A、B端输入的选择
组合逻辑器件,用于产生ALU的进位输入Cin,受两位控制信号SCI的选择控制,输入为标志寄存的输出FLAG_C
时序逻辑部件,带有清零端RESET,输出只在时钟正跳变时发生变化;接收ALU的标志位输出,在控制信号SST的控制下输出实际需要的标志位
组合逻辑器件,将8位的OFFSET(来自指令的低8位)带符号位扩展到16位
时序逻辑器件,16位寄存器,在控制信号pc_en的控制下可接收ALU的运算结果(高电平接收,否则保持不变)。输出送往地址寄存器(读取指令内容)以及数据选择器(进行自增运算)。
都是16位的寄存器,地址寄存器用于存放要读写的内存地址单元的地址,输出送往地址总线,输入可能为PC内容,也可能为ALU的输出(对读写内存指令);指令寄存器存放当前执行指令的内容,它的输入来自从内存读取的指令和数据,输出送往控制逻辑。
本实验中的寄存器都为16位,带有清零端和使能端,实际上在写VHDL程序时,通用寄存器以及AR、IR、PC使用的都是同一个模板。按照我们的设计,通用寄存器共有16个,由指令的低8位的全部或其中的高4位或低4位来从寄存器组中选择源寄存器和目的寄存器。安排寄存器选择器件reg_mux,为组合逻辑器件,用于输出选定寄存器的内容。另外,由控制逻辑给出1位控制信号reg_en,控制是否对选中寄存器进行写操作,也须由寄存器选择器件给出对特定寄存器的写使能信号。
时序逻辑器件,作用是用多位触发器的输出信号的不同组合状态,来标识每条指令的执行步骤。其功能相当于一个状态机。前文已述,我们设计的节拍发生器共有3位触发器。在编码方面,遵循了这样的原则:从一个状态变到下一个状态时,状态发生变化的触发器数目应尽量少。
组合逻辑器件,根据指令内容(由IR提供)和指令的执行步骤(由节拍发生器提供)及其他一些条件信号(标志寄存器输出),形成并提供出计算机各部件当前时刻要用到的控制信号。根据前面所总结的全部控制信号的意义、作用和数值,可以比较容易地写出控制逻辑部件。
组合逻辑器件,作用相当于一个双向门,是为了解决数据总线的冲突问题设置的。控制信号就是控制逻辑输出的读写控制信号wr,进行读操作时输出高阻态,写操作时输出ALU的运算结果。
对外输出寄存器内容的译码电路,组合逻辑器件,根据外部输入的寄存器选择信号输出制定的寄存器内容(包括为了便于观察引出的内部信号寄存器)。
经软件测试后数据证明CPU运行正常且正确执行指令
library ieee;
use ieee.std_logic_1164.all;
entity controller is
port(timer: in std_logic_vector(2 downto 0);
instruction: in std_logic_vector(7 downto 0);
c,z,v,s: in std_logic;
dest_reg,sour_reg: out std_logic_vector(1 downto 0);
offset: out std_logic_vector(3 downto 0);
sst,sci,rec: out std_logic_vector(1 downto 0);
alu_func,alu_in_sel: out std_logic_vector(2 downto 0);
en_reg,en_pc,wr: out std_logic);
end controller;
architecture behave of controller is
begin
process(timer,instruction,c,z,v,s)
variable temp1,temp2 : std_logic_vector(3 downto 0) ;
variable temp3,temp4 : std_logic_vector(1 downto 0) ;
variable alu_out_sel: std_logic_vector(1 downto 0);
begin
for I in 3 downto 0 loop
temp1(I):=instruction(I+4);
temp2(I):=instruction(I);
end loop;
for I in 1 downto 0 loop
temp3(I):=instruction(I+2);
temp4(I):=instruction(I);
end loop;
case timer is
when "100"=>
dest_reg<="00";
sour_reg<="00";
offset<="0000";
sci<="00"; --c=0
sst<="11"; --null
alu_out_sel:="00";
alu_in_sel<="000"; -- SR DR
alu_func<="000"; -- A+B+Cin
wr<='1'; --读
rec<="00";
when "000"=>
dest_reg<="00";
sour_reg<="00";
offset<="0000";
sci<="01"; -- c=1
sst<="11"; --null
alu_out_sel:="10"; --输入pc
alu_in_sel<="100"; -- 0 pc
alu_func<="000"; --A+B+Cin
wr<='1'; --读
rec<="01"; --输出pc
when "001"=>
dest_reg<="00";
sour_reg<="00";
offset<="0000";
sci<="00"; --c=0
sst<="11"; --null
alu_out_sel:="00";
alu_in_sel<="000"; --SR DR
alu_func<="000"; --A+B+Cin
wr<='1';
rec<="10"; --读入IR
when "011"=>
wr<='1';
rec<="00";
case temp1 is
when "0000"=> --ADD dr sr
dest_reg<=temp3;
sour_reg<=temp4;
offset<="0000";
sci<="00"; --c=0
sst<="00"; --正常
alu_out_sel:="01"; --输入寄存器
alu_in_sel<="000"; --sr dr
alu_func<="000"; --A+B+Cin
when "0001"=> --AND dr sr
dest_reg<=temp3;
sour_reg<=temp4;
offset<="0000";
sci<="00"; --c=0
sst<="00"; --正常
alu_out_sel:="01"; --输入寄存器
alu_in_sel<="000"; --sr dr
alu_func<="010"; --A与B
when "0010"=> --CMP dr sr
dest_reg<=temp3;
sour_reg<=temp4;
offset<="0000";
sci<="00"; --c=0
sst<="00"; --正常
alu_out_sel:="00";
alu_in_sel<="000"; --sr dr
alu_func<="001"; --B-A-Cin
when "0011"=> --MVRR dr sr
dest_reg<=temp3;
sour_reg<=temp4;
offset<="0000";
sci<="00"; --c=0
sst<="11"; --null
alu_out_sel:="01"; --输入寄存器
alu_in_sel<="001"; --sr 0
alu_func<="000"; --A+B+Cin
when "0100"=> --DEC dr
dest_reg<=temp3;
sour_reg<=temp4;
offset<="0000";
sci<="01"; --c=1
sst<="00"; --正常
alu_out_sel:="01"; --输入寄存器
alu_in_sel<="010"; --0 dr
alu_func<="001"; --B-1
when "0101"=> --SHL dr
dest_reg<=temp3;
sour_reg<=temp4;
offset<="0000";
sci<="00"; --c=0
sst<="00"; --正常
alu_out_sel:="01"; --输入寄存器
alu_in_sel<="010"; --0 DR
alu_func<="101"; --左移
when "0110"=> --ADC dr sr
dest_reg<=temp3;
sour_reg<=temp4;
offset<="0000";
sci<="10"; --c
sst<="00"; --正常
alu_out_sel:="01"; --输入寄存器
alu_in_sel<="000"; --dr sr
alu_func<="000"; --A+B+Cin
when "0111"=> --JR addr
dest_reg<="00";
sour_reg<="00";
offset<=temp2;
sci<="00"; --c=0
sst<="11"; --null
alu_out_sel:="10"; --输入pc
alu_in_sel<="011"; --offset pc
alu_func<="000"; --A+B+Cin
when "1000"=> --JRC addr
dest_reg<="00";
sour_reg<="00";
offset<=temp2;
sci<="00"; --c=0
sst<="11"; --null
alu_out_sel:=c&"0"; --c=1时输入pc
alu_in_sel<="011"; --offset pc
alu_func<="000"; --A+B+Cin
when "1001"=> --JRNZ addr
dest_reg<="00";
sour_reg<="00";
offset<=temp2;
sci<="00"; --c=0
sst<="11"; --null
alu_out_sel:=(not z)&"0"; --z=1时输入pc
alu_in_sel<="011"; --offset pc
alu_func<="000"; --A+B+Cin
when "1010"=> --CLC
dest_reg<="00";
sour_reg<="00";
offset<=temp2;
sci<="00"; --c=0
sst<="01"; --c=0
alu_out_sel:="00";
alu_in_sel<="000"; --sr dr
alu_func<="000"; --A+B+Cin
when "1011"=> --STC
dest_reg<="00";
sour_reg<="00";
offset<=temp2;
sci<="00"; --c=0
sst<="10"; --c=1
alu_out_sel:="00";
alu_in_sel<="000"; --sr dr
alu_func<="000"; --A+B+Cin
when others=>
null;
end case;
when "101"=>
alu_func<="000"; --A+B+Cin
wr<='1';
sst<="11"; --null
dest_reg<=temp3;
sour_reg<=temp4;
offset<="0000";
case temp1 is
when "1100" | "1111"=> --JMPA addr/MVRD dr,data
sci<="01"; --c=1
alu_out_sel:="10"; --输入pc
alu_in_sel<="100"; --0 pc
rec<="01"; --输出pc
when "1101"=> --LDRR dr,sr DR<-[SR]
sci<="00"; --c=0
alu_out_sel:="00";
alu_in_sel<="001"; --sr 0
rec<="11"; --输出alu_out
when "1110"=> --STRR dr,sr [DR]<-SR
sci<="00"; --c=0
alu_out_sel:="00";
alu_in_sel<="010"; --0 dr
rec<="11"; --输出alu_out
when others=>
null;
end case;
when "111"=>
dest_reg<=temp3;
sour_reg<=temp4;
offset<="0000";
sci<="00"; --c=0
sst<="11"; --null
alu_func<="000"; --A+B+Cin
rec<="00"; --null
case temp1 is
when "1101" | "1111"=> --LDRR dr,sr DR<-[SR]/MVRD dr,data
alu_out_sel:="01"; --输入寄存器
alu_in_sel<="101"; --0 DATA
wr<='1';
when "1100"=> --JMPA addr
alu_out_sel:="10"; --输入pc
alu_in_sel<="101"; --0 DATA
wr<='1';
when "1110"=> --STRR dr,sr [DR]<-SR
alu_out_sel:="00";
alu_in_sel<="001"; --sr 0
wr<='0'; --写
when others=>
null;
end case;
when others=>
null;
end case;
en_reg<=alu_out_sel(0);
en_pc<=alu_out_sel(1);
end process;
end behave;
library ieee;
use ieee.std_logic_1164.all;
entity timer is
port(
clk : in std_logic;
reset : in std_logic;
ins : in std_logic_vector(7 downto 0);
output : out std_logic_vector(2 downto 0));
end timer;
architecture behave of timer is
type state_type is(s0,s1,s2,s3,s4,s5);
signal state:state_type;
begin
process(clk,reset,ins)
begin
if reset='0' then state<=s0;
elsif (clk'event and clk='1') then
case state is
when s0=>
state<=s1;
when s1=>
state<=s2;
when s2=>
if ins(7)='1' and ins(6)='1' then
state<=s4;
else state<=s3;
end if;
when s3=>
state<=s1;
when s4=>
state<=s5;
when s5=>
state<=s1;
end case;
end if;
end process;
process(state)
begin
case state is
when s0=>
output<="100";
when s1=>
output<="000";
when s2=>
output<="001";
when s3=>
output<="011";
when s4=>
output<="101";
when s5=>
output<="111";
end case;
end process;
end behave;
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity alu is
port(cin:in std_logic;
alu_a,alu_b:in std_logic_vector(7 downto 0);
alu_func:in std_logic_vector(2 downto 0);
alu_out:out std_logic_vector(7 downto 0);
c,z,v,s:out std_logic);
end alu;
architecture behave of alu is
begin
process(alu_a,alu_b,cin,alu_func)
variable temp1,temp2,temp3 : std_logic_vector(7 downto 0) ;
begin
temp1 := "0000000"&cin;
case alu_func is
when "000"=>
temp2 := alu_b+alu_a+temp1;
when "001"=>
temp2 := alu_b-alu_a-temp1;
when "010"=>
temp2 := alu_a and alu_b;
when "011"=>
temp2 := alu_a or alu_b;
when "100"=>
temp2 := alu_a xor alu_b;
when "101"=>
temp2(0) := '0';
for I in 7 downto 1 loop
temp2(I) := alu_b(I-1);
end loop;
when "110"=>
temp2(7) := '0';
for I in 6 downto 0 loop
temp2(I) := alu_b(I+1);
end loop;
when others=>
temp2 := "00000000";
end case;
alu_out <= temp2;
if temp2 = "00000000" then z<='1';
else z<='0';
end if;
if temp2(7) = '1' then s<='1';
else s<='0';
end if;
case alu_func is
when "000" | "001"=>
if (alu_a(7)= '1' and alu_b(7)= '1' and temp2(7) = '0') or
(alu_a(7)= '0' and alu_b(7)= '0' and temp2(7) = '1') then
v<='1';
else v<='0';
end if;
when others=>
v<='0';
end case;
case alu_func is
when "000"=>
temp3 := "11111111"-alu_b-temp1;
if temp3
if alu_b
c <= alu_b(7);
when "110"=>
c <= alu_b(0);
when others=>
c<='0';
end case;
end process;
end behave;
library ieee;
use ieee.std_logic_1164.all;
entity bus_mux is
port(alu_in_sel : in std_logic_vector(2 downto 0);
data,pc,offset,sr,dr : in std_logic_vector(7 downto 0);
alu_sr,alu_dr : out std_logic_vector(7 downto 0));
end bus_mux;
architecture behave of bus_mux is
begin
process(alu_in_sel,data,pc,offset,sr,dr)
begin
case alu_in_sel is
when "000"=>
alu_sr<=sr;
alu_dr<=dr;
when "001"=>
alu_sr<=sr;
alu_dr<="00000000";
when "010"=>
alu_sr<="00000000";
alu_dr<=dr;
when "011"=>
alu_sr<=offset;
alu_dr<=pc;
when "100"=>
alu_sr<="00000000";
alu_dr<=pc;
when "101"=>
alu_sr<="00000000";
alu_dr<=data;
when others=>
alu_sr<="00000000";
alu_dr<="00000000";
end case;
end process;
end behave;
library ieee;
use ieee.std_logic_1164.all;
entity flag_reg is
port(sst: in std_logic_vector(1 downto 0);
c,z,v,s,clk,reset: in std_logic;
flag_c,flag_z,flag_v,flag_s: out std_logic);
end flag_reg;
architecture behave of flag_reg is
begin
process(clk,reset)
begin
if reset = '0' then
flag_c<='0';
flag_z<='0';
flag_v<='0';
flag_s<='0';
elsif clk'event and clk = '1' then
case sst is
when "00"=>
flag_c<=c;
flag_z<=z;
flag_v<=v;
flag_s<=s;
when "01"=>
flag_c<='0';
when "10"=>
flag_c<='1';
when "11"=>
null;
end case;
end if;
end process;
end behave;
library ieee;
use ieee.std_logic_1164.all;
entity reg is
port(d: in std_logic_vector(7 downto 0);
clk,reset,en: in std_logic;
q:out std_logic_vector(7 downto 0));
end reg;
architecture behave of reg is
begin
process(clk,reset,en)
begin
if reset = '0' then
q <= "00000000";
elsif clk'event and clk = '1' then
if en = '1' then
q <= d;
end if;
end if;
end process;
end behave;
library ieee;
use ieee.std_logic_1164.all;
entity reg_mux is
port(reg_0: in std_logic_vector(7 downto 0);
reg_1: in std_logic_vector(7 downto 0);
reg_2: in std_logic_vector(7 downto 0);
reg_3: in std_logic_vector(7 downto 0);
dest_reg:in std_logic_vector(1 downto 0);
sour_reg:in std_logic_vector(1 downto 0);
reg_sel: in std_logic_vector(1 downto 0);
en: in std_logic;
en_0: out std_logic;
en_1: out std_logic;
en_2: out std_logic;
en_3: out std_logic;
dr: out std_logic_vector(7 downto 0);
sr: out std_logic_vector(7 downto 0);
reg_out: out std_logic_vector(7 downto 0));
end reg_mux;
architecture behave of reg_mux is
begin
process(dest_reg,sour_reg,reg_sel,reg_0,reg_1,
reg_2,reg_3,en)
variable temp : std_logic_vector(3 downto 0);
begin
case dest_reg is
when "00"=>
dr<=reg_0;
temp := "0001";
when "01"=>
dr<=reg_1;
temp := "0010";
when "10"=>
dr<=reg_2;
temp := "0100";
when "11"=>
dr<=reg_3;
temp := "1000";
end case;
if en = '0' then
temp := "0000";
end if;
en_0 <= temp(0);
en_1 <= temp(1);
en_2 <= temp(2);
en_3 <= temp(3);
case sour_reg is
when "00"=>
sr<=reg_0;
when "01"=>
sr<=reg_1;
when "10"=>
sr<=reg_2;
when "11"=>
sr<=reg_3;
end case;
case reg_sel is
when "00"=>
reg_out<=reg_0;
when "01"=>
reg_out<=reg_1;
when "10"=>
reg_out<=reg_2;
when "11"=>
reg_out<=reg_3;
end case;
end process;
end behave;
library ieee;
use ieee.std_logic_1164.all;
entity t1 is
port(flag_c:in std_logic;
sci:in std_logic_vector(1 downto 0);
alu_cin:out std_logic);
end t1;
architecture behave of t1 is
begin
process(sci,flag_c)
begin
case sci is
when "00"=>
alu_cin<='0';
when "01"=>
alu_cin<='1';
when "10"=>
alu_cin<=flag_c;
when others=>
alu_cin<='0';
end case;
end process;
end behave;
library ieee;
use ieee.std_logic_1164.all;
entity t2 is
port(offset_4:in std_logic_vector(3 downto 0);
offset_8:out std_logic_vector(7 downto 0));
end t2;
architecture behave of t2 is
begin
process(offset_4)
begin
if offset_4(3) = '1' then offset_8 <= "1111" & offset_4;
else offset_8 <= "0000" & offset_4;
end if;
end process;
end behave;
library ieee;
use ieee.std_logic_1164.all;
entity t3 is
port(wr : in std_logic;
alu_out : in std_logic_vector(7 downto 0);
output : out std_logic_vector(7 downto 0));
end t3;
architecture behave of t3 is
begin
process(wr,alu_out)
begin
case wr is
when '1'=>
output<="ZZZZZZZZ";
when '0'=>
output<=alu_out;
end case;
end process;
end behave;
library ieee;
use ieee.std_logic_1164.all;
entity ir is
port(mem_data: in std_logic_vector(7 downto 0);
rec: in std_logic_vector(1 downto 0);
clk,reset: in std_logic;
q: out std_logic_vector(7 downto 0));
end ir;
architecture behave of ir is
begin
process(clk,reset)
begin
if reset = '0' then
q <= "00000000";
elsif clk'event and clk = '1' then
case rec is
when "10"=>
q <= mem_data;
when others=>
null;
end case;
end if;
end process;
end behave;
library ieee;
use ieee.std_logic_1164.all;
entity pc is
port(alu_out: in std_logic_vector(7 downto 0);
en: in std_logic;
clk,reset: in std_logic;
q: out std_logic_vector(7 downto 0));
end pc;
architecture behave of pc is
begin
process(clk,reset)
begin
if reset = '0' then
q <= "00000000";
elsif clk'event and clk = '1' then
if en = '1' then
q <= alu_out;
end if;
end if;
end process;
end behave;
library ieee;
use ieee.std_logic_1164.all;
entity ar is
port(alu_out: in std_logic_vector(7 downto 0);
pc: in std_logic_vector(7 downto 0);
rec: in std_logic_vector(1 downto 0);
clk,reset: in std_logic;
q: out std_logic_vector(7 downto 0));
end ar;
architecture behave of ar is
begin
process(clk,reset)
begin
if reset = '0' then
q <= "00000000";
elsif clk'event and clk = '1' then
case rec is
when "01"=>
q <= pc;
when "11"=>
q <= alu_out;
when others=>
null;
end case;
end if;
end process;
end behave;