最近因为导师要求我带大三学生的fpga实验课,有一个实验是用fpga设计处理器的核心电路。做出来以后便用这篇博文总结一下。
该实验只设计了一个最基本的处理器其中包括多个寄存器,一个多路选择器,一个加法/减法单元,计数器和一个控制单元。
寄存器的作用是存储单个位或者字,通过时钟信号和控制单元输出的信号来控制寄存器的输出。处理器所处理的输入数据通过多路复用器加载到不同的寄存器中,复用器的输出称为总线,总线是容许数据从一个位置传到另外一个位置的。该实验寄存器的位宽为16位,总共定义了R0-R7,A,G,IR寄存器。
加减法单元是通过多路复用器将数据首先加载到一个特定的寄存器A中,这个寄存器固定作为这个单元的一个操作数。第二个操作书通过总线传到另外一个数据接口,通过运算操作后,把数据寄存到寄存器G中,寄存器G中的数值可以通过复用器传输到其他位置。
在控制单元的控制下,每个时钟周期可以完成不同的操作,它能控制哪个寄存器加载总线上的数据,哪个寄存器的数值放到总线上。
本次实验需要用到4条指令,mvi,mov,add,sub。每个指令运行的周期如下:
通过iR寄存器来查询指令。因为iR寄存器有16位,可以选择前八位来代表指令,后面8位分别代表寄存器,如iiiiiiiixxxxyyyy,iiiiiiii代表指令,xxxx代表Rx寄存器,yyyy代表Ry寄存器。
因此,我们在进行编写程序时,可以把整个实验分为七个模块。
首先是寄存器模块,此处便是一个D触发器。
entity regn is
port(
clk,nin,rst<span style="white-space:pre"> </span>: in std_logic;
n : in std_logic_vector(15 downto 0);
nout : out std_logic_vector(15 downto 0)
);
end regn;
architecture arch of regn is
begin
process(clk,nin,rst)
begin
<span style="white-space:pre"> </span>if(clk'event and clk = '1')
then
if(rst = '0')
then
nout <= "0000000000000000";
else
if(nin = '1')
then
nout <= n;
end if;
end if;
<span style="white-space:pre"> </span>end if;
end process;
end arch;
第二个模块是加减法。
entity addsub is
port(
<span style="white-space:pre"> </span>A,BusWires : in std_logic_vector(15 downto 0);
G : out std_logic_vector(15 downto 0);
clk : in std_logic;
Add_Sub,Gin : in std_logic
<span style="white-space:pre"> </span>);
end addsub;
architecture arch of addsub is
begin
<span style="white-space:pre"> </span>process(clk,Gin,Add_Sub)
begin
if(clk'event and clk = '1')
then
if(Gin = '1')
then
if(Add_Sub = '1')
then
G <= A+BusWires;
else
G <= A-BusWires;
end if;
end if;
end if;
end process;
end arch;
第三个是多路选择器模块。
<span style="font-size:10px;">entity mul is
port(
R0,R1,R2,R3,R4,R5,R6,R7,G,Din : in std_logic_vector(15 downto 0);
Rout : in std_logic_vector(7 downto 0);
Dinout,Gout : in std_logic;
BusWires : out std_logic_vector(15 downto 0)
);
end mul;
architecture arch of mul is
begin
process(Gout,Dinout,Rout)
begin
case ( Gout & Dinout & Rout) is
when "0000000001" => BusWires <= R0;
when "0000000010" => BusWires <= R1;
when "0000000100" => BusWires <= R2;
when "0000001000" => BusWires <= R3;
when "0000010000" => BusWires <= R4;
when "0000100000" => BusWires <= R5;
when "0001000000" => BusWires <= R6;
when "0010000000" => BusWires <= R7;
when "0100000000" => BusWires <= Din;
when "1000000000" => BusWires <= G;
when OTHERS => NULL;
end case;
end process;
end arch;</span><span style="font-size:18px;">
</span>
第四个模块是加法计数器模块,是进行指令的加减周期计算的。
<pre name="code" class="plain">entity upcount is
port(
rst,clear,clk : in std_logic;
Q : out std_logic_vector(1 downto 0)
);
end upcount;
architecture arch of upcount is
signal Q1 : std_logic_vector(1 downto 0);
begin
process(clk)
begin
if(clk'event and clk = '1')
then
if(rst = '0')
then
Q1 <= "00";
else if(clear = '1')
then
Q1 <= "00";
else
Q1 <= Q1 + '1';
end if;
end if;
end if;
<span style="white-space:pre"> </span>Q <= Q1;
end process;
end arch;
<span style="font-size:18px; font-family: Arial, Helvetica, sans-serif;"> </span><span style="font-size:18px; font-family: Arial, Helvetica, sans-serif;">第五个模块是38译码器模块,对iR寄存器的输出进行译码从而选择寄存器。</span>
entity dec3to8 is
port(
rst : in std_logic;
sel : in std_logic_vector(2 downto 0);
r_out : out std_logic_vector(7 downto 0)
);
end dec3to8;
architecture arch of dec3to8 is
begin
process(rst,sel)
begin
if(rst = '0')
then
r_out <= "00000000";
else
case(sel) is
when "000" => <span style="white-space:pre"> </span>r_out <= "00000001";
when "001" => r_out <= "00000010";
when "010" => r_out <= "00000100";
when "011" => r_out <= "00001000";
when "100" => r_out <= "00010000";
when "101" => r_out <= "00100000";
when "110" => r_out <= "01000000";
when "111" => r_out <= "10000000";
when others => r_out <= "00000000";
end case;
end if;
end process;
end arch;
第六个模块是处理器模块,是对他所接收的输入进行处理从而选择哪个模块进行输入和输出。
<span style="font-size:10px;">entity control is
port(
count : in std_logic_vector(1 downto 0);
reg_IR : in std_logic_vector(15 downto 0);
Rin,Rout : out std_logic_vector(7 downto 0);
IRin,Ain,Gin,Gout,
DINout,ADDSUB,Clear : out std_logic;
Done : buffer std_logic
);
end control;
architecture arch of control is
constant mv :std_logic_vector := "00000000";
constant mvi :std_logic_vector := "00000001";
constant add :std_logic_vector := "00000010";
constant sub :std_logic_vector := "00000011";
constant D :std_logic_vector := "1000";
constant R0 :std_logic_vector := "0000";
constant R1 :std_logic_vector := "0001";
constant R2 :std_logic_vector := "0010";
constant R3 :std_logic_vector := "0011";
constant R4 :std_logic_vector := "0100";
constant R5 :std_logic_vector := "0101";
constant R6 :std_logic_vector := "0110";
constant R7 :std_logic_vector := "0111";
signal w :std_logic_vector(7 downto 0);
signal Xreg,Yreg:std_logic_vector(7 downto 0);
component dec3to8
port(
rst : in std_logic;
sel : in std_logic_vector(2 downto 0);
r_out : out std_logic_vector(7 downto 0)
);
end component;
begin
w <= reg_IR(15 downto 8);
decx : dec3to8
port map('1',reg_IR(6 downto 4),Xreg);
decy : dec3to8
port map('1',reg_IR(2 downto 0),Yreg);
process(count,w,Xreg,Yreg)
begin
Rout <= "00000000";
Rin <= "00000000";
Ain <= '0';
Gin <= '0';
ADDSUB <= '0';
Gout <= '0';
DINout <= '0';
Done <= '0';
Clear <= '0';
if(count = "00")
then
Rout <= "00000000";
Rin <= "00000000";
IRin <= '1';
Ain <= '0';
Gin <= '0';
ADDSUB <span style="white-space:pre"> </span><= '0';
Gout <= '0';
DINout <span style="white-space:pre"> </span><= '0';
Done <= '0';
Clear <= '0';
elsif(count = "01")
then
if(w = mv)
then
IRin <= '0';
Ain <= '0';
DINout <span style="white-space:pre"> </span><= '0';
Gout <= <span style="white-space:pre"> </span>'0';
Rout <= <span style="white-space:pre"> </span>Yreg;
Rin <= Xreg;
Clear <= '1';
Done <= '1';
elsif(w = mvi)
then
IRin <= '0';
Ain <= '0';
DINout <span style="white-space:pre"> </span><=<span style="white-space:pre"> </span> '1';
Gout <=<span style="white-space:pre"> </span> '0';
Rout <= <span style="white-space:pre"> </span>"00000000";
Rin <= <span style="white-space:pre"> </span>Xreg;
Clear <= '1';
Done <= '1';
elsif(w = add)
then
IRin <= '0';
Ain <= '1';
Gout <= '0';
Done <= '0';
Rin <= "00000000";
Rout <= Xreg;
DINout <= '0';
Clear <= '0';
elsif(w = sub)
then
IRin <= '0';
Ain <= '1';
Gout <= '0';
Done <= '0';
Rin <= "00000000";
Rout <= Xreg;
DINout <span style="white-space:pre"> </span><= '0';
Clear <= '0';
else
if(Done = '1')
then
IRin <= '1';
else
IRin <= '0';
end if;
end if;
elsif(count = "10")
then
if(w = add)
then
Ain <= <span style="white-space:pre"> </span>'0';
Gin <= '1';
Rout <= Yreg;
Gout <= '0';
DINout <span style="white-space:pre"> </span><= '0';
ADDSUB <span style="white-space:pre"> </span><= '1';
Done <= '0';
elsif(w = sub)
then
Ain <= '0';
Gin <= '1';
Rout <= Yreg;
Gout <= '0';
DINout <= '0';
ADDSUB <= '0';
Done <= '0';
else
IRin <= '0';
end if;
elsif(count = "11")
then
if(w = add)
then
Rin <= Xreg;
Gin <= '0';
Rout <= "00000000";
Gout <= '1';
Done <= <span style="white-space:pre"> </span>'1';
Clear <= '1';
DINout <span style="white-space:pre"> </span><= '0';
elsif(w = sub)
then
Rin <= Xreg;
Gin <= '0';
Rout <= "00000000";
Gout <= '1';
Clear <= '1';
DINout <span style="white-space:pre"> </span><= '0';
Done <=<span style="white-space:pre"> </span> '1';
else
Rin <= "00000000";
Rout <= "00000000";
IRin <= '0';
<span style="white-space:pre"> </span>end if;
end if;
end process;
end arch; </span>
第七个模块就是把所有模块进行例化和调用。
entity processor is
port(
Clk,rst <span style="white-space:pre"> </span>: in std_logic;
BusWire : <span style="white-space:pre"> </span>out std_logic_vector(15 downto 0);
Done : <span style="white-space:pre"> </span>out std_logic;
Din : in std_logic_vector(15 downto 0)
);
end processor;
architecture arch of processor is
signal reg0,reg1,reg2,reg3,reg4,reg5,
reg6,reg7,regG,buswr,rega,regIR : std_logic_vector(15 downto 0);
signal IRin,Ain,Gin,Gout,
DINout,ADD_SUB,Clear : std_logic;
signal reg,Rout,Rin : std_logic_vector(7 downto 0);
signal upcount_1 : std_logic_vector(1 downto 0);
-- register
component regn
port(
clk,nin,rst : in std_logic;
n : in std_logic_vector(15 downto 0);
<span style="white-space:pre"> </span>nout : out std_logic_vector(15 downto 0)
);
end component;
-- multiplexers : select the register
component mul
port(
R0,R1,R2,R3,R4,R5,R6,R7,G,Din : in std_logic_vector(15 downto 0);
Rout : in std_logic_vector(7 downto 0);
Dinout,Gout : in std_logic;
BusWires : out std_logic_vector(15 downto 0)
);
end component;
-- addsub
component addsub
port(
A,BusWires : in std_logic_vector(15 downto 0);
G : out std_logic_vector(15 downto 0);
clk : in std_logic;
Add_Sub,Gin : in std_logic
);
end component;
--control unit
component control
port(
count : in std_logic_vector(1 downto 0);
reg_IR : in std_logic_vector(15 downto 0);
Rin,Rout : out std_logic_vector(7 downto 0);
IRin,Ain,Gin,Gout,
DINout,ADDSUB,Clear<span style="white-space:pre"> </span>: out std_logic;
Done : buffer std_logic
);
end component;
--upcount
component upcount
port(
rst,clear,clk <span style="white-space:pre"> </span> : in std_logic;
Q : out std_logic_vector(1 downto 0)
);
end component;
<span style="white-space:pre"> </span>begin
R0<span style="white-space:pre"> </span>: regn
port map(clk,Rin(0),rst,buswr,reg0);
R1 : regn
port map(clk,Rin(1),rst,buswr,reg1);
R2 : regn
port map(clk,Rin(2),rst,buswr,reg2);
R3 : regn
port map(clk,Rin(3),rst,buswr,reg3);
R4 : regn
port map(clk,Rin(4),rst,buswr,reg4);
R5 : regn
port map(clk,Rin(5),rst,buswr,reg5);
R6 : regn
port map(clk,Rin(6),rst,buswr,reg6);
R7 : regn
port map(clk,Rin(7),rst,buswr,reg7);
A : regn
port map(clk,Ain,rst,buswr,rega);
IR : regn
port map(clk,IRin,rst,Din,regIR);
Add : addsub
port map(rega,buswr,regG,clk,Add_sub,Gin);
multi : mul
port map(reg0,reg1,reg2,reg3,reg4,reg5,reg6,reg7,regG,Din,
Rout,DINout,Gout,buswr);
count : upcount
port map(rst , Clear , clk,upcount_1);
control_unit : control
port map(upcount_1,regIR,Rin,Rout,IRin,Ain,Gin,
Gout,DINout,ADD_SUB,Clear,Done);
BusWire <= buswr;
end arch;
<span style="font-size:18px;">在testbeech中给定的激励如下</span>
<pre name="code" class="plain">clk_gen :process
begin
clk <= '0';
wait for clk_period / 2;
clk <= '1';
wait for clk_period / 2;
end process;
rst_gen :process
begin
rst <= '0';
wait for clk_period * 3;
rst <= '1';
wait;
end process;
Din_gen :process
begin
Din <= "0000000100101000";
wait for clk_period * 4;
Din <= "0000011111011110";
wait for clk_period;
Din <= "0000000101111000";
wait for clk_period;
Din <= "0000000111110101";
wait for clk_period;
Din <= "0000000000110111";
wait for clk_period * 2;
Din <= "0000001000100111";
wait for clk_period * 4;
Din <= "0000001100100110";
wait for clk_period * 4;
Din <= "0000000100101000";
wait for clk_period;
Din <= "0000011111011110";
wait;
end process;<span style="font-family: Arial, Helvetica, sans-serif;"> </span><span style="font-family: Arial, Helvetica, sans-serif;"> </span>
在modelsim仿真的波形如下
另:本人可承接各种毕业设计,pcb设计,FPGA项目设计,电机驱动板卡设计,ARM驱动项目
quincybing 2014.10.28 first version