专栏中心

EEPW首页 > 专栏 > Verilog编写实战技巧(一)

Verilog编写实战技巧(一)

发布人:0750long 时间:2010-03-10 来源:工程师 发布文章
Verilog编写实战技巧(一)

 

 

看了很多Altera官方的代码,总结了其中的一些比较好的编写形式和技巧,供大家参考。

信号写法

1.信号选通:

assign write_strobe = write & begintransfer;

 

2.使能信号是多个其他信号的逻辑与

assign control_reg_en = (address == 3'b001) && write && chipselect;

 

3.多级控制信号:三组信号,复合信号用粗体标注。

有些信号会在多处被使用,这样定义信号层次清晰。

assign write_strobe = write & begintransfer;

  assign stop_strobe_0 = (address == 0) && write_strobe;

  assign global_reset = stop_strobe_0 && writedata[0];

global_reset信号等效于下面:

assign global_reset =  (address == 0) &&(write & begintransfer )&& writedata[0];

 

4.表达式也可以给信号赋值

assign counter_is_zero = (internal_counter == 0);         

dma_mem_read_idle <= ((dma_mem_read_idle == 1) & (go == 0)) |

                    ((dma_mem_read_idle == 1) & (p1_done_read == 1)) ;

 

5.信号也可以是多个信号的组合。用{}实现

assign counter_load_value = {period_h_register,period_l_register};

 

6.寄存器的写选通可以通过片选、写信号和寄存器地址信号的逻辑与实现

assign status_wr_strobe = chipselect && ~write_n && (address == 0);

 

7. 将寄存器某几位作为控制信号定义出来,以便使用

  assign reen = control[5];

  assign ween = control[6];

assign leen = control[7];

 

8. 定义一个ram区域

         reg     [ 31: 0] mem_array [ 15: 0];

访问:mem_array[wraddress] <= data;

 

双向数据端口写法

 inout   [ 7: 0] LCD_data;

  assign LCD_data = (address[0]) ? 8'bz : writedata;

  assign readdata = LCD_data;

 

多路选择:

①assign read_mux_out = ({32 {(address == 0)}} & time_counter_0[31 : 0]) |

    ({32 {(address == 1)}} & time_counter_0[63 : 32]) |

    ({32 {(address == 2)}} & event_counter_0) |

    ({32 {(address == 4)}} & time_counter_1[31 : 0]) |

    ({32 {(address == 5)}} & time_counter_1[63 : 32]) |

    ({32 {(address == 6)}} & event_counter_1) |;

 

   ②assign control_readdata_temp = (slave_address == 3'b000)? status_register :

                                               (slave_address == 3'b001)? read_address_register :

                                               (slave_address == 3'b011)? length_register :

                                               (slave_address == 3'b110)? control_register :

                                               (slave_address == 3'b111)? checksum_register : 0;

 

从端口基本写

  always @(posedge clk or negedge reset_n)//always中赋值的变量为reg型,

    begin

      if (reset_n == 0)

          data_out <= 0;

      else if (chipselect && ~write_n && (address == 0))

          data_out <= writedata[15 : 0];

    end

assign out_port = data_out;//把reg型变量连续赋值给wire型变量

 

端口信号

//一个模块与多个其他模块有接口,端口分布时就按与其他模块连接分组,每一小组可以按先输入再输出排序。

module slave (

      // these connect to the clock port

      clk,

      reset,

      // these connect to the slave port

      slave_address,

      slave_read,

      slave_readdata,

      // these connect

      control_go,

      control_done,

      control_fixed_read_address,

      // this connects to the irq sender port

      control_irq

);

 

参数化调用

编写子模块时,尽量多用参数定义,使模块使用场合更灵活多变。

一般在模块端口定义后面紧跟着参数定义。

      parameter ADDRESSWIDTH = 32;

      parameter FIFODEPTH = 32;

      parameter FIFODEPTH_LOG2 = 5;

      localparam OFFSETWIDTH = LOG2(BYTEENABLEWIDTH);

上层模块在例化子模块时,可以对参数进行修改,在例化模块后用deparam

      latency_aware_read_master the_latency_aware_read_master (

             .clk (clk),

             .reset (reset),

             .control_fixed_location (fixed_read_address),  // RCON bit

             .control_read_base (read_address),

      );

      defparam the_latency_aware_read_master.ADDRESSWIDTH = 32;

      defparam the_latency_aware_read_master.FIFODEPTH = 32;

      defparam the_latency_aware_read_master.FIFODEPTH_LOG2 = 5;

 

寄存器写:

现有读选通信号,再在always中将读选通信号作为判断条件

  assign period_l_wr_strobe = chipselect && ~write_n && (address == 2);

  always @(posedge clk or negedge reset_n)

    begin

      if (reset_n == 0)

          period_l_register <= 849;

      else if (period_l_wr_strobe)

          period_l_register <= writedata;

end

 

寄存器读:

先通过多路选择器,在将选中寄存器在always中同步赋值

  assign read_mux_out = ({16 {(address == 2)}} & period_l_register) |

    ({16 {(address == 3)}} & period_h_register) |

({16 {(address == 1)}} & control_register) |);

 

  always @(posedge clk or negedge reset_n)

    begin

      if (reset_n == 0)

          readdata <= 0;

      else if (read)

          readdata <= read_mux_out;

    end

专栏文章内容及配图由作者撰写发布,仅供工程师学习之用,如有侵权或者其他违规问题,请联系本站处理。 联系我们

关键词:

相关推荐

Movellus 发布了首款片上电源网络分析仪

Other World Computing(OWC)将在COMPUTEX展示Thunderbolt 5解决方案

数字孪生技术助力晶圆厂,AI 工厂发展

智能计算 2025-05-20

彻底理解无刷电机

亚信电子与联发科技携手打造AIoT新未来

设计功率器件中的散热考虑

视频 2011-10-17

设计指南-数字电位器

MATLAB EXPO 2025中国用户大会 以软件定义产品共创无限未来

LPC900系列单片机掉电检测应用设计

Pico Technology扩展PicoScope3000E系列,推出入门级混合信号示波器

英特尔发布全新GPU,AI和工作站迎来新选择

英伟达新办公大楼「星座」落地台湾

2025-05-20

设计指南-为什么我们需要斩波放大器

如何选择一个电源模块

视频 2011-10-17

3核A7+单核M0多核异构,米尔全新低功耗RK3506核心板发布

设计指南-低功耗压力传感器

LPC900系列单片机ISP相关FAQ

更多 培训课堂
更多 焦点
更多 视频

技术专区