在大型FPGA的设计过程中,往往是采用的从上至下的混合设计方法,既是先
由顶层设计工程师将一个工程进行整体的规划布局,在画好原理图后,将原理图
的各个部分(小的模块)交由其他的工程师去完成,分别调试仿真成功之后,再
由顶层工程师相当于是对工程进行组装,整体调试,验证设想。
那么在分由各个工程师完成的部分,不同的工程师可能用的不是同一种设计
方法,也可能不是同一种设计语言,那么顶层工程师就要对所有的不同的设计文
件进行组装,也就是设置自己的文件为编译的顶层文件(相当于是C语言里面的
main函数),然后以这个顶层文件为基准进行编译(相当于C语言里面main中的函
数调用),调用的模块也可以不是同一种语言或者方法设计的,这样就是实现了
在FPGA工程设计过程中在不同的组合方法,使得设计的效率提高。
具体的实现混合设计有几种方法,其中一个是将设计的小模块实例化,做成
一个实体,这个我还没有试验过;第二种就是将写好的代码进行图元化,然后在顶层文件中调用这些图元,组成你需要的逻辑功能电路。
小弟我用了第二种混合设计的方法,弄了一个很简单的东西,VHDL语言写的是BCD译码的数码管显示电路,verilog HDL写的是按键消抖以及检测按键的电路,然后分别对两个文件进行图元化(File--Create/update--Create
symbol files for current file),最后顶层的schematic file中调用这两个图元,连接即可,最后把这个.bdf文件设置为顶层文件,编译配置即可。
按键代码如下:
module
key_delay_prj3(
clk,rst_n,
sw1_n,sw2_n,sw3_n,sw4_n,sw5_n,sw6_n,sw7_n,sw8_n,
led
);
input clk; //主时钟信号,20MHZ
input rst_n; //复位信号,低电平有效
input
sw1_n,sw2_n,sw3_n,sw4_n,sw5_n,sw6_n,sw7_n,sw8_n; //独立按键
output led; //发光二极管,由按键控制,按下则置fan
wire [7:0] led; //最后是送到数码管显示的output端口
//全部做的是二级缓存结构----------------------------------//
reg [7:0]
key_rst;
always @(posedge
clk or negedge rst_n)
if(!rst_n) //异步复位
key_rst <= 8'b11111111;
else key_rst <=
{sw1_n,sw2_n,sw3_n,sw4_n,sw5_n,sw6_n,sw7_n,sw8_n};
//------------------------------------------------------//
reg [7:0]
key_rst_r;//每个时钟周期的上升沿将key_rst的值锁存到key_rst_r中
always @(posedge
clk or negedge rst_n)
if(!rst_n)
key_rst_r <= 8'b11111111;
else
key_rst_r <= key_rst;
//两次采集的值不同则产生一个时钟周期的高脉冲//
wire [7:0]
key_an = key_rst_r & (~key_rst);
//--------------------------------------------------//
reg [19:0] cnt; //计数寄存器
always @(posedge
clk or negedge rst_n)
if(!rst_n)
cnt <= 20'd0;
else if(key_an) cnt <= 20'd0;
else cnt <= cnt + 1'b1;
//-------------------------------------------------//
reg [7:0]
low_sw;
always @(posedge
clk or negedge rst_n)
if(!rst_n)
low_sw <= 8'b11111111;
else if(cnt == 20'd1000000) //每隔20ms锁存一次按键的值
low_sw <=
{sw1_n,sw2_n,sw3_n,sw4_n,sw5_n,sw6_n,sw7_n,sw8_n};
//每个时钟周期的上升沿将low_sw的值锁存到low_sw_r中//
reg [7:0]
low_sw_r;
always @(posedge
clk or negedge rst_n)
if(!rst_n)
low_sw_r <= 8'b11111111;
else
low_sw_r <= low_sw;
//当寄存器low_sw由1变成0时,led_ctrl的值变为高,维持一个时钟周期//
wire [7:0]
led_ctrl = low_sw_r[7:0] & (~low_sw[7:0]);
reg [7:0] d;
always @(posedge
clk or negedge rst_n)
if(!rst_n) begin
d <= 8'b00000000;
end
else begin //按键发生变化时LED做亮灭翻转
if(led_ctrl[0]) d[0] <= ~d[0];
if(led_ctrl[1]) d[1] <= ~d[1];
if(led_ctrl[2]) d[2] <= ~d[2];
if(led_ctrl[3]) d[3] <= ~d[3];
if(led_ctrl[4]) d[4] <= ~d[4];
if(led_ctrl[5]) d[5] <= ~d[5];
if(led_ctrl[6]) d[6] <= ~d[6];
if(led_ctrl[7]) d[7] <= ~d[7];
end
assign led[0] =
d[0] ? 1'b1 : 1'b0; //LED翻转输出
assign led[1] =
d[1] ? 1'b1 : 1'b0;
assign led[2] =
d[2] ? 1'b1 : 1'b0;
assign led[3] =
d[3] ? 1'b1 : 1'b0;
assign led[4] =
d[4] ? 1'b1 : 1'b0;
assign led[5] =
d[5] ? 1'b1 : 1'b0;
assign led[6] =
d[6] ? 1'b1 : 1'b0;
assign led[7] =
d[7] ? 1'b1 : 1'b0;
endmodule
BCD译码,数码管显示电路代码:
library ieee;
use
ieee.std_logic_1164.all;
use
ieee.std_logic_unsigned.all;
use
ieee.std_logic_arith.all;
entity
shumaguan_prj is --实体申明
port(
clk:in std_logic;
led_cs:out std_logic;
key_in:in std_logic_vector(7 downto 0);
disp
:out std_logic_vector(7 downto 0)
);
end
shumaguan_prj;
architecture rtl
of shumaguan_prj is
signal
key_in_buf:std_logic_vector(7 downto 0);---定义一个缓冲器
signal
disp_buf: std_logic_vector(7 downto 0);---定义一个缓冲器
begin
key_in_buf <=
key_in;
disp <=
disp_buf;
led_cs <=
'1'; ---数码管的片选打开
process(clk)
begin
if rising_edge(clk) then
case key_in_buf is
when
"00000001" => disp_buf<="11111001";--按键s1显示1
when
"00000010" => disp_buf <=
"10100100"; --按键s2显示2
when "00000100"
=> disp_buf <=
"10110000";
when "00001000"
=> disp_buf <=
"10011001";
when "00010000"
=> disp_buf <=
"10010010";
when "00100110"
=> disp_buf <=
"10000010";
when "01000000"
=> disp_buf <=
"11111000";
when "10000000"
=> disp_buf <=
"10000000";
when others => disp_buf
<="11111111";
end case;
end if;
end process;
end rtl;
最后连接图如下:
文章评论(0条评论)
登录后参与讨论