HDL FPGA 学习 - FPGA基本要素,开发流程,Verilog语法和规范、编写技巧

news2024/11/20 8:48:42

目录

Altera FPGA 基本要素

FPGA 开发流程和适用范围

设计和实施规范

顶层设计的要点

Verilog HDL

语法规范

编写规范

设计技巧


编辑整理 by Staok,始于 2021.2 且无终稿。转载请注明作者及出处。整理不易,请多支持。

本文件是“瞰百易”计划的一部分,尽量遵循“二项玻”定则,致力于与网络上碎片化严重的现象泾渭分明!

本文系广泛撷取、借鉴和整理,适合刚入门的人阅读和遵守,已经有较多经验的人看一看图个乐,如有错误恭谢指出!本文已经是长期积累和堆叠而形成一定规模,不必按照从前到后的顺序去看,可以挑感兴趣的章节去看。

本文为简述风格,本意即记录要点和便于快速拾起。

本文对应的 Github/Gitee 仓库地址,本文最新的原文 和 一些源码、备查手册等等 均放在里面。


Altera FPGA 基本要素

p.s 过于基础的概念不提,这不是入门帖。入门可以跳到 “O.0 值得跟着的学习网站” 章节进行摄入。

p.s 以下以 Cyclone IV E 系列 FPGA 为例。

  • FPGA基础资源选择:逻辑单元(LE)数量,内嵌存储器(M9K)数量(总 RAM Bits 数),乘法器数量,PLL 数量,I/O 数量,全局时钟网络数量等。

  • 板级电路组成:电源,时钟,复位,JTAG,固化配置信息 FLASH,外设。具体连接形式参考一些开发板和开源板子的原理图和 PCB。

    • 电源:核心电源(标识 VCCINT,低压版本 1.0V,非低压 1.2V),IO BANK(标识 VCCIOx(x = 1 到 8),电压 1.2V 到 3.3V),PLL(模拟 PLL 标识 VCCAx(x = 1、2 或 4),其地标识 GNDAx(x 同前),电压 2.5V;数字 PLL 标识 VCCD_PLLx(x = 1、2 或 4),电压 1.2V),外设供电。不同系列 FPGA 的供电措施不同,具体要看电器参数等手册,尽量使用推荐值。
    • 复位:上电后,FPGA 器件开始加载外部 FLASH 芯片的固化信息,加载完毕之后(最多 0.3s)再进行复位(低电平有效),阻容 RC 复位电路可选:R = 47kΩ,C = 10uF,3.3V 的 IO 标准下,充电到 1.7V 时间为 340ms。
  • 全局时钟网络:专用时钟网络走线,同一时钟到达不同寄存器的时间差可以被控制到很小的范围内。外部输入时钟信号要连接到 “全局时钟专用引脚” 上。FPGA 的综合工具会自动识别和分配。

  • I/O:输入和输出时钟信号尽量分配到专用引脚上。差分信号对儿必须分配到支持差分的专用引脚上。高速信号分配到支持高速传输的专用引脚上(如 DDR 的专用 IO 接口)。一些硬核使用的引脚可能是固定的要注意。总线信号尽量分配到同一个 BANK。一些产生噪声干扰的信号(如时钟信号)尽量远离器件的配置喜欢和其它敏感的信号。

  • 调试和固化:

    更多详细参考:

    • FPGA配置方式。
    • FPGA的各种功能管脚。
    • Altera特殊管脚的使用。
    • 官方手册里是最全的、最准的,多看!

    具体看官网手册 “Cyclone IV Device Handbook Volume 1” 的 “Configuration Process” 章节和 “Configuring Altera FPGAs.pdf” 手册。

    • 调试为通过 JTAG 接口用 Blaster 下载器把编译生成的 .sof 文件下载到 FPGA 内掉电易失的 SRAM 中。

    • 固化是通过 JTAG 接口用 Blaster 下载器把编译并转化生成的 .jic 文件下载到 FPGA 对于的外部 FLASH 器件中。FPGA 上电从 FLASH 中获取配置信息,分为几种不同的配置模式,根据 [3:0]MSEL 四个引脚上电时的电平状态确定,而具体的 [3:0]MSEL 与 启动方式的关系 看对应 FPGA 芯片系列型号的手册。配置模式分为以下几种:

      AS(主动串行),适用于小容量。由 FPGA 器件引导配置过程,EPCS 系列 FLASH 专供 AS 模式。一般用此模式。

      AP(主动并行),速度快,占 I/O 更多,适用于大容量 FPGA 器件。EPC 系列 FLASH 用于此。

      PS(被动串行),需要外部 MCU 或 CPLD(如 MAX II 系列)控制 FLASH 的数据打入 FPGA,此方式最灵活,对于多个 FPGA 或者要自动更换固件用此模式。

      assets/被动串行配置方式(PS)详解.jpg

      等其他。

FPGA 开发流程和适用范围

  • 开发流程:需求分析,模块划分,实现,前仿真,分配 IO,时钟信号约束 + 其他信号时序分析和约束,后仿真,下载验证和调试,固化代码(注意是有顺序的)。1.4 Verilog 设计方法 | 菜鸟教程 (runoob.com)。

    fpga开发流程图

  • FPGA 固有灵活性和并行性。FPGA 应用领域列举:逻辑粘合,实时控制,高速信号采集和处理,协议实现,仿真验证系统,片上系统 SoC。

  • 处理器和 FPGA 分工:MCU、MPU 适合做管理、协调,FPGA 的数字逻辑适合做专用的、复杂的、结构和功能固定下来的算法实现。

  • 推荐多去读读 FPGA 原厂(Altera 或 Xilinx)的官方文档,在它们的一些文档手册中有各种常见的电路的参考实现实例和代码风格。

  • 板级 PCB 走线遵循 “PCB走线规范”。

设计和实施规范

这里的规范仅为初级,另有 “HuaWei Verilog 规范” 等规范可供参考。

顶层设计的要点
  1. 单个模块尽量使用一个时钟源;对于多个模块要认真、清楚的划分时钟域;跨时钟域的信号一定做同步处理(D触发器同步);片内的 PLL / DLL 资源尽量利用起来;至少要对所有时钟信号加上简单的时序约束,不能没有。
  2. 数据传递的两边速率不一致要在中间加 缓存机制,常见的如 FIFO 和 乒乓缓存,后者详见 “设计技巧” 小节里的 “乒乓操作” 部分。
  3. 复杂逻辑/时序逻辑要使用 FSM (有限状态机)方式来写,在下面的 “模块收集” 里面有状态机的例子。
  4. 条件逻辑/状态图等一定要遍历所有状态,一定,防止不可预料的错误综合结果,对于 if 要有 else,对于 case 要有 default。
  5. 对于仿真:先对每一个单个模块仿真,要求代码覆盖率、条件分支覆盖率、表达式覆盖率必须达到 100%,这三个可以通过 Modelsim 查看;子系统仿真,将多个模块组合在一起进行仿真,覆盖率尽量高;系统级仿真,软硬件整板联调。仔细设计仿真激励文件。
  6. 通常采用自顶向下的设计方式。先确定系统有哪些输入和输出,把系统划分成多个子功能模块(框图模块),每个功能模块再划分下一层的子模块(HDL 意义上的模块),最后的每个模块的设计对应一个 module ,可以一个 module 设计成一个 verilog HDL 文件。
  7. 在 FPGA 逻辑全编译之前,尽量将全部 顶层 IO 分配给 实体芯片的引脚 而 不要空置,没用到的输入信号也要 assign 到 确定的 0 或 1,这样不但保证 确定的逻辑行为,而且如果不做那么全编译时 Timing 时序 无法保证 从而 亮红。
  8. 工程文件夹划分规范:prj 为工程文件存放目录; rtl 为 verilog 可综合代码存放目录; testbench 为测试文件存放目录; img 为设计相关图片存放目录; doc 为设计相关文档存放目录; prj 文件夹下还建立了子文件夹 ip,用于存放 Quartus Prime 中生成的 IP 核文件。
Verilog HDL
语法规范
  • No.1,层次化设计,IP 化设计。自写小 IP 尽量参数化、可重用,方便日后搭建数字积木。

  • 顶层文件名与顶层模块名一致。

  • 模块的定义名加尾缀"_ module",输入输出的信号名各加后缀"_ in"和"_ out",低电平有效的信号加尾缀"_ n"或“#”,时钟信号使用"clk _“或"Clk _“前缀,复位信号使用"rst _“前缀,使能信号使用"en"或者"Enable"标识等。

  • 定义模块的时候,定义输入输出信号时就带好 “input”/“in” 、 “output”/“out” 和 “reg” 等的标识修饰。

  • 一个 tab 四个空格。

  • 用 tab 划分清晰的语句层次,用 tab 对齐多行同层次语句等。

  • begin 和 end 语句块修饰词在竖方向对齐。

  • 操作符等前后用一个空格做间隔。

  • 注释齐全,对自己和别人负责。

  • 以下用一例子包含 verilog 常用语法。

/* 这里是注释 */
// 还是注释

/*
	Verilog 保留字
	always  and  assign begin  buf  bufif0 bufif1 case  casex  casez  cmos
    deassign  default defparam  disable edge  else  end  endcase  endmodule
    endfunction  endprimitive  endspecify  endtable  endtask  event
    for  force  forever  fork  function  highz0  highz1  if  ifnone
    initial  inout  input  integer join  large  macrmodule  medium  module
    nand  negedge  nmos  nor  not  notif0  notif1 or  output
    parameter pmos  posedge  primitive  pull0  pull1  pullup pulldown
    rcmos  real  realtime  reg  release repeat rnmos rpmos rtran  rtranif0
    rtranif1  scalared  small  specify specparam  strong0 strong1 supply0 supply1
    table  task  time  trantranif0  tranif1 tri  tri0  tri1  triand  trior
    trireg  vectored  wait  wand  weak0 weak1 while  wire  wor  xnor  xor
*/

/*	引用自 https://blog.csdn.net/luxinwylive/article/details/99827766
	(1)所有综合工具都支持的结构:always,assign,begin,end,case,wire,tri,aupply0,supply1,reg,integer,default,for,function,and,nand,or,nor,xor,xnor,buf,not,bufif0,bufif1,notif0,notif1,if,inout,input,instantitation,module,negedge,posedge,operators,output,parameter。
	(2)所有综合工具都不支持的结构:time,defparam,$finish,fork,join,initial,delays,UDP,wait。
	(3)有些工具支持有些工具不支持的结构:casex,casez,wand,triand,wor,trior,real,disable,forever,arrays,memories,repeat,task,while。
*/

/* wire 类型变量定义物理连线,不保存东西,reg 类型变量定义寄存器,用于保存东西 */

/*
 引自 https://zhuanlan.zhihu.com/p/72012739
 wire 用法总结
    1.wire可以在Verilog中表示任意宽度的单线/总线
    2.wire可以用于模块的输入和输出端口以及一些其他元素并在实际模块声明中
    3.wire不能存储值(无状态),并且不能在always @ 块内赋值(=或<=)左侧使用。
    4.wire是assign语句左侧唯一的合法类型(assign 后面跟着的必须是一个 wire 类型)
    5.wire只能用于组合逻辑
 reg 用法总结
    1. 声明寄存器,可以存储信息(有内存,有状态)允许连接到模块的输入端口,但不能连接到一个模块的实例化的输出
    2. 在模块声明中,reg可以用作输出,但不能用作输入
    3. 在always@(......)语句块内,= 或者 <= 赋值语句的左边必须是是reg变量
    在initial语句块内,= 赋值语句的左边必须是是reg变量
    4. Reg不能用于assign赋值语句的左侧
    5. 当与@(posedge clock)块一起使用时,reg可用于创建寄存器
    6. reg可用于组合逻辑和时序逻辑
*/

/* 连续赋值语句(assign)用于对线型变量(wire)的赋值,不能够出现在任何一个过程块(begin ... end)中;连续赋值语句(assign)定义组合逻辑,声明物理逻辑的关系;线型变量一旦被连续赋值语句赋值后,赋值语句右端表达式中的信号有任何变化,都将实时地反映到左端的线型变量中 */

/* 过程赋值语句(= 和 <=)完成对寄存器变量(reg)的赋值,只能在过程块语句中被赋值;过程赋值语句只有在语句被执行到时,赋值过程才能够进行一次,而且赋值过程的具体执行时间还受到各种因素的影响 */

/*
	数据类型:
	5'o37		5 位八进制数,二进制为 11111
	10'o37		右对齐,高位补 0
	10'bx0x1 	左边补 x,完整即 x x x x x x x 0 x 1,x 表示未知状态
	4'b1x_01	4 位二进制数,为 1 x 0 1,下划线方便阅读
	4'hz  		4 位z(扩展的z) , 即 zzzz,z 表高阻状态
	parameter SEC_TIME = 48_000_000; 十进制数
	位长不能够为变量表达式,可以为预编译、parameter 的表达式

	verilog 中 整形、浮点型等变量的 定义字 相当于 define 或者 parameter 的作用,这里只用 后二者即可了

	字符串
	reg [8*14 : 1]Message = "INTERNAL ERROR"; I 为第 1 位,N 为 第 2 位,依此类推

	数组
	reg [wordsize : 0]my_memory[arraysize : 0];
	引用数组某个数的某个位
	my_memory_1 = my_memory[1];
	my_memory_1_bit0 = my_memory_1[0];
      verilog 不支持 数组作为 模块的输入或输出,systemVerilog 支持

	运算;
	算术运算符(+,-,x,/,%)
	赋值运算符(=,<=)
	关系运算符(>,<,>=,<=)
    逻辑运算符(&&,||,!)
    条件运算符(?;)
    位运算符 (~,|,^,&,^~) 
      对于 & 运算用法之一:assign max_avl_address = &avl_address; 
       则 avl_address 最大(全1)的时候 max_avl_address 为 1,否则为 0
    移位运算符(<<,>>)
    拼接运算符({})
*/

/*
	预编译:

	宏定义:`define WIDTH 8
	引用:reg [`WIDTH-1:0] s1;  原样替换

	`ifdef 宏名 (标识符)
          程序段1
    `else
          程序段2
    `endif
*/

/*
 for 语句,尽量不要用,要使用 计数器 + case 语句 来替代
 https://blog.csdn.net/messi_cyc/article/details/79098444
*/

/*
 使用语句实现 边沿检测
 https://blog.csdn.net/bleauchat/article/details/85322247
*/

/* 模块注释规范 */
/**
  *******************************************************************************************************
  * File Name    : xxx.v
  * Author       : xxx
  * Version      : V1.0.0
  * Date         : 20xx-xx-xx
  * Brief        : xxxxx
  *******************************************************************************************************
  * History
  *		1.Author: xxx
  *		  Date: 20xx-xx-xx
  *		  Mod: xxxxx
  *
  *		2.Author: xxx
  *		  Date: 20xx-xx-xx
  *		  Mod: xxxxx
  *
  *******************************************************************************************************
  */

// *********************************************************************************
// Project Name :       
// Author       : xxx
// Email        : 
// Blogs        : 
// File Name    : xxx.v
// Module Name  :
// Called By    :
// Abstract     :
//
// CopyRight(c) 2018-2021, xxx Studio.. 
// All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date         By              Version                 Change Description
// -----------------------------------------------------------------------
// xxxx/xx/xx    xx       		1.0                     Original
//  
// *********************************************************************************
module example_module
(
    /*输入信号*/
    input clk_in,             /*时钟输入*/
    input rst_n_in,           /*复位(低有效)信号输入*/

    /*输出信号*/
    output reg [7:0]q_out,    /*q 左移位输出,要用语句块赋值,所以定义为 寄存器类型 */
    output reg [7:0]p_out     /*p 右移位输出*/

    /* 寄存器组定义 reg [7:0]Mem[0:1] 即 2 个 8 位的 Mem*/

    output output_1 = 0,output_2  /* 缺省为 wire 线网类型,可以定义初始值 */
    /* tri 主要用于定义三态的线网 */

);
    /* 定义常量参数 */
    parameter  bit_7 = 7,bit_8 = 8;

    /* 三目运算例子 
      wire [2:0] Student = Marks > 18 ? Grade_A : Grade_C;
      assign LR = (LR_select[1] == 1'b1) ? 1'bz : LR_select[0];
    */

    /* 时序逻辑定义,对 q 左移位输出*/
    always @(posedge clk_in or negedge rst_n_in)
        begin
            /* 顺序执行 */
            if(!rst_n_in)
                begin
                    q_out <= 8'bzzZz_0001; /* 总线赋值 */
                end
            else
                begin
                    q_out <= { q_out[6:0] , q_out[bit_7] }; /* 使用位拼接,左移位 */
                end
        end

    /*对 p 右移位输出*/
    always @(posedge clk_in or negedge rst_n_in)
        begin
            if(rst_n_in == 1'b0)
                begin
                    p_out <= 8'b1000_0000;
                end
            else
                begin
                    p_out <= { p_out[0] , p_out[7:1] }; /* 使用位拼接,右移位 */
                end
        end

    /* 在模块里面调用模块,即 FA_struct 模块例化,并建立连接 */
    FA_struct FA1(
        .A (q_out[1]),
        .B (p_out[1]),
      .C (rst_n_in),
        .output_1(),	/* 该引脚悬空,如果是 example_module 模块的输入则变为高阻,如果是输出则弃用 */ 
      .output_2(output_2)
     );

endmodule

/* case 语句例子
case(case_expr)
    case item_expr : procedural_statement;
    . . .
    . . .
    [default:procedural_statement]
endcase
*/

/* 门级描述组合逻辑电路 */
module FA_struct
(
    input A;
    input B;
    input C;

	output output_1;
	output output_2;
);
    /* 模块内连线 */
    wire S1, T1, T2, T3;

    xor x1 (S1, A, B);
    xor x2 (output_1, S1, C);
    and A1 (T3, A, B );
    and A2 (T2, B, C);
    and A3 (T1, A, C);
    or O1 (output_2, T1, T2, T3 );

endmodule

/*
	一个参数化模块设计例子
	定义:
module Sdram_Write
#(  parameter   DATA_WIDTH  =   16,		注,#() 这个部分用于模块参数化配置,对于 verilog 不可综合
    parameter   ADDR_WIDTH  =   12,
    parameter   ROW_DEPTH   =   2,
    parameter   COL_DEPTH   =   256,
    parameter   BURST_LENGTH =   4,       //burst length
    parameter   ACT_DEPTH    =  1,
    parameter   BREAK_PRE   =   1
)
(
    input                       clk,
    input                       rst_n,
    input                       wr_trig,
    input                       wr_en,
    input                       ref_rq,
    output          reg [3:0]   wr_cmd,
    output          reg [ADDR_WIDTH - 1:0]  wr_addr,
    output                       wr_rq,
    output          reg         wr_end_flag,
    output              [1:0]   wr_bank_addr,
    output              [DATA_WIDTH - 1:0]  wr_data,
    //wfifo
    output                       wfifo_rd_en,
    input               [7:0]    wfifo_rd_data
);
	例化:
Sdram_Write
#(  .DATA_WIDTH             ('d16),
    .ADDR_WIDTH             ('d12),
    .ROW_DEPTH              ('d1),
    .COL_DEPTH              ('d4),
    .BURST_LENGTH           ('d4),       //burst length
    .ACT_DEPTH              ('d1),
    .BREAK_PRE              ('d1) 
)
Sdram_Write_inst(
    .clk                    (clk),
    .rst_n                  (rst_n),
    .wr_trig                (wr_trig),
    .wr_en                  (wr_en),
    .ref_rq                 (ref_rq),
    .wr_cmd                 (wr_cmd),
    .wr_addr                (wr_addr),
    .wr_rq                  (wr_rq),
    .wr_end_flag            (wr_end_flag),
    .wr_bank_addr           (wr_bank_addr),
    .wr_data                (wr_data),
    .wfifo_rd_en            (wfifo_rd_en),
    .wfifo_rd_data          (wfifo_rd_data)
);

*/
编写规范
  • 以时钟信号同步的时序逻辑编写时尽量只用非阻塞赋值”<="(同步执行),用阻塞赋值”="(顺序执行)可能会产生bug,后者一般用于组合逻辑设计。尽量避免使用异步信号(比如异步总线等),即慎用或少用 assign 语句连接逻辑,而尽量把所有逻辑在 always @(*) begin … end 中实现;如果传入一个异步信号,尽量加寄存器(D触发器)用时钟进行锁存。

  • 尽量大部分功能使用时序逻辑电路设计,使用行为语句 + 时序逻辑电路描述(“always@” + “<=”) 完成建模(对于 reg 类型变量)。对于组合逻辑电路描述,简单逻辑可以使用连续赋值语句(“assign” + “=”)(对于 wire 类型变量),对于复杂组合逻辑使用 “always@( 所有敏感信号 )” + “=” 的语句。

  • Always 块的一般形式为:

    /* 这里加注释对该模块进行功能描述 */
    always @(negedge clk_in or negedge i2s_module_rst) /* 在时钟的边沿触发,再加一个复位触发条件 */
        begin
            if(!i2s_module_rst) /* 先判断是否复位 */
                begin /* 在复位块中,因该对 else 情况里面的所有 被幅值的 reg 变量进行 复位,都设置为复位值,必要! */
                    WS <= 1'b1; /* 添加语句描述 */
                end
            else
                begin /* 保持格式 */
                    if(one_flame_counter < half_flame_count)
                        begin
                            WS <= 1'b0;
                        end
                    else
                        begin
                            WS <= 1'b1;
                        end
                end
        end
    
  • case 语句必须带 default 分支,照顾到 case 的所有情况;if 语句必须带 else 分支;即分支语句要 写到/考虑 所有情况。

  • 所有的内部寄存器都应该能够被复位,尽量每个模块都要有时钟同步复位信号(不要用异步复位)。

  • 设计逻辑尽量避免不定态 x 或者高阻态 z 进入参与关键逻辑区域,仿真时就注意。

  • 移位操作直接用位拼接。

  • 同一个信号在很多地方使用,比如参数和时钟等等,应该在每一个用到的地方加一个寄存器(D触发器)用于中继缓冲,避免一个信号扇出信号数量过多。

  • 常用的,时钟上升沿锁存数据,时钟下降沿改变数据。

  • 从可综合性角度考虑,应慎用各种循环语句(for,while 等,因为编译器仅将其展开成重复语句,过多占用逻辑),大部分情况下,用于设计的循环语句可以用其他方式所替代,比如用 case 语句替代循环语句。并行块(fork … join)不可综合且容易出现竞争问题,在仿真设计中不建议使用。

  • 逻辑表达式不要写的太长,可以简化逻辑(卡诺图法或者公式法,或者 multisim 里面的逻辑分析仪简化逻辑表达式)或者分多行去写,即不要让 RTL 图中某一段逻辑链过于长;长逻辑表达式用括号划分清关系减少歧义。

  • 竞争与冒险的概念:逻辑电路中,由于门的输入信号经过不同的延时,到达门的时间不一致,这种情况叫竞争;由于竞争而导致输出产生毛刺(瞬时错误),这一现象叫冒险。为避免组合逻辑的输出出现“毛刺”,即冒险或竞争的发生,可以在输出加一个寄存器(D触发器),即让输出与时钟同步,当所有信号都到达寄存器(D 触发器)的输入后,时钟再“打一拍” 进行锁存 才能输出,这样避免最后的输出有“毛刺”;避免锁存器,使用触发器。

  • 对于有 选择 和 加法、比较 等逻辑块,编写时应让信号先经过 选择器,再送入 乘法器、加法器 或 比较器 等,即“先选后比,先选后加,先选后乘”。逻辑电路面积大小对比:乘法器 > 加法器 > 比较器 > 选择器。

  • 尽量不要用减法和除法(一个考虑多,一个面积大);乘以常数直接用 “*”,编译器会优化;两变量乘法用硬件乘法器IP。

  • 使用 function 函数语句对复杂数值运算打包(它不能包含任何时间控制语句);函数(function)可以调用其他函数(function)但不能调用任务(task),(function)函数由 任务(task)或其它 module 中调用。使用 task 语句写可重用的、固定下来的组合逻辑(不能有时序逻辑 always,不能有 wire 类型数据,这就是和 module 的区别;任务(task)可以调用其他任务(task)和函数(function),任务(task)只能在 module 中的语句块中被调用)。

  • 可以用 generate for 写 同结构不同参数 的 always@(*) 等代码,用 generate if/case 写一些随着需求可变的代码或 IP 核。 generate 语句属于预编译语句。

  • FGPA 的功耗与被使用的触发器或门电路的数量及其翻转次数成正比,尽量减少高速翻转的触发器数量是降低 FPGA 功耗的根本方法之一。

设计技巧

p.s 以下内容引自 信息理论与技术教研中心 别志松 的 PPT 《复杂数字系统设计的常用技巧》,本文作者又做了一些补充。

解决速度与面积矛盾的基本原则:1、向关键路径要速度。对于关键路径,可以采用牺牲面积换取速度的方式。2、向非关键路径要面积。对于非关键路径,通过各种方式换取面积。

基本途径:1、EDA工具的约束和优化方式的设置。2、优化代码。以下就是代码优化的一些方法。

速度的三重定义

  • Throughput:吞吐量
    • 单位时间内能处理的数据量。
    • 常用单位有bit/s,等。
  • Latency:时延
    • 指的是从数据输入到达至相应数据输出之间的时间。
    • 单位是微秒等。
  • Timing:时序
    • 指的是时序单元之间的路径所对应的时延。
    • 通常说时序关系不满足一般指触发器间关键路径的最大时延超过目标时钟周期。
    • 标准度量是时钟周期或频率。

速度的三个方面的折中

  • Latency 换 Throughput。
  • Timing 换 Throughput。
  • Timing 换 Latency 等。

提高吞吐量的方法

  • 流水线技术

    流水线技术就是把本来只能在一个较长的时钟周期内执行的操作(组合逻辑)分成几步较小的操作,并在多个较高速的时钟内完成。这些步骤的划分是通过多级寄存器来实现的。前级寄存器处理新输入数据的同时,末级寄存器产生老输入数据所对应的输出。

  • 多路并行处理

    将耗时较长的电路复制若干份,每份处理部分数据。这种处理方法需要对输入数据进行分解,对输出数据进行合并。主要用于减小 Latency。

减小延时的主要思想

  • 尽快将数据从输入传递到输出,减小中间过程处理时延,即减少数据处理链的长度。
  • 流水线技术不符合低 Latency 的要求。经常采用的方法:
    • 并行处理。
    • 去掉流水线。
  • 减小 Latency 的代价:有可能减少吞吐量;会造成关键路径时延增大。
  • 既要保证 Throughput,又要保证较小的 Latency,只能采取前述并行处理方法。

改善时序性能的方法

即提高最高运行速度。

  • 添加中间寄存器层。流水线化。防止中间纯组合逻辑链太长导致延时太长,即防止一个语句特别长运算特别多,所以中间添加寄存器层。

    将多数据的数学运算分为多个运算的组合,这些组合是并行处理的。

  • 关键路径改造为并行结构。并行处理。减少串入串出,增加输入和输出的数量,写为并入并出。

  • 展平逻辑结构。也是增加并行。

  • 减小扇出。

面积优化方法

  • 精简代码。引用上面“编写规范”一节:
    • 对于有选择和加法、比较等逻辑块,编写时应让信号先经过选择器,再送入乘法器、加法器或比较器等,即“先选后比,先选后加,先选后乘”。面积:乘法器 > 加法器 > 比较器 > 选择器。
    • 不使用除法和减法。等等等等。
  • 资源共享。
    • 模块化。声明会被高利用率的寄存器。
    • 等。
  • 合理使用复位信号。

乒乓操作

“乒乓操作” 是一个常常应用于数据流控制的处理技巧。数据缓冲模块可以为 单\双口 RAM、FIFO 等。向缓冲区 1 存数据的时候,缓冲区 2 向外出数据,向缓冲区 2 存数据的时候,缓冲区 1 向外出数据,以此循环。

assets/乒乓操作示意图.png

  • 乒乓操作的最大特点是通过 “输入数据选择单元 ”和 “输出数据选择单元” 按节拍、相互配合的切换,将经过缓冲的数据流没有停顿地送到 “数据流运算处理模块” 进行运算与处理。
  • 把乒乓操作模块当做一个整体,站在这个模块的两端看数据,输入数据流和输出数据流都是连续不断的,没有任何停顿,因此非常适合对数据流进行流水线式处理。
  • 所以乒乓操作常常与流水线结合使用,完成数据的无缝缓冲与处理。

乒乓缓存的实施

  1. 两个单口 RAM 方式。设计一个 MUX 模块,输入为一个类似 SRAM 接口,其后面控制两个单口 RAM(外部 SRAM 芯片 或 FPGA 内建 RAM),输出一个 类似 SRAM 接口芯片和 通知可读的信号(通知后面,一个 RAM 块已经写满可以快速读出)。
  2. 一个双口 RAM 方式。设计一个 MUX 模块,输入接口同上,其 后面控制 一个 双口 RAM(外部芯片或 FPGA 内建),MUX 模块的输入数据就不断循环 从地址 0 到最大地址 存进该 RAM,当存到一半的时候 输出一个 通知可读信号,即当 前半部分 存满后 可以读前半部分(此时 MUX模块正在后半部分存),当后半部分存满后可以读后半部分(此时 MUX模块又回到前半部分地址开始存),这样 一个 双口 RAM 的前后两半作为两块 RAM 进行乒乓操作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1469259.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何正确设置CrossOver之偏好设置 crossover软件使用 crossover设定 crossover软件安装

CrossOver的核心是Wine&#xff0c;Wine是一个能在多种POSIX-compliant操作系统&#xff08;如&#xff1a;Linux、Mac OS等&#xff09;上运行Windows应用的兼容层。Wine不是Windows的模拟工具&#xff0c;它是把Windows API 调用翻译成为动态的 POSIX 调用&#xff0c;实现Li…

东方博宜 1086. 姐妹数对

东方博宜 1086. 姐妹数对 思路&#xff1a;先按照题意把规律找出来&#xff0c;按照规律再写程序。 #include<iostream> using namespace std; int main() {int n ;cin >> n ;int sum 0 ;for(int i 1 ; i < n ; i){for(int j i1 ; j < n ; j){int m ;m …

Linux配置jdk、tomcat、mysql离线安装与启动

目录 1.jdk安装 2.tomcat的安装&#xff08;开机自启动&#xff09; 3.MySQL的安装 4.连接项目 1.jdk安装 上传jdk安装包 jdk-8u151-linux-x64.tar.gz 进入opt目录&#xff0c;将安装包拖进去 解压安装包 这里需要解压到usr/local目录下&#xff0c;在这里我新建一个文件夹…

Git的基本操作和原理

目录 写在前面的话 为什么要有Git&#xff08;git初识&#xff09;&#xff1f; Git安装(Centos为例) Git基本操作 创建Git本地仓库 Git配置 认识工作区、暂存区、版本库 概念认识 添加文件 查看.git文件 修改文件 版本回退 撤销修改 情况一&#xff1a;…

【办公类-22-06】周计划系列(1)“信息窗” (2024年调整版本)

作品展示 调用原来的信息窗素材&#xff0c;制作下学期的19周的信息窗基础word 背景需求&#xff1a; 开学了&#xff0c;继续做周计划系列&#xff0c;在原有基础上&#xff0c;进行进一步代码优化 【办公类-22-01】周计划系列&#xff08;1&#xff09;-生成“信息窗”&am…

供应链大数据:穿越经济迷雾的指南针

随着经济形势的变幻莫测&#xff0c;企业运营面临着前所未有的挑战。在这个充满不确定性的时代&#xff0c;供应链大数据如同一盏明亮的指南针&#xff0c;为企业提供精准的方向指引。下面&#xff0c;我们将深入探讨供应链大数据如何帮助企业洞察市场趋势、优化库存管理、降低…

K线实战分析系列之八:十字星——容易识别的特殊形态

K线实战分析系列之八&#xff1a;十字星——容易识别的特殊形态 一、十字启明星和十字黄昏星二、弃婴底部形态和弃婴顶部形态三、总结十字启明星和十字黄昏星形态的要点 一、十字启明星和十字黄昏星 当开盘价与收盘价极为接近的时候&#xff0c;当期的K线就呈现为一根十字线&am…

PyPDF2:项目实战源码分享(PDF裁剪)

目录&#x1f4d1; 1. 背景&#x1f4d1;2. 源码模块解析&#x1f4d1;2.1 读取PDF页数2.2 获取指定页的宽高尺寸2.3 裁剪单页PDF2.4 批量裁剪PDF 总结&#x1f4d1; 1. 背景&#x1f4d1; 接PyPDF2模块推荐博文中提到的实际需求&#xff08;将银行网站下载来的多页且单页多张…

设计模式--单例模式--懒汉饿汉

单例模式 单例模式(Singleton)&#xff0c;保证一个类仅有一个实例&#xff0c;并提供一个访问它的全局访问点。 单例模式 通常我们可以让一个全局变量使得一个对象被访问&#xff0c;但它不能防止你实例化多个对象。一个最好的办法就是&#xff0c;让类自身负责保存它的唯一实…

[嵌入式系统-34]:RT-Thread -19- 新手指南:RT-Thread标准版系统架构

目录 一、RT-Thread 简介 二、RT-Thread 概述 三、许可协议 四、RT-Thread 的架构 4.1 内核层&#xff1a; 4.2 组件与服务层&#xff1a; 4.3 RT-Thread 软件包&#xff1a; 一、RT-Thread 简介 作为一名 RTOS 的初学者&#xff0c;也许你对 RT-Thread 还比较陌生。然…

vue-element-admin如何绕开系统的请求的路由,使用静态路由

我开发时候遇到一个这样的问题&#xff0c;服务端权限管理部分还没搞好&#xff0c;所以但是需要将所有菜单列出来 我做了以下的修改 首先是建一个文件存放后期需要动态生成的路由 引入到常量路由中 另外在permissions当中

FPGA之16:1复选器

每个slice 都有一个F8MUX。F8MUX原语&#xff1a; MUXF8 MUXF8_inst&#xff08; .0&#xff08;0&#xff09;&#xff0c;Il Output of MUX to general routing .I0&#xff08;10&#xff09;&#xff0c;//Input&#xff08;tie to MUXF7L/LO out&#xff09; .I1&#xf…

This dependency was not found解决方法

问题如上(前端代码)&#xff0c;我是引用js文件出的问题&#xff0c;无法找到api/userManage模块。 解决&#xff1a;没感觉哪有问题&#xff0c;把后面加了个/&#xff0c;就解决了&#xff0c;代表src目录&#xff0c;应该是目录和目录之间应该有/作为分割&#xff1a;

vue3+js 实现记住密码功能

常见的几种实现方式 1 基于spring security 的remember me 功能 ​​​​​​​ localStorage 除非主动清除localStorage 里的信息 &#xff0c;不然永远存在&#xff0c;关闭浏览器之后下次启动仍然存在 存放数据大小一般为5M 不与服务器进行交互通信 cookies 可以…

C++ //练习 8.4 编写函数,以读模式打开一个文件,将其内容读入到一个string的vector中,将每一行作为一个独立的元素存于vector中。

C Primer&#xff08;第5版&#xff09; 练习 8.4 练习 8.4 编写函数&#xff0c;以读模式打开一个文件&#xff0c;将其内容读入到一个string的vector中&#xff0c;将每一行作为一个独立的元素存于vector中。 环境&#xff1a;Linux Ubuntu&#xff08;云服务器&#xff09…

【Java程序设计】【C00314】基于Springboot的足球俱乐部管理系统(有论文)

基于Springboot的足球俱乐部管理系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的足球俱乐部管理系统的设计与实现&#xff0c;本系统有管理员以及用户二种角色权限 管理员权限操作的功能包括管理公告&#x…

C语言实现简单选择排序

简单选择排序 简单选择排序的平均复杂度为 O(n2),但效率通常比相同平均复杂度的直接插入排序还要差。但由于选择排序是 内部排序&#xff0c;因此在内存严格受限的情况下还是可以用的。选择排序的原理很简单&#xff0c;如下图所示&#xff1a;持续从未处理元素中找到最小值并加…

使用命令行创建文件夹和文件

创建文件夹 md 文件夹名字 创建文件 echo >文件名字.后缀然后回车即可 注意点:echo >文件名字.后缀 的 >后面不可以加空格&#xff0c;不然会报错\

16. BI - 推荐系统之 ALS 实现

本文为 「茶桁的 AI 秘籍 - BI 篇 第 16 篇」 文章目录 对 MovieLens 进行电影推荐 Hi,你好。我是茶桁。 前面两节课的内容中&#xff0c;我们从矩阵分解到 ALS 原理&#xff0c;依次给大家讲解了推荐系统中的一个核心概念。 矩阵分解中拆矩阵的背后其实是聚类。就说 k 等于几…

YOLOv8重磅升级!新增旋转目标检测功能

YOLOv8重磅升级&#xff01;新增旋转目标检测功能&#xff0c;基于DOTA数据集&#xff0c;支持15个类别目标航拍图像检测&#xff0c;模型&代码均已开源~ 新版亮点 YOLOv8-OBB&#xff1a;YOLOv8中OBB(Oriented Bounding Box)模型的引入标志着物体检测的重要一步&#xff…