首页
📁归档
⏳时光机
🚩友链
📫留言
📧订阅本站
推荐
📕考研课程
🏜️ 免费壁纸
❤ 捐助本站
💰资助名单
🎵音乐实验
Search
1
【NPN/PNP三极管】放大电路饱和失真和截止失真的区别
20,039 阅读
2
论文写作中如何把word里面所有数字和字母替换为新罗马字体
10,601 阅读
3
【高数】形心计算公式讲解大全
9,035 阅读
4
Vivado-FPGA Verilog烧写固化教程
7,859 阅读
5
【概论】一阶矩、二阶矩原点矩,中心矩区别与概念
7,803 阅读
🪶微语&随笔
励志美文
我的随笔
写作办公
📡电子&通信
嵌入式&系统
通信&信息处理
编程&脚本笔记
⌨️IC&系统
FPGA&ASIC
VLSI&IC验证
EDA&虚拟机
💻电子&计算机
IP&SOC设计
机器学习
软硬件算法
登录
/
注册
FPGA&ASIC(共60篇)
找到
60
篇与
FPGA&ASIC
相关的结果
- 第 4 页
2022-08-30
【verilog】单端口与双端口RAM设计
RAM (Random Access Memory)随机访问存储器. RAM又称随机存取存储器,存储单元的内容可按照需要随机取出或存入,且存取的速度与存储单元的位置无关。这种存储器在断电时,将丢失其存储内容,所以主要用于存储短时间使用的程序。它主要用来存储程序中用到的变量。凡是整个程序中,所用到的需要被改写的量(包括全局变量、局部变量、堆栈段等),都存储在RAM中。 目录 单端口RAM设计 双端口RAM设计 单端口RAM设计 题目描述: 设计一个单端口RAM,它有: 写接口,读接口,地址接口,时钟接口和复位;存储宽度是4位,深度128。 注意rst为低电平复位 信号示意图: 图片 输入描述: 输入信号 enb, clk, rst addr w_data 类型 wire 在testbench中,clk为周期5ns的时钟,rst为低电平复位 输出描述: 输出信号 r_data 类型 wire `timescale 1ns/1ns module RAM_1port( input clk, input rst, input enb, input [6:0]addr, input [3:0]w_data, output wire [3:0]r_data ); //*************code***********// reg [3:0] ram_reg[127:0]; reg [3:0] ram_data; integer i; always@(posedge clk or negedge rst)begin if(~rst) begin for(i=0;i<128;i=i+1)begin ram_reg[i]<=4'b0; end end else begin if(enb)begin//wire ram_reg[addr]<=w_data; end else begin ram_reg[addr]<=ram_reg[addr]; end end end assign r_data = enb? 4'b0:ram_reg[addr]; //*************code***********// endmodule双端口RAM设计 描述 实现一个深度为8,位宽为4bit的双端口RAM,数据全部初始化为0000。具有两组端口,分别用于读数据和写数据,读写操作可以同时进行。当读数据指示信号read_en有效时,通过读地址信号read_addr读取相应位置的数据read_data,并输出;当写数据指示信号write_en有效时,通过写地址信号write_addr 和写数据write-data,向对应位置写入相应的数据。 程序的信号接口图如下: 图片 模块的时序图如下: 图片 使用Verilog HDL实现以上功能并编写testbench验证。 输入描述: clk:系统时钟信号 rst_n:异步复位信号,低电平有效 read_en,write_en:单比特信号,读/写使能信号,表示进行读/写操作 read_addr,write_addr:8比特位宽的信号,表示读/写操作对应的地址 write_data:4比特位宽的信号,在执行写操作时写入RAM的数据 输出描述: read_data:4比特位宽的信号,在执行读操作时从RAM中读出的数据 `timescale 1ns/1ns module ram_mod( input clk, input rst_n, input write_en, input [7:0]write_addr, input [3:0]write_data, input read_en, input [7:0]read_addr, output reg [3:0]read_data ); reg [3:0] ram_reg[7:0]; integer i; always@(posedge clk or negedge rst_n)begin if(~rst_n) begin for(i=0;i<8;i=i+1)begin ram_reg[i]<=4'b0; end end else begin if(write_en)begin ram_reg[write_addr]<=write_data; end end end always@(posedge clk or negedge rst_n)begin if(~rst_n) begin read_data<=4'b0; end else begin if(read_en)begin read_data<=ram_reg[read_addr]; end end end endmodule
FPGA&ASIC
刘航宇
4年前
0
1,582
0
Verilog教程-CIC 滤波器设计
积分梳状滤波器(CIC,Cascaded Integrator Comb),一般用于数字下变频(DDC)和数字上变频(DUC)系统。CIC 滤波器结构简单,没有乘法器,只有加法器、积分器和寄存器,资源消耗少,运算速率高,可实现高速滤波,常用在输入采样率最高的第一级,在多速率信号处理系统中具有着广泛应用。 目录 DDC 原理 带通采样定理 DDC 频谱搬移 单级 CIC 滤波器 积分器 梳状器 抽取器 参数说明 多级 CIC 滤波器 CIC 滤波器设计 积分器设计 抽取器设计 梳状器设计 顶层例化 仿真结果 DDC 原理 DDC 工作原理 DDC 主要由本地振荡器(NCO) 、混频器、滤波器等组成,如下图所示。 图片 DDC 将中频信号与振荡器产生的载波信号进行混频,信号中心频率被搬移,再经过抽取滤波,恢复原始信号,实现了下变频功能。 中频数据采样时,需要很高的采样频率来确保 ADC(模数转换器)采集到信号的信噪比。经过数字下变频后,得到的基带信号采样频率仍然是 ADC 采样频率,所以数据率很高。此时基带信号的有效带宽往往已经远小于采样频率,所以利用抽取、滤波进行数据速率的转换,使采样率降低,避免资源的浪费和设计的困难,就成为 DDC 不可缺少的一部分。 而采用 CIC 滤波器进行数据处理,是 DDC 抽取滤波部分最常用的方法。 带通采样定理 在 DDC 系统中,输入的中频载波信号会根据载波频率进行频移,得到一个带通信号。如果此时仍然采用奈奎斯特采样定理,即采样频率为带通信号最高频率的两倍,那么此时所需的采样频率将会很高,设计会变的复杂。此时可按照带通采样定理来确定抽样频率。 带通采样定理:一个频带限制在$\left(f_{L}, f_{H}\right)$的连续带通信号,带宽为$\mathrm{B}=f_{H}-f_{L}$。令$0 \leq m \leq N-1$,其中 N 为不大于$f_{H} / B$的最大正整数,如果采样频率满足条件:$\frac{2 f_{H}}{m+1} \leq F_{S} \leq \frac{2 f_{L}}{m}$,$0 \leq m \leq N-1$ 则该信号完全可以由其采样值无失真的重建。 当 m=1 时,带通采样定理便是奈奎斯特采样定理。 带通采样定理的另一种描述方式为:若信号最高频率为信号带宽的整数倍,采样频率只需大于信号带宽的两倍即可,此时不会发生频谱混叠。 所以,可以认为采样频率的一半是 CIC 滤波器的截止频率。 DDC 频谱搬移 例如一个带宽信号中心频率为 60MHz,带宽为 8MHz, 则频率范围为 56MHz ~ 64MHz,m 的可取值范围为 0 ~ 7。取 m=1, 则采样频率范围为 64MHz ~ 112MHz。 取采样频率为 80MHz,设 NCO 中心频率为 20 MHz,下面讨论复信号频谱搬移示意图。 (1)考虑频谱的对称性,输入复信号的频谱示意图如下: 图片 (2)80MHz 采样频率采样后,56~64MHz 的频带被搬移到了 -24~ -16MHz 与 136 ~ 144MHz(高于采样频率被滤除)的频带处,-64~ -56MHz 的频带被搬移到 -144~ -136MHz(高于采样频率被滤除)与 16~24MHz 的频带处。 采样后频带分布如下: 图片 (3)信号经过 20MHz NCO 的正交电路后, -24~ -16MHz 的频带被搬移到 -4~4MHz 与 -44~ -36MHz 的频带处,16~24MHz 的频带被搬移到 -4~4MHz 与 36~44MHz 的频带处,如下所示。 图片 (4)此时中频输入的信号已经被搬移到零中频基带处。 -44~ -36MHz 和 36~44MHz 的带宽信号是不需要的,可以滤除;-4~4MHz 的零中频信号数据速率仍然是 80MHz,可以进行抽取降低数据速率。而 CIC 滤波,就是要完成这个过程。 上述复习了很多数字信号处理的内容,权当抛 DDC 的砖,引 CIC 的玉。 CIC 滤波器原理 单级 CIC 滤波器 设滤波器抽取倍数为 D,则单级滤波器的冲激响应为: 图片 对其进行 z 变换,可得单级 CIC 滤波器的系统函数为: 图片 令 图片 可以看出,单级 CIC 滤波器包括两个基本组成部分:积分部分和梳状部分,结构图如下: 图片 积分器 积分器是一个单级点的 IIR(Infinite Impulse Response,无限长脉冲冲激响应)滤波器,且反馈系数为 1,其状态方程和系统函数分别为: 图片 图片 梳状器 梳状器是一个 FIR 滤波器,其状态方程和系统函数分别为: 图片 图片 抽取器 在积分器之后,还有一个抽取器,抽取倍数与梳状器的延时参数是一致的。利用 z 变换的性质进行恒等变换,将抽取器移动到积分器与梳状器之间,可得到单级 CIC 滤波器结构,如下所示。 图片 参数说明 CIC 滤波器结构变换之前的参数 D 可以理解为梳状滤波器的延时或阶数;变换之后,D 的含义 变为抽取倍数,而此时梳状滤波器的延时为 1,即阶数为 1。 很多学者会引入一个变量 M,表示梳状器每一级的延时,此时梳妆部分的延时就不为 1 了。那么梳状器的系统函数就变为: 图片 其实把 DM 整体理解为单级滤波器延时,或者抽取倍数,也都是可以的。可能实现的方式或结构不同,但是最后的结果都是一样的。本次设计中,单级滤波器延时都为 M=1,即抽取倍数与滤波延时相同。 多级 CIC 滤波器 单级 CIC 滤波器的阻带衰减较差,为了提高滤波效果,抽取滤波时往往会采用多级 CIC 滤波器级联的结构。 实现多级直接级联的 CIC 滤波器在设计和资源上并不是最优的方式,需要对其结构进行调整。如下所示,将积分器和梳状滤波器分别移至一组,并将抽取器移到梳状滤波器之前。先抽取再进行滤波,可以减少数据处理的长度,节约硬件资源。 图片 当然,级联数越大,旁瓣抑制越好,但是通带内的平坦度也会变差。所以级联数不宜过多,一般最多 5 级。 CIC 滤波器设计 设计说明 CIC 滤波器本质上就是一个简单的低通滤波器,截止频率为采样频率除以抽取倍数后的一半。输入数据信号仍然是 7.5MHz 和 250KHz,采样频率 50MHz。抽取倍数设置为 5,则截止频率为 5MHz,小于 7.5MHz,可以滤除 7.5MHz 的频率成分。设计参数如下: 输入频率: 7.5MHz 和 250KHz 采样频率: 50MHz 阻带: 5MHz 阶数: 1(M=1) 级数: 3(N=3) 关于积分时中间数据信号的位宽,很多地方给出了不同的计算方式,计算结果也大相径庭。这里总结一下使用最多的计算方式: 图片 其中,D 为抽取倍数,M 为滤波器阶数,N 为滤波器级数。抽取倍数为 5,滤波器阶数为 1,滤波器级联数为 3,取输入信号数据位宽为 12bit,对数部分向上取整,则积分后数据不溢出的中间信号位宽为 21bit。 为了更加宽裕的设计,滤波器阶数如果理解为未变换结构前的多级 CIC 滤波器直接型结构,则滤波器阶数可以认为是 5,此时中间信号最大位宽为 27bit。 积分器设计 根据输入数据的有效信号的控制,积分器做一个简单的累加即可,注意数据位宽。 //3 stages integrator module integrator #(parameter NIN = 12, parameter NOUT = 21) ( input clk , input rstn , input en , input [NIN-1:0] din , output valid , output [NOUT-1:0] dout) ; reg [NOUT-1:0] int_d0 ; reg [NOUT-1:0] int_d1 ; reg [NOUT-1:0] int_d2 ; wire [NOUT-1:0] sxtx = {{(NOUT-NIN){1'b0}}, din} ; //data input enable delay reg [2:0] en_r ; always @(posedge clk or negedge rstn) begin if (!rstn) begin en_r <= 'b0 ; end else begin en_r <= {en_r[1:0], en}; end end //integrator //stage1 always @(posedge clk or negedge rstn) begin if (!rstn) begin int_d0 <= 'b0 ; end else if (en) begin int_d0 <= int_d0 + sxtx ; end end //stage2 always @(posedge clk or negedge rstn) begin if (!rstn) begin int_d1 <= 'b0 ; end else if (en_r[0]) begin int_d1 <= int_d1 + int_d0 ; end end //stage3 always @(posedge clk or negedge rstn) begin if (!rstn) begin int_d2 <= 'b0 ; end else if (en_r[1]) begin int_d2 <= int_d2 + int_d1 ; end end assign dout = int_d2 ; assign valid = en_r[2]; endmodule抽取器设计 抽取器设计时,对积分器输出的数据进行计数,然后间隔 5 个数据进行抽取即可。 module decimation #(parameter NDEC = 21) ( input clk, input rstn, input en, input [NDEC-1:0] din, output valid, output [NDEC-1:0] dout); reg valid_r ; reg [2:0] cnt ; reg [NDEC-1:0] dout_r ; //counter always @(posedge clk or negedge rstn) begin if (!rstn) begin cnt <= 3'b0; end else if (en) begin if (cnt==4) begin cnt <= 'b0 ; end else begin cnt <= cnt + 1'b1 ; end end end //data, valid always @(posedge clk or negedge rstn) begin if (!rstn) begin valid_r <= 1'b0 ; dout_r <= 'b0 ; end else if (en) begin if (cnt==4) begin valid_r <= 1'b1 ; dout_r <= din; end else begin valid_r <= 1'b0 ; end end end assign dout = dout_r ; assign valid = valid_r ; endmodule梳状器设计 梳状滤波器就是简单的一阶 FIR 滤波器,每一级的 FIR 滤波器对数据进行一个时钟延时,然后做相减即可。因为系数为 ±1,所以不需要乘法器。 module comb #(parameter NIN = 21, parameter NOUT = 17) ( input clk, input rstn, input en, input [NIN-1:0] din, input valid, output [NOUT-1:0] dout); //en delay reg [5:0] en_r ; always @(posedge clk or negedge rstn) begin if (!rstn) begin en_r <= 'b0 ; end else if (en) begin en_r <= {en_r[5:0], en} ; end end reg [NOUT-1:0] d1, d1_d, d2, d2_d, d3, d3_d ; //stage 1, as fir filter, shift and add(sub), //no need for multiplier always @(posedge clk or negedge rstn) begin if (!rstn) d1 <= 'b0 ; else if (en) d1 <= din ; end always @(posedge clk or negedge rstn) begin if (!rstn) d1_d <= 'b0 ; else if (en) d1_d <= d1 ; end wire [NOUT-1:0] s1_out = d1 - d1_d ; //stage 2 always @(posedge clk or negedge rstn) begin if (!rstn) d2 <= 'b0 ; else if (en) d2 <= s1_out ; end always @(posedge clk or negedge rstn) begin if (!rstn) d2_d <= 'b0 ; else if (en) d2_d <= d2 ; end wire [NOUT-1:0] s2_out = d2 - d2_d ; //stage 3 always @(posedge clk or negedge rstn) begin if (!rstn) d3 <= 'b0 ; else if (en) d3 <= s2_out ; end always @(posedge clk or negedge rstn) begin if (!rstn) d3_d <= 'b0 ; else if (en) d3_d <= d3 ; end wire [NOUT-1:0] s3_out = d3 - d3_d ; //tap the output data for better display reg [NOUT-1:0] dout_r ; reg valid_r ; always @(posedge clk or negedge rstn) begin if (!rstn) begin dout_r <= 'b0 ; valid_r <= 'b0 ; end else if (en) begin dout_r <= s3_out ; valid_r <= 1'b1 ; end else begin valid_r <= 1'b0 ; end end assign dout = dout_r ; assign valid = valid_r ; endmodule顶层例化 按信号的流向将积分器、抽取器、梳状器分别例化,即可组成最后的 CIC 滤波器模块。 梳状滤波器的最终输出位宽一般会比输入信号小一些,这里取 17bit。当然输出位宽完全可以与输入数据的位宽一致。 module cic #(parameter NIN = 12, parameter NMAX = 21, parameter NOUT = 17) ( input clk, input rstn, input en, input [NIN-1:0] din, input valid, output [NOUT-1:0] dout); wire [NMAX-1:0] itg_out ; wire [NMAX-1:0] dec_out ; wire [1:0] en_r ; integrator #(.NIN(NIN), .NOUT(NMAX)) u_integrator ( .clk (clk), .rstn (rstn), .en (en), .din (din), .valid (en_r[0]), .dout (itg_out)); decimation #(.NDEC(NMAX)) u_decimator ( .clk (clk), .rstn (rstn), .en (en_r[0]), .din (itg_out), .dout (dec_out), .valid (en_r[1])); comb #(.NIN(NMAX), .NOUT(NOUT)) u_comb ( .clk (clk), .rstn (rstn), .en (en_r[1]), .din (dec_out), .valid (valid), .dout (dout)); endmoduletestbench testbench 编写如下,主要功能就是不间断连续的输入 250KHz 与 7.5MHz 的正弦波混合信号数据。输入的混合信号数据也可由 matlab 生成,具体过程参考《并行 FIR 滤波器设计》一节。 module test ; parameter NIN = 12 ; parameter NMAX = 21 ; parameter NOUT = NMAX ; reg clk ; reg rstn ; reg en ; reg [NIN-1:0] din ; wire valid ; wire [NOUT-1:0] dout ; //===================================== // 50MHz clk generating localparam T50M_HALF = 10000; initial begin clk = 1'b0 ; forever begin # T50M_HALF clk = ~clk ; end end //============================ // reset and finish initial begin rstn = 1'b0 ; # 30 ; rstn = 1'b1 ; # (T50M_HALF * 2 * 2000) ; $finish ; end //======================================= // read cos data into register parameter SIN_DATA_NUM = 200 ; reg [NIN-1:0] stimulus [0: SIN_DATA_NUM-1] ; integer i ; initial begin $readmemh("../tb/cosx0p25m7p5m12bit.txt", stimulus) ; i = 0 ; en = 0 ; din = 0 ; # 200 ; forever begin @(negedge clk) begin en = 1 ; din = stimulus[i] ; if (i == SIN_DATA_NUM-1) begin i = 0 ; end else begin i = i + 1 ; end end end end cic #(.NIN(NIN), .NMAX(NMAX), .NOUT(NOUT)) u_cic ( .clk (clk), .rstn (rstn), .en (en), .din (din), .valid (valid), .dout (dout)); endmodule // test仿真结果 由下图仿真结果可知,经过 CIC 滤波器后的信号只有一种低频率信号(250KHz),高频信号(7.5MHz)被滤除了。 但是波形不是非常完美,这与设计的截止频率、数据不是持续输出等有一定关系。 此时发现,积分器输出的数据信号也非常的不规则,这与其位宽有关系。 图片 为了更好的观察积分器输出的数据,将其位宽由 21bit 改为 34bit,仿真结果如下。 此时发现,CIC 滤波器的数据输出并没有实质性的变化,但是积分器输出的数据信号呈现锯齿状,也称之为梳状。这也是梳状滤波器名字的由来。 图片
FPGA&ASIC
刘航宇
4年前
0
1,510
2
2022-08-13
Verilog 实现并行 FIR 滤波器设计
FIR(Finite Impulse Response)滤波器是一种有限长单位冲激响应滤波器,又称为非递归型滤波器。 FIR 滤波器具有严格的线性相频特性,同时其单位响应是有限长的,因而是稳定的系统,在数字通信、图像处理等领域都有着广泛的应用。 目录 FIR 滤波器原理 并行 FIR 滤波器设计 并行设计 仿真结果 附录:matlab 使用 生成输入的混合信号 FIR 滤波器原理 FIR 滤波器是有限长单位冲击响应滤波器。直接型结构如下: 图片 FIR 滤波器本质上就是输入信号与单位冲击响应函数的卷积,表达式如下: 图片 FIR 滤波器有如下几个特性: (1) 响应是有限长序列。 (2) 系统函数在 |z| > 0 处收敛,极点全部在 z=0 处,属于因果系统。 (3) 结构上是非递归的,没有输出到输入的反馈。 (4) 输入信号相位响应是线性的,因为响应函数 h(n) 系数是对称的。 (5) 输入信号的各频率之间,相对相位差也是固定不变的。 (6) 时域卷积等于频域相乘,因此该卷积相当于筛选频谱中各频率分量的增益倍数。某些频率分量保留,某些频率分量衰减,从而实现滤波的效果。 并行 FIR 滤波器设计 设计说明 输入频率为 7.5 MHz 和 250 KHz 的正弦波混合信号,经过 FIR 滤波器后,高频信号 7.5MHz 被滤除,只保留 250KHz 的信号。设计参数如下: 输入频率: 7.5MHz 和 250KHz 采样频率: 50MHz 阻带: 1MHz ~ 6MHz 阶数: 15(N-1=15) 由 FIR 滤波器结构可知,阶数为 15 时,FIR 的实现需要 16 个乘法器,15 个加法器和 15 组延时寄存器。为了稳定第一拍的数据,可以再多用一组延时寄存器,即共用 16 组延时寄存器。由于 FIR 滤波器系数的对称性,乘法器可以少用一半,即共使用 8 个乘法器。 并行设计,就是在一个时钟周期内对 16 个延时数据同时进行乘法、加法运算,然后在时钟驱动下输出滤波值。这种方法的优点是滤波延时短,但是对时序要求比较高。 并行设计 设计中使用到的乘法器模块代码,可参考流水线式设计的乘法器。 为方便快速仿真,也可以直接使用乘号 * 完成乘法运算,设计中加入宏定义 SAFE_DESIGN 来选择使用哪种乘法器。 FIR 滤波器系数可由 matlab 生成,具体见附录。 /*********************************************************** >> V201001 : Fs:50Mhz, fstop:1Mhz-6Mhz, order: 15 ************************************************************/ `define SAFE_DESIGN module fir_guide ( input rstn, //复位,低有效 input clk, //工作频率,即采样频率 input en, //输入数据有效信号 input [11:0] xin, //输入混合频率的信号数据 output valid, //输出数据有效信号 output [28:0] yout //输出数据,低频信号,即250KHz ); //data en delay reg [3:0] en_r ; always @(posedge clk or negedge rstn) begin if (!rstn) begin en_r[3:0] <= 'b0 ; end else begin en_r[3:0] <= {en_r[2:0], en} ; end end //(1) 16 组移位寄存器 reg [11:0] xin_reg[15:0]; reg [3:0] i, j ; always @(posedge clk or negedge rstn) begin if (!rstn) begin for (i=0; i<15; i=i+1) begin xin_reg[i] <= 12'b0; end end else if (en) begin xin_reg[0] <= xin ; for (j=0; j<15; j=j+1) begin xin_reg[j+1] <= xin_reg[j] ; //周期性移位操作 end end end //Only 8 multipliers needed because of the symmetry of FIR filter coefficient //(2) 系数对称,16个移位寄存器数据进行首位相加 reg [12:0] add_reg[7:0]; always @(posedge clk or negedge rstn) begin if (!rstn) begin for (i=0; i<8; i=i+1) begin add_reg[i] <= 13'd0 ; end end else if (en_r[0]) begin for (i=0; i<8; i=i+1) begin add_reg[i] <= xin_reg[i] + xin_reg[15-i] ; end end end //(3) 8个乘法器 // 滤波器系数,已经过一定倍数的放大 wire [11:0] coe[7:0] ; assign coe[0] = 12'd11 ; assign coe[1] = 12'd31 ; assign coe[2] = 12'd63 ; assign coe[3] = 12'd104 ; assign coe[4] = 12'd152 ; assign coe[5] = 12'd198 ; assign coe[6] = 12'd235 ; assign coe[7] = 12'd255 ; reg [24:0] mout[7:0]; `ifdef SAFE_DESIGN //流水线式乘法器 wire [7:0] valid_mult ; genvar k ; generate for (k=0; k<8; k=k+1) begin mult_man #(13, 12) u_mult_paral ( .clk (clk), .rstn (rstn), .data_rdy (en_r[1]), .mult1 (add_reg[k]), .mult2 (coe[k]), .res_rdy (valid_mult[k]), //所有输出使能完全一致 .res (mout[k]) ); end endgenerate wire valid_mult7 = valid_mult[7] ; `else //如果对时序要求不高,可以直接用乘号 always @(posedge clk or negedge rstn) begin if (!rstn) begin for (i=0 ; i<8; i=i+1) begin mout[i] <= 25'b0 ; end end else if (en_r[1]) begin for (i=0 ; i<8; i=i+1) begin mout[i] <= coe[i] * add_reg[i] ; end end end wire valid_mult7 = en_r[2]; `endif //(4) 积分累加,8组25bit数据 -> 1组 29bit 数据 //数据有效延时 reg [3:0] valid_mult_r ; always @(posedge clk or negedge rstn) begin if (!rstn) begin valid_mult_r[3:0] <= 'b0 ; end else begin valid_mult_r[3:0] <= {valid_mult_r[2:0], valid_mult7} ; end end `ifdef SAFE_DESIGN //加法运算时,分多个周期进行流水,优化时序 reg [28:0] sum1 ; reg [28:0] sum2 ; reg [28:0] yout_t ; always @(posedge clk or negedge rstn) begin if (!rstn) begin sum1 <= 29'd0 ; sum2 <= 29'd0 ; yout_t <= 29'd0 ; end else if(valid_mult7) begin sum1 <= mout[0] + mout[1] + mout[2] + mout[3] ; sum2 <= mout[4] + mout[5] + mout[6] + mout[7] ; yout_t <= sum1 + sum2 ; end end `else //一步计算累加结果,但是实际中时序非常危险 reg signed [28:0] sum ; reg signed [28:0] yout_t ; always @(posedge clk or negedge rstn) begin if (!rstn) begin sum <= 29'd0 ; yout_t <= 29'd0 ; end else if (valid_mult7) begin sum <= mout[0] + mout[1] + mout[2] + mout[3] + mout[4] + mout[5] + mout[6] + mout[7]; yout_t <= sum ; end end `endif assign yout = yout_t ; assign valid = valid_mult_r[0]; endmoduletestbench testbench 编写如下,主要功能就是不间断连续的输入 250KHz 与 7.5MHz 的正弦波混合信号数据。输入的混合信号数据也可由 matlab 生成,具体见附录。 `timescale 1ps/1ps module test ; //input reg clk ; reg rst_n ; reg en ; reg [11:0] xin ; //output wire valid ; wire [28:0] yout ; parameter SIMU_CYCLE = 64'd2000 ; //50MHz 采样频率 parameter SIN_DATA_NUM = 200 ; //仿真周期 //===================================== // 50MHz clk generating localparam TCLK_HALF = 10_000; initial begin clk = 1'b0 ; forever begin # TCLK_HALF ; clk = ~clk ; end end //============================ // reset and finish initial begin rst_n = 1'b0 ; # 30 rst_n = 1'b1 ; # (TCLK_HALF * 2 * SIMU_CYCLE) ; $finish ; end //======================================= // read signal data into register reg [11:0] stimulus [0: SIN_DATA_NUM-1] ; integer i ; initial begin $readmemh("../tb/cosx0p25m7p5m12bit.txt", stimulus) ; i = 0 ; en = 0 ; xin = 0 ; # 200 ; forever begin @(negedge clk) begin en = 1'b1 ; xin = stimulus[i] ; if (i == SIN_DATA_NUM-1) begin //周期送入数据控制 i = 0 ; end else begin i = i + 1 ; end end end end fir_guide u_fir_paral ( .xin (xin), .clk (clk), .en (en), .rstn (rst_n), .valid (valid), .yout (yout)); endmodule仿真结果 由下图仿真结果可知,经过 FIR 滤波器后的信号只有一种低频率信号(250KHz),高频信号(7.5MHz)被滤除了。而且输出波形是连续的,能够持续输出。 但是,如红圈所示,波形起始部分呈不规则状态,对此进行放大。 图片 波形起始端放大后如下图所示,可见不规则波形的时间段,即两根竖线之间的时间间隔是 16 个时钟周期。 因为数据是串行输入,设计中使用了 16 组延时寄存器,所以滤波后的第一个正常点应该较第一个滤波数据输出时刻延迟 16 个时钟周期。即数据输出有效信号 valid 应该再延迟 16 个时钟周期,则会使输出波形更加完美。 图片 附录:matlab 使用 生成 FIR 滤波器系数 打开 matlab,在命令窗口输入命令: fdatool。 然后会打开如下窗口,按照 FIR 滤波器参数进行设置。 这里选择的 FIR 实现方法是最小二乘法(Least-squares),不同的实现方式滤波效果也不同。 图片 点击 File -> Export 将滤波器参数输出,存到变量 coef 中,如下图所示。 图片 此时 coef 变量应该是浮点型数据。对其进行一定倍数的相乘扩大,然后取其近似的定点型数据作为设计中的 FIR 滤波器参数。这里取扩大倍数为 2048,结果如下所示。 图片 生成输入的混合信号 利用 matlab 生成混合的输入信号参考代码如下。 信号为无符号定点型数据,位宽宽度为 12bit,存于文件 cosx0p25m7p5m12bit.txt。 clear all;close all;clc; %======================================================= % generating a cos wave data with txt hex format %======================================================= fc = 0.25e6 ; % 中心频率 fn = 7.5e6 ; % 杂波频率 Fs = 50e6 ; % 采样频率 T = 1/fc ; % 信号周期 Num = Fs * T ; % 周期内信号采样点数 t = (0:Num-1)/Fs ; % 离散时间 cosx = cos(2*pi*fc*t) ; % 中心频率正弦信号 cosn = cos(2*pi*fn*t) ; % 杂波信号 cosy = mapminmax(cosx + cosn) ; %幅值扩展到(-1,1) 之间 cosy_dig = floor((2^11-1) * cosy + 2^11) ; %幅值扩展到 0~4095 fid = fopen('cosx0p25m7p5m12bit.txt', 'wt') ; %写数据文件 fprintf(fid, '%x\n', cosy_dig) ; fclose(fid) ; %时域波形 figure(1); subplot(121);plot(t,cosx);hold on ; plot(t,cosn) ; subplot(122);plot(t,cosy_dig) ; %频域波形 fft_cosy = fftshift(fft(cosy, Num)) ; f_axis = (-Num/2 : Num/2 - 1) * (Fs/Num) ; figure(5) ; plot(f_axis, abs(fft_cosy)) ;
FPGA&ASIC
刘航宇
4年前
0
626
2
Verilog教程语句块
顺序块,并行块,嵌套块,命名块,disable
FPGA&ASIC
刘航宇
4年前
0
361
1
ASIC与FPGA设计哪个前景更好
ASIC和FPGA到底选哪个好?两者的流程有什么区别?做FPGA到底有没有必要转ASIC设计……网上经常看到各种关于ASIC与FPGA的问题。 ASIC (Application Specific Integrated Circuit),即专用集成电路,是指应特定用户要求和特定电子系统的需要而设计、制造的集成电路。 FPGA(FieldProgrammable Gate Array),即现场可编程门阵列,它是在PAL(可编程阵列逻辑)、GAL(通用阵列逻辑)等可编程器件的基础上进一步发展的产物,FPGA是一种可以重构电路的芯片,是一种硬件可重构的体系结构,通过编程可以随时改变它的应用场景。 图片 FPGA与ASIC的异同 相同点:本质上都是芯片,FPGA开发严格按照ASIC开发流程,都是集成电路方向。一般来说,一些电子类硬件产品能用FPGA做出来就能用ASIC做出来,基本上两种不同的渠道做出来的东西能够实现相同的功能。 不同点:前者是把做好的网表或者电路代码下载到FPGA中,形成门阵列,产品交付的时候或者用的时候发现问题都可以重新打补丁、更新版本后再正常进行。而ASIC最终要去流片,做成一个芯片,要求更高!设计流程上非常漫长,一般是一年左右一个周期,需要用到多个验证师,因为后期一旦发生问题只能重新去生产,出现的bug比较多或者比较严重,还有可能全部回收,甚至存在赔钱风险。 在ASIC的设计过程中,往往要用到FPGA 进行原型验证。完成FPGA 验证可以说就完成了ASIC 整套流程的50~70%。 FPGA和ASIC的设计流程区别 FPGA设计拥有可重新配置芯片的功能,而ASIC设计一般具备较少的可重新配置芯片功能。 图片 FPGA又称为“万能芯片”,其内部包含大量的可配置单元(基于LUT的Slice),可配置IP(DSP、CMT、PCIe、Serdes等),可配置存储器。用户可以将自己的设计下载到FPGA芯片中就可以快速实现自己的功能,可以快速搭建Demo系统,设计周期短。 ASIC芯片首先要经过代码设计、综合、后端等复杂的设计流程,再经过几个月的生产加工以及封装测试,才能拿到芯片来搭建系统,复杂的原因是除了功能要正确之外,各种功耗、面积都要达到一个极致,整个设计周期很长。 不同情况选择哪种设计比较好 考虑到时间问题, ASIC设计流程漫长,大概一年左右一个周期,而FPGA设计一般几个星期或者一两个月就能完成,如果想快速看到成效选择FPGA设计会比较好。 在性能方面,ASIC设计出来的芯片比较好,完整的定制,性能更加稳定。ASIC (Application Specific Integrated Circuit)本身就是一种专用集成电路芯片。用一个比较形象的比喻,电影公司要做尤达大师的模型,方案一:买几箱乐高积木,用搭积木的方式来制作,快速解决问题。方案二:联系模具厂,画图纸开模,大规模生产。FPGA设计出的是积木堆积起来的尤达大师,ASIC设计出的是一次定型的尤达大师,后者更为稳定。 图片 涉及设计成本,ASIC设计完成一般会花费几百万到几个亿不等,但如果产量多,那么单块ASIC芯片成本就会低,特别便宜的芯片还有2块左右的;而FPGA设计完成有时候几百块钱就能搞定,如果产量多那单块成本就摆在这了,最后也是一笔巨资。所以,小批量生产和使用用FPGA设计比较占优势,反之大批量生产和使用ASIC占优势。 其实,国内很多公司刚开始市场发展还不稳定时,都是用的FPGA设计;当有了一定市场和抗风险能力后,才开始用ASIC设计。 FPGA工程师是否有必要转ASIC设计工程师 虽然FPGA工程师目前行情发展也不错,但是很多人在考虑转ASIC设计工程师。 一方面,国内目前FPGA工程师相对来说比较多,很多人在学校时基本上通过几千块买一块FPGA板就可以自己开发,自己就能创造出一个实训环境;而ASIC设计工程师相对来说非常缺乏,因为学校目前无法搭建出一个成熟的实训环境,无法做IC设计,很多人对这方面的知识也比较匮乏。所以,是去做大多数人都会的东西还是做只有少数人会的东西更有前途,答案可想而知。 另一方面,结合目前实际情况来看,还有比较直观的一点就是ASIC设计比FPGA设计工资要高,天花板也要高很多。 原来做FPGA的人一般对于verilog也会比较熟,转ASIC还是非常有优势的,趁着现在年纪不大,处于学习黄金期,基本只要稍微学一下就会了,转起来也是比较快的。
FPGA&ASIC
刘航宇
4年前
0
1,128
1
2022-07-15
【Verilog】创建12小时时钟的计数器
题目描述 创建一组适合用作12小时时钟的计数器(带有am / pm指示器)。您的计数器由快速运行的时钟提供时钟,每当您的时钟增加(即每秒一次)时,便会在ena上产生一个脉冲。 重置将时钟重置为12:00 AM。 pm对于AM是0,对于PM是1。 hh,mm和ss是两个BCD(二进制-编码的十进制数字分别代表小时(01-12),分钟(00-59)和秒(00-59)。Reset的优先级比enable的优先级高。 以下时序图显示了从11:59:59 AM到12:00:00 PM的过渡行为以及同步复位和启用行为。 图片 请注意,11:59:59 PM前进至12:00:00 AM,12:59:59 PM前进至01:00:00 PM。没有00:00:00。从图中知道,hh、mm、ss都是8位二进制数,且分为前四位和后四位,如果前四位满足了要求,后四位就加一个数;8位都满足了要求,就复位。 解答 module top_module( input clk, input reset, input ena, output pm, output [7:0] hh, output [7:0] mm, output [7:0] ss); wire [3:0] enable; assign enable[0] = ena; assign enable[1] = ena & (ss==8'h59); assign enable[2] = ena & (ss==8'h59) & (mm==8'h59); assign enable[3] = ena & (hh==8'h11) & (ss==8'h59) & (mm==8'h59); count60 second (clk,reset,enable[0],ss); count60 minute (clk,reset,enable[1],mm); count12 hour (clk,reset,enable[2],hh); count2 halfday (clk,reset,enable[3],pm); endmodule module count12( input clk, input reset, input ena, output [7:0] q); always @(posedge clk) begin if (reset) q <= 8'h12; else if (ena) begin if (q == 8'h12) q <= 8'h1; else if (q[3:0] == 4'h9) begin q[3:0] <= 0; q[7:4] <= 1; end else q[3:0] <= q[3:0] + 1; end else q <= q; end endmodule module count60( input clk, input reset, input ena, output [7:0] q); always @(posedge clk) begin if (reset) q <= 0; else if (ena) begin if (q == 8'h59) q <= 0; else if (q[3:0] == 4'h9) begin q[3:0] <= 0; q[7:4] <= q[7:4] + 1; end else q[3:0] <= q[3:0] + 1; end else q <= q; end endmodule module count2( input clk, input reset, input ena, output q); always @(posedge clk) begin if (reset) q <= 0; else if (ena) begin if (q < 1'b1) q <= q + 1; else q <= 0; end else q <= q; end endmodule
FPGA&ASIC
刘航宇
4年前
1
1,289
1
2022-07-14
[Verilog]ASIC/FPGA实现边沿检测电路(上升/下降沿)
目录 1、什么是边沿检测 2、采用1级触发器的边沿检测电路设计(以下降沿为例)2.1、设计方法 2.2、Verilog实现 2.3、RTL电路 2.4、Testbench 2.5、仿真结果 3、采用2级触发器的边沿检测电路(以下降沿为例)3.1、设计方法 3.2、Verilog实现 3.3、RTL电路 3.4、Testbench 3.5、仿真结果 4、参考文献 1、什么是边沿检测 边沿检测用于检测信号的上升沿或下降沿,通常用于使能信号的捕捉等场景。 2、采用1级触发器的边沿检测电路设计(以下降沿为例) 2.1、设计方法 设计波形图如下所示: 图片 各信号说明如下: sys_clk:基准时钟信号(这里设定为50MHz,周期20ns) sys_rst_n:低电平有效的复位信号 in:输入信号,需要对其进行下降沿检测 ~in:输入信号的反相信号 in_d1:对输入信号寄存一拍 in_neg:得到的下降沿指示信号,该信号为 ind1 && ~in 对上图进行分析: 信号in是我们需要对其进行下降沿检测的信号 信号~in是将信号in反向 信号in_d1是使用寄存器寄存in信号,即对其进行打拍,或者说是同步到系统时钟域下 输入信号开始为高电平,在L2处变为低电平,产生第1个下降沿,在L5出产生第2个下降沿 A处为产生的第1个下降沿指示信号,B处为产生的第2个下降沿指示信号 由此我们可以推导出边沿检测信号产生的一般方法: 将需要检测的信号寄存一拍,同步到系统时钟域下,得到信号 in_d1 将需要检测的信号反向,得到信号 ~in 将信号 in_d1 反向,得到信号 ~in_d1 通过组合逻辑电路可以得到下降沿信号 in_neg:assign in_neg = ~in && in_d1 同样通过组合逻辑电路可以得到上升沿信号 in_pos:assign in_pos = in && ~in_d1 双边沿检测就是将上两条加(或运算)起来就可以了,化简后有:双边沿信号 in_both = in ^ ind1 2.2、Verilog实现 根据上文分析不难编写Verilog代码如下: //使用1级寄存器的下降沿检测电路 module detect_1 ( input sys_clk, //时钟(设定为 50MHz) input sys_rst_n, //复位信号(n 表示低电平有效) input in, //需要进行下降沿检测的输入信号 output in_neg //输出的下降沿指示信号 ); //reg 定义 reg in_d1; //寄存一拍的信号 assign in_neg = ~in && in_d1; //组合逻辑得到下降沿 //上升沿: assign in_pos = in && ~in_d1; //双边沿: assign in_pos = in ^ in_d1; //寄存模块,将输入信号打一拍 always@(posedge sys_clk or negedge sys_rst_n)begin if(!sys_rst_n) in_d1 <= 1'b0; //复位清零 else in_d1 <= in; //寄存一拍 end endmodule2.3、RTL电路 图片 上图为生成的RTL电路:该电路由一级D触发器+与逻辑门构成。 2.4、Testbench Testbench文件需要例化刚刚设计好的模块,并设置好激励。 `timescale 1ns/1ns //时间刻度:单位1ns,精度1ns module tb_detect_1(); //仿真模块 //输入reg 定义 reg sys_clk; reg sys_rst_n; reg in; //输出wire定义 wire in_neg; //设置初始化条件和输入激励 initial begin sys_clk = 1'b0; //初始时钟为0 sys_rst_n <= 1'b0; //初始复位 in <= 1'b0; //初始化输入信号 /*****以下部分为设置的激励,以产生2个下降沿*******/ #10 //10个时间单位后 sys_rst_n <= 1'b1; //拉高复位(此时复位无效) in <= 1'b1; //拉高输入 #20 //20个时间单位后 in <= 1'b0; //拉低输入,制造第1个下降沿 #80 //80个时间单位后 in <= 1'b1; //拉高输入 #60 //60个时间单位后 in <= 1'b0; //拉低输入,制造第2个下降沿 end //always代表重复进行,#10代表每10个时间单位 //每10个时间单位反转时钟,即时钟周期为20个时间单位(20ns) always #10 sys_clk = ~sys_clk; //例化被测试模块 detect_1 detect_1_inst ( .sys_clk (sys_clk ), .sys_rst_n (sys_rst_n ), .in (in), .in_neg (in_neg) ); endmodule 2.5、仿真结果 使用ModelSim执行仿真,仿真出来的波形如所示: 图片 从波形图可以看到: 10ns后停止复位 在第1条参考线处输入信号 in 产生了第1个下降沿信号 在第3条参考线处输入信号 in 产生了第2个下降沿信号 在第1条参考线和第2条参考线之间的产生了一个周期的下降沿指示信号 in_neg 在第3条参考线和第4条参考线之间的产生了一个周期的下降沿指示信号 in_neg 3、采用2级触发器的边沿检测电路(以下降沿为例) 3.1、设计方法 设计波形图如下所示: 图片 各信号说明如下: sys_clk:基准时钟信号(这里设定为50MHz,周期20ns) sys_rst_n:低电平有效的复位信号 in:输入信号,需要对其进行下降沿检测 in_d1:对输入信号寄存1拍 in_d2:对输入信号寄存2拍 ~in_d1:in_d1信号的反相信号 in_neg:得到的下降沿指示信号,该信号为 ~ind1 && ind2 对上图进行分析: 信号in是我们需要对其进行下降沿检测的信号 信号in_d1是使用寄存器寄存in信号,即对其打1拍 信号in_d2是使用寄存器寄存in_d1信号,即对其打1拍 信号~in_d1是将信号in_d1反向 输入信号开始为高电平,在L2处变为低电平,产生第1个下降沿,在L5出产生第2个下降沿 A处为产生的第1个下降沿指示信号,B处为产生的第2个下降沿指示信号 输出的下降沿指示信号落后下降沿一个时钟周期,这是因为对输入信号进行了寄存以消除亚稳态 由此我们可以推导出边沿检测信号产生的一般方法: 将需要检测的信号分别寄存1拍、2拍,同步到系统时钟域下,得到信号 in_d1、in_d2 将in_d1信号反向,得到信号 ~in_d1 将in_d2信号反向,得到信号 ~in_d2 通过组合逻辑电路可以得到下降沿信号 in_neg:assign in_neg = ~in_d1 && in_d2 同样通过组合逻辑电路可以得到上升沿信号 in_pos:assign in_pos = in_d1 && ~in_d2 双边沿检测就是将上两条加(或运算)起来就可以了,化简后有:双边沿信号 in_both = in_d1 ^ in_d2 3.2、Verilog实现 根据上文分析不难编写Verilog代码如下: //使用1级寄存器的下降沿检测电路 module detect_2 ( input sys_clk, //时钟(设定为 50MHz) input sys_rst_n, //复位信号(n 表示低电平有效) input in, //需要进行下降沿检测的输入信号 output in_neg //输出的下降沿指示信号 ); //reg 定义 reg in_d1; //寄存1拍的信号 reg in_d2; //寄存2拍的信号 assign in_neg = ~in_d1 && in_d2;//组合逻辑得到下降沿 //上升沿: assign in_pos = in && ~in_d1; //双边沿: assign in_pos = in ^ in_d1; //寄存模块,将输入信号打1拍、打2拍 always@(posedge sys_clk or negedge sys_rst_n)begin if(!sys_rst_n)begin in_d1 <= 1'b0; //复位清零 in_d2 <= 1'b0; end else begin in_d1 <= in; //寄存1拍 in_d2 <= in_d1; //寄存2拍 end end endmodule3.3、RTL电路 图片 上图为生成的RTL电路:该电路由2级D触发器+与逻辑门构成。 3.4、Testbench Testbench文件同2.4章。 3.5、仿真结果 使用ModelSim执行仿真,仿真出来的波形如所示: 图片 从波形图可以看到: 10ns后停止复位 在第1条参考线处输入信号 in 产生了第1个下降沿信号 在第4条参考线处输入信号 in 产生了第2个下降沿信号 在第2条参考线和第3条参考线之间的产生了一个周期的下降沿指示信号 in_neg 在第5条参考线和第6条参考线之间的产生了一个周期的下降沿指示信号 in_neg 两级寄存器构成的边沿检测电路可以有效的防止亚稳态的产生,产生的使能信号会落后一个时钟周期。 4、参考文献 【从零开始走进FPGA】你想干嘛——边沿检测技术 FPGA的边沿检测 FPGA基础入门篇(四) 边沿检测电路
FPGA&ASIC
刘航宇
4年前
0
2,628
1
【Verilog】卡诺图到电路Karnaugh Map to Circuit
目录 问题描述一问题解答 问题描述二问题解答 问题描述三问题解答 问题描述一 具有四个输入 (a,b,c,d) 的单输出数字系统在输入出现 2、7 或 15 时产生逻辑 1,当输入出现 0、1、4、5、6、9、10、13或14 时产生逻辑 0 。数字 3、8、11 和 12 的输入条件从未出现在此系统中。例如,7 对应于分别设置a,b,c,d为0、1、1、1。确定最小SOP形式的输出out_sop,以及最小POS形式的输出out_pos。 问题解答 (1)根据题意可以画出如下卡诺图: 图片 (2)随后进行卡诺图的化简: 最小SOP:采用圈1法,如图中蓝色和绿色实线所示,合并标1的最小项,即。 最小POS:采用圈0法,如图中红、黄、深蓝色虚线所示,合并标0的最小项,得到$L=c d+\bar{a} \bar{b} c$ 通过将该逻辑表达式进行化简,可以得到。$L=c \cdot(\bar{b}+\bar{c}+d) \cdot(\bar{a}+\bar{c}+d)$ 得到该卡诺图的逻辑表达式后,便可以开始编写verilog代码。 module top_module ( input a, input b, input c, input d, output out_sop, output out_pos ); assign out_sop = (c&d)|(~a&~b&c); //sop assign out_pos = c&(~b|~c|d)&(~a|~c|d); //pos endmodule问题描述二 得出下面卡诺图中显示的函数 f。 图片 问题解答 采用圈0法,如下图所示。 图片 合并标0的最小项,得到$\bar{L}=\overline{x_{1}} \overline{x_{3}}+\overline{x_{3}} \overline{x_{4}}+x_{1} \overline{x_{2}}+x_{1} x_{3}$将该表达式化简,可以得到:$L=\left(x_{1}+x_{3}\right) \cdot\left(x_{3}+x_{4}\right) \cdot\left(\bar{X}_ {1}+x_{2}\right) \cdot\left(\bar{X}_{1}+\bar{X}_{3}\right)$得到该卡诺图的逻辑表达式后,便可以开始编写verilog代码。 module top_module ( input [4:1] x, output f ); assign f = (x[1]|x[3])&(x[3]|x[4])&(~x[1]|x[2])&(~x[1]|~x[3]); endmodule问题描述三 得出下面卡诺图中显示的函数 f。(原试题要求简化 SOP 和 POS 形式的函数。) 图片 问题解答 最小SOP:采用圈1法,如下图所示。 图片 合并标1的最小项,得到$L=\overline{x_{2}} \overline{x_{4}}+\bar{X}_ {1} x_{3}+x_{2} x_{3} x_{4}$ 最小POS:采用圈0法,如下图所示。 图片 合并标0的最小项,得到$\bar{L}=\overline{x_{3}} \overline{x_{4}}+x_{2} \overline{x_{3}}+x_{1} x_{2} \overline{x_{4}}+x_{1} \overline{x_{2}} x_{4}$,通过化简该逻辑表达式,可以得到:$L=\left(x_{3}+\overline{x_{4}}\right) \cdot\left(\overline{x_{2}}+x_{3}\right) \cdot\left(\overline{x_{1}}+\overline{x_{2}}+x_{4}\right) \cdot\left(\overline{x_{1}}+x_{2}+\overline{x_{4}}\right)$得到该卡诺图的逻辑表达式后,便可以开始编写verilog代码。 module top_module ( input [4:1] x, output f ); //assign f = (~x[2]&~x[4])|(~x[1]&x[3])|(x[2]&x[3]&x[4]); //sop assign f = (x[3]|~x[4])&(~x[2]|x[3])&(~x[1]|~x[2]|x[4])&(~x[1]|x[2]|~x[4]); //pos endmodule
FPGA&ASIC
刘航宇
4年前
0
923
1
2022-07-06
【IC设计】数字IC设计流程及学习指南
IC的设计过程可分为两个部分,前端设计(也称逻辑设计)和后端设计(也称物理设计)并没有统一严格的界限,涉及到与工艺有关的设计就是后端设计。 目录 数字IC设计流程1. 规格制定 2. 详细设计 3. HDL编码 4. 仿真验证 5. 逻辑综合――Design Compiler5.1. STA 5.2. 形式验证 技能图解 1.语言 2.基础知识 3.设计工具 4.相关岗位 数字IC设计流程 1. 规格制定 芯片规格,也就像功能列表一样,是客户向芯片设计公司(称为Fabless,无晶圆设计公司)提出的设计要求,包括芯片需要达到的具体功能和性能方面的要求。 2. 详细设计 Fabless根据客户提出的规格要求,拿出设计解决方案和具体实现架构,划分模块功能。目前架构的验证一般基于SystemC语言,对构架模型的仿真可以使用SystemC的仿真工具。其中典型的例子是Synopsys公司的CoCentric和Summit公司的Visual Elite等。 3. HDL编码 使用硬件描述语言(VHDL,Verilog HDL,业界公司一般都是使用后者)将模块功能以代码来描述实现,也就是将实际的硬件电路功能通过HDL语言描述出来,形成RTL(寄存器传输级)代码。 设计输入工具:具有强大的文本编辑功能,多种输入方法(VHDL,Verilog,状态转移图,模块图等),语法模板,语法检查,自动生产代码和文档等功能。如Active-HDL,VisualVHDL/Verilog等。 RTL分析检查工具:Synopsys LEDA 4. 仿真验证 仿真验证就是检验编码设计的正确性,检验的标准就是第一步制定的规格。看设计是否精确地满足了规格中的所有要求。规格是设计正确与否的黄金标准,一切违反,不符合规格要求的,就需要重新修改设计和编码。 设计和仿真验证是反复迭代的过程,直到验证结果显示完全符合规格标准。 仿真验证工具Synopsys的VCS,Mentor ModelSim,Cadence Verilog-XL,Cadence NC-Verilog。 5. 逻辑综合――Design Compiler 仿真验证通过,进行逻辑综合。逻辑综合的结果就是把设计实现的HDL代码翻译成门级网表netlist。综合需要设定约束条件,就是你希望综合出来的电路在面积,时序等目标参数上达到的标准。逻辑综合需要基于特定的综合库,不同的库中,门电路基本标准单元(standard cell)的面积,时序参数是不一样的。所以,选用的综合库不一样,综合出来的电路在时序,面积上是有差异的。 一般来说,综合完成后需要再次做仿真验证(这个也称为后仿真,之前的称为前仿真)逻辑综合工具Synopsys的Design Compiler(DC),Cadence的 PKS,Synplicity的Synplify等。另外,和综合工具配合使用的还有很多其他工具,如静态时间分析工具,等效性检查工具等等。Synopsys公司和Cadence公司都提供完整的工具包。 5.1. STA Static Timing Analysis(STA),静态时序分析,这也属于验证范畴,它主要是在时序上对电路进行验证,检查电路是否存在建立时间(setup time)和保持时间(hold time)的违例(violation)。这个是数字电路基础知识,一个寄存器出现这两个时序违例时,是没有办法正确采样数据和输出数据的,所以以寄存器为基础的数字芯片功能肯定会出现问题。STA工具有Synopsys的Prime Time。 5.2. 形式验证 这也是验证范畴,它是从功能上(STA是时序上)对综合后的网表进行验证。常用的就是等价性检查(Equivalence Check)方法,以功能验证后的HDL设计为参考,对比综合后的网表功能,他们是否在功能上存在等价性。这样做是为了保证在逻辑综合过程中没有改变原先HDL描述的电路功能。形式验证工具有Synopsys的Formality。前端设计的流程暂时写到这里。从设计程度上来讲,前端设计的结果就是得到了芯片的门级网表电路。 技能图解 图片 1.语言 主流的Verilog、VHDL Verilog语言与软件语言最大的区别就是,因为它是用于描述电路的,因此它的写法是非常固定的,因为电路的变化是非常有限的。学习Verilog的时候,很多时候我们并不是在学习这门语言本身,而是学习其对应的电路特征,以及如何对这个电路进行描述。如果心中没有电路,那么你是不可能写好Verilog的。 VHDL语言的严谨性比Verilog要好,不像Verilog中一样存在大量符合语法却永远无法综合的语句。 SpinalHDL、Myhdl等 SpinalHDL和Chisel师承一脉,都是基于Scala来进行电路描述。其本质上仍旧是HDL而非HLS,在设计之前依旧需要有清晰的电路结构,只不过是在电路描述上更加方便和快捷而已。 目前有一些公司已经应用于FPGA设计中,ASIC应用还有待探究。 SpinalHDL资料: https://spinalhdl.github.io/SpinalDoc-RTD/master/index.html SystemVerilog/SystemC : 这两种语言都是为了验证而存在的,掌握基本的验证方法学有助于提高自己的debug效率,SystemVerilog是一种面向对象的语言,其设计的本意是用于搭建验证平台,主流的UVM方法也都是基于SystemVerilog实现的,所以立志成为IC验证工程师的同学,SystemVerilog的深入学习和流行方法论的学习都是必不可少的。 而对于那些只想做IC设计的同学而言,SystemVerilog同样也是值得学习的。且不说本文前面提到的用于提高验证效率的debug方法,即使只是为了做好设计,SystemVerilog也是大有用武之地。很多顶级的IC设计公司内部都开始使用SystemVerilog进行RTL设计了。 由于在SystemVerilog中加入了很多类似always_ff、always_comb等用于显式表明综合电路意图的新语法,代码的可读性更高,综合过程中也减少了歧义,尽可能地保证了综合结果与设计意图的一致性。从另一个角度来说,assertion的加入也极大地提高了代码的debug效率,非常有助于在大规模的数据交互过程中定位到出错的初始点,没有掌握的同学可以多花一些时间学习一下。 -> SV基础知识 脚本语言:Makefile/Perl/Python/Shell Makefile/Perl/Python/Shell都是常用的脚本语言,进行批量修改文本内容,实现自动化操作等,掌握一门得心应手的脚本语言将对工作效率的提升帮助极大。但凡做过一次的事情,就没有必要重复第二次。 -> Perl在IC中的应用 脚本语言:Tcl 在IC设计这个领域中,Tcl是一门非常常见的语言。可以用于描述时序和管脚约束文件,UPF信息,也可以用来搭建简单的工作平台。既是很多EDA工具默认支持的脚本语言,也是这些工具配置和输出的文件格式。因此,能够读懂Tcl,掌握Tcl语言的基本语法,就可以帮助更好的使用EDA工具。 -> 从零开始学Tcl C语言 作为基础语言,在验证时,往往需要用到C写的case; 2.基础知识 数电模电、电路分析、数据结构、计算机体系架构等 AMBA总线 AXI、AHB、APB、CHI、ACE等; -> AMBA总线 高低速接口 PCIE、DMA、DDR、USB、UART、SPI、I2C、MIPI等 -> 总线接口 低功耗设计 动态功耗、静态功耗、常见低功耗设计方法 -> 低功耗设计 静态时序分析 建立时间、保持时间、亚稳态及其解决方法、时序约束 -> 时序约束策略 、亚稳态、 FPGA中的亚稳态 设计方法 乒乓操作、流水线、串并转换、无毛刺切换、状态机等 跨时钟处理:快到慢、慢到快、异步FIFO(FIFO深度计算)等 ->时钟切换电路(Glitch-free clock switching circuit)、异步FIFO、同步FIFO、同步和异步FIFO、FIFO深度计算 3.设计工具 linux系统:linux、shell常见命令 gvim/emac编辑器: 熟练使用Vim/Emacs,用编程的方式来编程,可以提高效率。 版本管理工具:SVN、Git、p4等 版本管理,简而言之,就是一种用于记录和查询文件版本改动的工具; EDA工具 仿真工具:NCVerilog/ VCS/ ModelSim/ iVerilog 以上是比较业界比较主流的仿真工具,其中Icarus Verilog (iVerilog)为开源工具,仿真过程需要了解: 如何指定编译的文件类型; 如何指定编译文件清单; 如何指定索引目录; 如何指定仿真精度; 如何指定临时的宏变量; 如何指定语法检查的严苛等级; 如何混合编译由多种语言写成的工程; 如何调用不同波形生成工具的pli接口; 如何配合SDF反标进行后仿等; -> 芯片后仿及SDF反标、VCS实用技巧、开源verilog仿真工具iverilog+GTKWave 波形查看工具:DVE/ Verdi/ gtkWave 以上是业界比较主流的波形查看工具,所有的波形查看器都必须支持标准波形文件.vcd格式,但是由于.vcd格式的存储性能并不好,冗余信息过多,所以各波形查看工具都纷纷推出了自己支持的波形文件格式,如DVE的.vpd,Verdi的.fsdb,ModelSim的*.wlf; gtkWave也是跨平台的,而且简单易用,支持.vcd标准格式,同时支持高性能压缩格式.lxt和*.fst,gtkWave自带vcd转fst的转换器; 通常几G左右的.vcd格式波形转换为.vpd格式后只有几十MB左右,而转换为.fsdb后通常会更小,因此将标准波形文件.vcd转换为其他压缩格式更加有利于数据备份。 -> fsdb实用技巧、verdi实用技巧 逻辑等效性检查工具:formality-> 形式验证与formality基本流程 从功能上对综合后的网表进行验证,常用的就是等价性检查方法,以功能验证后的HDL设计为参考,对比综合后的网表功能,他们是否在功能上存在等价性。这样做是为了保证在逻辑综合过程中没有改变原先HDL描述的电路功能。 综合工具:dc ->DC综合 逻辑综合就是将HDL代码翻译成门级网表netlist; lint/cdc检查工具:spyglass -> SpyGlass安装教程、spyglass 基础操作、spyglass 常见错误lint 后端:PT、IIC2、innovus等 FPGA综合布线布局工具:synplify/vivado-> ->synplify 基础操作、基于synplify+vivado生成bitfile 其他:VC_static_tools ->VC_static Tools安装教程 4.相关岗位 前端设计 RTL IP设计:从算法协议到RTL coding的能力; SoC设计集成/验证:总线、功耗、系统架构的能力; SOC侧重将IP,模块集成形成一个系统,所以片上互联总线和外设接口是掌握的重点。片内互联总线一般是AMBA总线。外设接口又分为低速接口和高速接口,其中低速接口包括I2C,UART,SPI等,高速接口包括SATA,USB,PCIE,DDR等; 验证 FPGA原型验证:HAPS -> HAPS®-100原型系统、芯片验证技术 |HAPS与高性能ASIC原型验证 UVM验证:SV、UVM主流验证方法学 ->UVM芯片验证 EMU验证:zebu、帕拉丁 -> 芯片验证应用|基于ZeBu平台的虚拟主机应用方案 综合: 逻辑综合就是将HDL代码翻译成门级网表netlist; STA Static Timing Analysis(STA),静态时序分析,它主要是在时序上对电路进行验证,检查电路是否存在建立时间(setup time)和保持时间(hold time)的违例(violation),一个寄存器出现这两个时序违例时,是没有办法正确采样数据和输出数据的,所以以寄存器为基础的数字芯片功能肯定会出现问题。 DFT Design ForTest,可测性设计。芯片内部往往都自带测试电路,DFT的目的就是在设计的时候就考虑将来的测试。DFT的常见方法就是,在设计中插入扫描链,将非扫描单元(如寄存器)变为扫描单元;如bist、Scan Design、JTAG、ATPG等; 后端 物理验证、布线布局、静态时序分析、等价性检查、功耗分析
FPGA&ASIC
# ASIC/FPGA
刘航宇
4年前
0
3,094
9
【9】Verilog练习-串口指令处理器
目录 理论: 代码cmd_pro UART_top 现象 理论: 图片 图片 图片 代码 RX、TX需要与之在相同目录下 cmd_pro //指令处理器 `timescale 1ns/10ps module cmd_pro( clk, res, din_pro, en_din_pro, dout_pro, en_dout_pro, rdy ); input clk; input res; input[7:0] din_pro;//指令和数据输入端口; input en_din_pro;//输入使能; output[7:0] dout_pro;//指令执行结果; output en_dout_pro;//指令输出使能; output rdy;//串口发送模块空闲标志,0表示空闲; parameter add_ab=8'h0a; parameter sub_ab=8'h0b; parameter and_ab=8'h0c; parameter or_ab=8'h0d; reg[2:0] state;//主状态机寄存器(2^3个状态); reg[7:0] cmd_reg,A_reg,B_reg;//存放指令、A和B; reg[7:0] dout_pro; reg en_dout_pro; always@(posedge clk or negedge res) if(~res)begin state<=0;cmd_reg<=0;A_reg<=0;B_reg<=0;dout_pro<=0; en_dout_pro<=0; end else begin case(state) 0://等指令; begin en_dout_pro<=0; if(en_din_pro) begin cmd_reg<=din_pro; state<=1; end end 1://收A; begin if(en_din_pro) begin A_reg<=din_pro; state<=2; end end 2://收B; begin if(en_din_pro) begin B_reg<=din_pro; state<=3; end end 3://指令译码和执行 begin state<=4; case(cmd_reg) add_ab: begin dout_pro<=A_reg+B_reg; end sub_ab: begin dout_pro<=A_reg-B_reg; end and_ab: begin dout_pro<=A_reg&B_reg; end or_ab: begin dout_pro<=A_reg|B_reg; end endcase end 4://发送指令执行结果 begin if(~rdy)begin en_dout_pro<=1; state<=0; end end default:// begin state<=0; en_dout_pro<=0; end endcase end endmoduleUART_top //串口指令处理器 `timescale 1ns/10ps module UART_top( clk, res, RX, TX ); input clk; input res; input RX; output TX; wire[7:0] din_pro; wire en_din_pro; wire[7:0] dout_pro; wire en_dout_pro; wire rdy; UART_Rxer UART_Rxer( .clk(clk), .res(res), .RX(RX), .data_out(din_pro), .en_data_out(en_din_pro) ); UART_TXer UART_TXer( .clk(clk), .res(res), .data_in(dout_pro), .en_data_in(en_dout_pro), .TX(TX), .rdy(rdy) ); cmd_pro cmd_pro( .clk(clk), .res(res), .din_pro(din_pro), .en_din_pro(en_din_pro), .dout_pro(dout_pro), .en_dout_pro(en_dout_pro), .rdy(rdy) ); endmodule //-----testbench of UART_top----- module UART_top_tb; reg clk,res; wire RX; wire TX; reg[45:0] RX_send;//里面装有串口字节发送数据 assign RX=RX_send[0];//连接RX; reg[12:0] con; UART_top UART_top( clk, res, RX, TX ); initial begin clk<=0;res<=0;RX_send<={1'b1,8'h09,1'b0,1'b1,8'h06,1'b0,1'b1,8'h0a,1'b0,16'hffff}; con<=0; #17 res<=1; #4000000 $stop; end always #5 clk<=~clk; always@(posedge clk)begin if(con==5000-1)begin con<=0; end else begin con<=con+1; end if(con==0)begin RX_send[44:0]<=RX_send[45:1]; RX_send[45]<=RX_send[0]; end end endmodule现象 图片
FPGA&ASIC
# ASIC/FPGA
刘航宇
4年前
0
412
2
2022-06-21
【8】Verilog练习-串口数据发送
理论: 图片 图片 代码: //串口发送模块 `timescale 1ns/10ps module UART_TXer( clk, res, data_in, en_data_in, TX, rdy ); input clk; input res; input[7:0] data_in;//准备发送的数据; input en_data_in;//发送使能; output TX;//输出使能 output rdy;//空闲标志,0表示空闲; reg[3:0] state;//主状态机寄存器; reg[9:0] send_buf;//发送寄存器 assign TX=send_buf[0];//连接TX; reg[9:0] send_flag;//用于判断右移结束; reg[12:0] con;//用于计算波特周期 reg rdy; always@(posedge clk or negedge res) if(~res)begin state<=0;send_buf<=1;con<=0;send_flag<=10'b10_0000_0000;rdy<=0; end else begin case(state) 0://等待使能信号; begin if(en_data_in)begin send_buf={1'b1,data_in,1'b0}; send_flag<=10'b10_0000_0000; rdy<=1; state<=1; end end 1://串口发送,寄存器右移; begin if(con==5000-1)begin con<=0; end else begin con<=con+1; end if(con==5000-1)begin send_buf[8:0]<=send_buf[9:1]; send_flag[8:0]<=send_flag[9:1]; end if(send_flag[0])begin rdy<=0; state<=0; end end endcase end endmodule //----testbench of UART_TXer--- module UART_TXer_tb; reg clk,res; reg[7:0] data_in; reg en_data_in; wire TX; wire rdy; UART_TXer UART_TXer( //同名例化; clk, res, data_in, en_data_in, TX, rdy ); initial begin clk<=0;res<=0;data_in<=8'h7f;en_data_in<=0; #17 res<=1; #30 en_data_in<=1; #10 en_data_in<=0; #10000 $stop; end always #5 clk<=~clk; endmodule结果: 图片
FPGA&ASIC
# ASIC/FPGA
刘航宇
4年前
0
491
3
2022-06-15
【7】Verilog练习-串口数据接收
原理: 图片 图片 图片 图片 程序 //串口数据接收 `timescale 1ns/10ps module UART_Rxer( clk, res, RX, data_out, en_data_out ); input clk; input res; input RX; output[7:0] data_out;//接收字节输出; output en_data_out;//输出使能; reg[7:0] data_out; reg[7:0] state;//主状态机; reg[12:0] con;//用于计算比特宽度; reg[3:0] con_bits;//用于计算比特数; reg RX_delay;//RX的延时; reg en_data_out; always@(posedge clk or negedge res) if(~res)begin state<=0;con<=0;con_bits<=0;RX_delay<=0; data_out<=0;en_data_out<=0; end else begin RX_delay<=RX; case(state) 0://等空闲; begin if(con==5000-1)begin //24M/4800=5000 con<=0; end else begin con<=con+1; end if(con==0)begin if(RX)begin con_bits<=con_bits+1; end else begin con_bits<=0; end if(con_bits==12)begin//连续12个1,说明处于空闲状态 state<=1; end end end 1://等起始位; begin en_data_out<=0; if(~RX&RX_delay)begin state<=2; end end 2://收最低位b0;T=5000;1.5T=7500 begin if(con==7500-1)begin con<=0; data_out[0]<=RX; state<=3; end else begin con<=con+1; end end 3://收最低位b1; begin if(con==5000-1)begin con<=0; data_out[1]<=RX; state<=4; end else begin con<=con+1; end end 4://收最低位b2; begin if(con==5000-1)begin con<=0; data_out[2]<=RX; state<=5; end else begin con<=con+1; end end 5://收最低位b3; begin if(con==5000-1)begin con<=0; data_out[3]<=RX; state<=6; end else begin con<=con+1; end end 6://收最低位b4; begin if(con==5000-1)begin con<=0; data_out[4]<=RX; state<=7; end else begin con<=con+1; end end 7://收最低位b5; begin if(con==5000-1)begin con<=0; data_out[5]<=RX; state<=8; end else begin con<=con+1; end end 8://收最低位b6; begin if(con==5000-1)begin con<=0; data_out[6]<=RX; state<=9; end else begin con<=con+1; end end 9://收最低位b7; begin if(con==5000-1)begin con<=0; data_out[7]<=RX; state<=10; end else begin con<=con+1; end end 10://产生使能脉冲 begin en_data_out<=1; state<=1; end default:// begin state<=0; con<=0; con_bits<=0; en_data_out<=0; end endcase end endmodule //----testbench of UART_Rxer-- module UART_Rxer_tb; reg clk,res; wire RX; wire[7:0] data_out; wire en_data_out; reg[25:0] RX_send;//里面装有串口字节发送数据; assign RX=RX_send[0];//连接RX reg[12:0] con; UART_Rxer UART_Rxer( .clk(clk), .res(res), .RX(RX), .data_out(data_out), .en_data_out(en_data_out) ); initial begin clk<=0;res<=0;RX_send<={1'b1,8'haa,1'b0,16'hffff}; con<=0; #17 res<=1; #4000000 $stop; end always #5 clk<=~clk; always@(posedge clk)begin if(con==5000-1)begin con<=0; end else begin con<=con+1; end if(con==0)begin RX_send[24:0]<=RX_send[25:1]; RX_send[25]<=RX_send[0]; end end endmodule现象 图片
FPGA&ASIC
刘航宇
4年前
0
507
3
上一页
1
...
3
4
5
下一页