library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity cal is
port(clk:in std_logic; --输入时钟信号
num:in std_logic_vector(9 downto 0);--数字按键
plus:in std_logic;--加法按键
subt:in std_logic;--减法按键
mult:in std_logic;--乘法按键
mdiv:in std_logic;--除法按键
equal:in std_logic;--等号键
c:in std_logic; --清零键,异步置位键
onum1,onum2,onum3:out std_logic_vector(0 to 6)); --3个七段译码显示管
end cal;
architecture a of cal is
signal flag:std_logic; --表示是否有是第一个数的输入标识flag
signal fl:std_logic; --表示是否开始第二个数的标识fl
signal acc:std_logic_vector(7 downto 0):=x"00"; --用于存放第一个数的累加器
signal reg:std_logic_vector(7 downto 0):=x"00"; --用于存放第二个以及以后的数字的寄存器
signal keep:std_logic_vector(7 downto 0);--用于放显示数字的暂存器
signal ans:std_logic_vector(7 downto 0); --用于放各步计算结果的寄存器,不包括除法结果
signal dans:std_logic_vector(3 downto 0);
--用于存放除法结果的寄存器
signal dan:std_logic_vector(3 downto 0);
signal numbuff:std_logic_vector(3 downto 0);--数字缓存
signal vf:std_logic;--表示是否是最后结果的标识
signal strdiv:std_logic;--除法计算开始的信号
signal numclk:std_logic;--将数字想哦那个缓存numbuff放入累加器acc或寄存器reg的信号
signal clear:std_logic; --清零reg中数字的信号
signal inplus:std_logic;
signal insubt:std_logic;
signal inmult:std_logic;
signal inmdiv:std_logic;
signal inequal:std_logic;--同步加减乘除等于信号
signal cou:std_logic_vector(1 downto 0);--用来记忆是第几次计算的信号
component numdecoder is --引用数字按键的译码电路
port(reset:in std_logic;
inclk:in std_logic;
innum:in std_logic_vector(9 downto 0);
outnum:buffer std_logic_vector(3 downto 0);
outflag:out std_logic);
end component;
component display is--引用数字的显示电路
port(c,clk:in std_logic;
keep:in std_logic_vector(7 downto 0);
onum1,onum2,onum3:out std_logic_vector(0 to 6));
end component;
component div is --引用除法器
port(a:in std_logic_vector(7 downto 0);
b:in std_logic_vector(3 downto 0);
clk:in std_logic;
str:in std_logic;
s:out std_logic_vector(3 downto 0);
y:out std_logic_vector(3 downto 0));
end component;
begin
innum1:numdecoder port map (c,clk,num,numbuff,numclk);--按键后产生相对应的数字
pacecal:process(c,clk)--产生同步运算符号
begin
if c='1' then
inplus<='0';insubt<='0';inmult<='0';inmdiv<='0';
elsif clk'event and clk='1' then
if plus='1' then
inplus<='1';insubt<='0';inmult<='0';inmdiv<='0';
elsif subt='1' then
inplus<='0';insubt<='1';inmult<='0';inmdiv<='0';
elsif mult='1' then
inplus<='0';insubt<='0';inmult<='1';inmdiv<='0';
elsif mdiv='1' then
inplus<='0';insubt<='0';inmult<='0';inmdiv<='1';
end if;
end if;
end process pacecal;
ctrflag:process(c,clk)--用于产生flag信号,其实flag也只在整个运算中
--输入第一个数字时flag=0,输完时为1
begin
if c='1' then--异步置位
flag<='0';
elsif clk'event and clk='1' then
if inplus='1' or insubt='1' or inmult='1' or inmdiv='1' then
flag<='1';
else
flag<='0';
end if;
end if;
end process ctrflag;
ctrfirstnum:process(c,numclk)--第一个运算数,放入acc中
begin
if c='1' then
acc<="00000000";
elsif numclk'event and numclk='0' then
if flag='0' then--第一个数正在输入
acc<=acc+acc+acc+acc+acc+acc+acc+acc+acc+acc+numbuff;--相当于acc<=acc*10+numbuff
end if;
end if;
end process ctrfirstnum;
ctrsecondnum:process(c,clk,numclk)--输入第二个数及以后的数,放入reg中
begin
if c='1' or clear='1' then
reg<="00000000";fl<='0';
elsif numclk'event and numclk='0' then
if flag='1' then
fl<='1'; --表示正在输入第二个数
reg<=reg+reg+reg+reg+reg+reg+reg+reg+reg+reg+numbuff;
end if;
end if;
end process ctrsecondnum;
ctrclear:process(c,clk)--产生clear信号
begin
if c='1' then
clear<='0';
else
if inequal'event and inequal='0' then
clear<='1';
end if;
end if;
end process ctrclear;
ctrinequal:process(c,clk)--运算时钟
begin
if c='1' then
inequal<='0';
elsif clk'event and clk='1' then
if plus='1' or subt='1' or mult='1' or mdiv='1' or equal='1' then
inequal<='1';
else inequal<='0';
end if;
end if;
end process ctrinequal;
ctrcou:process(c,clk)
begin
if c='1' then
cou<="00";
elsif inequal'event and inequal='1' then
if cou="10" then
cou<=cou;
else cou<=cou+1;
end if;
end if;
end process ctrcou;
ctrcal:process(c,inequal)--下面是运算进程
begin
if c='1' then
ans<="00000000";
strdiv<='0';
elsif inequal'event and inequal='1' then
if flag='1' then
if inplus='1' then
if cou="10" then
ans<=ans+reg;
else ans<=acc+reg;
end if;
elsif insubt='1' then
if cou="10" then
ans<=ans-reg;
else ans<=acc-reg;
end if;
elsif inmult='1' then
if acc<="00001111" and reg<="00001111" then
ans<=acc(3 downto 0)*reg(3 downto 0);
else ans<="00000000";
end if;
elsif inmdiv='1' then
strdiv<='1';
end if;
else strdiv<='0';
end if;
end if;
end process ctrcal;
d1:div port map (acc,reg(3 downto 0),clk,strdiv,dans,dan);
ctrvf:process(c,equal)
begin
if c='1' then
vf<='0';
elsif equal'event and equal='1' then
vf<='1';
end if;
end process ctrvf;
ctrkeep:process(c,clk)--用于存放显示数的keep寄存器,时段不同,用于显示不同寄存器的内容
begin
if c='1' then
keep<="00000000";
elsif clk'event and clk='1' then
if flag='0' then
keep<=acc;
elsif flag='1' and fl='1' and vf='0' then
keep<=reg;
elsif flag='1' and fl='0' and vf='0' and cou="10" then
keep<=ans;
elsif flag='1' and vf='1' then
if inmdiv='0' then
keep<=ans;
else
keep(3 downto 0)<=dans;
end if;
end if;
end if;
end process ctrkeep;
v1: display port map (c,clk,keep,onum1,onum2,onum3);--调用显示模块,把8位二进制转化为整数