原创 Verilog编写实战技巧(一)

2010-3-8 10:36 3957 3 3 分类: FPGA/CPLD

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


信号写法<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />


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

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
3
关闭 站长推荐上一条 /3 下一条