Skip to content
minichao9901 edited this page Jun 3, 2024 · 64 revisions

如何快速生成例化模板

xilinx::designutils::write_template -template -verilog

verilog代码中增加debug_mark语句(一般放在接口定义前面)

(*mark_debug="true"*)

xsct的一些命令

connect
ta     //list all targets
ta 2   //选择targets 2
help
help ta
jtagterminal -start
mrd 0x00000000 4
mwr 0x50 0x11223344
mrd 0x50
help mwr   //关于写的更多用法
help mrd   //关于读的更多用法

rrd     //读取cpu寄存器组
rrd mpcore   //可以看到所有的cpu内部外设寄存器
rwr     //写cpu寄存器组

rst    //复位
stop   //暂停
con    //继续运行

locals  //查看局部变量
print   //非常强大好用。可以用来print全局变量,print表达式做计算。改变全局变量值等等。

bpadd  //添加断点
bpaddr -addr 0x1000000
bpadd -addr &main
bpadd -file main.c -line 23
bpadd -addr &fooVar -type hw -mode 0x3   //给变量加数据观测点和断点
nxt    //到达breakpoint后,会停止。输入nxt执行下一行
nxt 10000  //往下执行10000行。输入一个很大的值,目的是让其达到下一个breakpoint

在xsct中bpadd添加断点后,再烧录程序,它会在断点的地方停下来。这个时候可以用rrd/mrd观察寄存器组或内存的信息。输入con,让其继续跑下去。

寄存器操作函数(xil_io.h)

#include "xil_io.h"

u8 Xil_In8(UINTPTR Addr)
u16 Xil_In16(UINTPTR Addr)
u32 Xil_In32(UINTPTR Addr)
u64 Xil_In64(UINTPTR Addr)

void Xil_Out8(UINTPTR Addr, u8 Value)
void Xil_Out16(UINTPTR Addr, u16 Value)
void Xil_Out32(UINTPTR Addr, u32 Value)
void Xil_Out64(UINTPTR Addr, u64 Value)

Cache操作函数

DDR访问,一般会关闭Dcache,但速度很慢。 建议使用mmu的设置,对一段内存设置为uncache

#include "xil_cache.h"

void Xil_DCacheEnable(void)
void Xil_DCacheDisable(void)

void Xil_DCacheInvalidate(void)
void Xil_DCacheInvalidateRange(INTPTR adr, u32 len)
void Xil_DCacheFlush(void)
void Xil_DCacheFlushRange(INTPTR adr, u32 len)

adr和len需要32bytes对齐volatile static u8 SrcBuffer[BUFFER_BYTESIZE] __attribute__ ((aligned (64)));
volatile static u8 DestBuffer[BUFFER_BYTESIZE] __attribute__ ((aligned (64)));

#include "xil_mmu.h"
void* Xil_MemMap(UINTPTR PhysAddr, size_t size, u32 flags);
Xil_MemMap(frame_buffer_addr, 800*480*3, NORM_NONCACHE);

测量延时的函数

#include "xtime_l.h"

XTime t1,t2;
function1();
XTime_GetTime(&t1);
function2();
XTime_GetTime(&t2);

int dt = (u32)(t2-t1) * (1000000.0/ COUNTS_PER_SECOND);
xil_printf("dt=%fus\r\n", dt);

不需要的引脚处理

#其余不用的输入/输出可以不分配引脚,并避免报错
set_property IOSTANDARD LVCMOS33 [get_ports *]
set_property SEVERITY {Warning} [get_drc_checks NSTD-1]
set_property SEVERITY {Warning} [get_drc_checks RTSTAT-1]
set_property SEVERITY {Warning} [get_drc_checks UCIO-1]

one_stage_counter

  • trigger by start_pulse
  • 默认是free-running模式
  • 只需要将其中case语句种加注释的一行注释掉,就变成one-time counter
module one_stage_counter;
    reg clk, rst_n;
    initial clk=0;
    always #10 clk=~clk;
    initial begin
        rst_n=0;
        #1000;
        rst_n=1;
    end 
    
    reg start_pulse;
    initial begin
        start_pulse=0;
        wait(rst_n==1);
        #1000;
        start_pulse=1;
        #30;
        start_pulse=0;
    end    
 
    /*********************************************************************************/     
    parameter CNT_MAX=31;
    reg [31:0] div_cnt;
    reg cnt_valid;   
    
    always @(posedge clk or negedge rst_n)
    if(rst_n==0)
        div_cnt<=0;
    else if(add_div_cnt) begin
        if(end_div_cnt)
            div_cnt<=0;
        else
            div_cnt<=div_cnt+1; 
    end 
    
    assign add_div_cnt=cnt_valid;
    assign end_div_cnt=add_div_cnt && (div_cnt==CNT_MAX-1);    
    
    always @(posedge clk or negedge rst_n)
    if(rst_n==0)
        cnt_valid<=0;
    else case(cnt_valid)
        0: if(start_pulse) cnt_valid<=1;
        1: if(end_div_cnt) cnt_valid<=0;  //comment this line, becomes free running counter
    endcase     
    /*********************************************************************************/
    
endmodule 

cascade_counters

  • trigger by start_pulse
  • 默认是free-running模式
  • 只需要将其中case语句种加注释的一行注释掉,就变成one-time counter
module cascade_counters;
    reg clk, rst_n;
    initial clk=0;
    always #10 clk=~clk;
    initial begin
        rst_n=0;
        #1000;
        rst_n=1;
    end 
    
    reg start_pulse;
    initial begin
        start_pulse=0;
        wait(rst_n==1);
        #1000;
        start_pulse=1;
        #30;
        start_pulse=0;
    end
   
    /*********************************************************************************/ 
    parameter CNT_MAX=31;
    parameter LSM_MAX=6;
    reg [31:0] div_cnt;
    reg [5:0] lsm_cnt;
    reg cnt_valid;
    
    always @(posedge clk or negedge rst_n)
    if(rst_n==0)
        div_cnt<=0;
    else if(add_div_cnt) begin
        if(end_div_cnt)
            div_cnt<=0;
        else
            div_cnt<=div_cnt+1; 
    end 
    
    assign add_div_cnt=cnt_valid;
    assign end_div_cnt=add_div_cnt && (div_cnt==CNT_MAX-1);    
        
    always @(posedge clk or negedge rst_n)
    if(rst_n==0)
        lsm_cnt<=0;
    else if(add_lsm_cnt) begin
        if(end_lsm_cnt)
            lsm_cnt<=0; 
        else
            lsm_cnt<=lsm_cnt+1;    
    end
    
    assign add_lsm_cnt=end_div_cnt && cnt_valid;
    assign end_lsm_cnt=add_lsm_cnt && (lsm_cnt==LSM_MAX-1); 
    
    always @(posedge clk or negedge rst_n)
    if(rst_n==0)
        cnt_valid<=0;
    else case(cnt_valid)
        0: if(start_pulse) cnt_valid<=1;
        1: if(end_lsm_cnt) cnt_valid<=0;  //comment this line, becomes free running counter
    endcase     
    /*********************************************************************************/ 
       
endmodule  

clk_rstn_gen

`timescale 1ns / 1ps
module clk_rstn_gen(
    output clk,
    output rst_n,
    output start_pulse
    );
    
    reg clk, rst_n;
    initial clk=0;
    always #10 clk=~clk;
    
    initial begin
        rst_n=0;
        #1000;
        rst_n=1;
    end

    reg start_pulse;
    initial begin
        start_pulse=0;
        wait(rst_n==1);
        #1000;
        @(posedge clk)
        #1 start_pulse=1;
        @(posedge clk)
        #1 start_pulse=0;
    end   
    
endmodule 
`timescale 1ns / 1ps
module clk_rstn_gen_multi(
    output clk,
    output rst_n1,
    output rst_n2,
    output rst_n3      
    );
    
    reg clk;
    reg rst_n1, rst_n2, rst_n3;
    initial clk=0;
    always #10 clk=~clk;
    
    initial begin
        rst_n1=0;
        rst_n2=0;
        rst_n3=0;        
        #10000;
        rst_n1=1;
        #10000;
        rst_n2=1;
        #10000;
        rst_n3=1;
    end   
    
endmodule

例化重新定义参数值

uart_tx uart_tx_inst
(
    .sys_clk(sys_clk),
    .sys_rst_n(sys_rst_n),
    .pi_data(xfer_data),
    .pi_flag(xfer_start),
    .po_ack(xfer_end)
);  
defparam uart_tx_inst.CLK_FREQ= 'd50_000;

融合状态机的新的计数器写法(实现one-time counter)

    /*********************************************************************************/ 
    /* 3) rewrite fsm, result is counter-like fsm */
    /*********************************************************************************/   
    reg [5:0] div_cnt3;
    
    always @(posedge clk or negedge rst_n)
    if(rst_n==0)
        div_cnt3<=0;
    else if(div_cnt3==0 && start_pulse)
        div_cnt3<=1;
    else if(div_cnt3>=1 && div_cnt3<5)
        div_cnt3<=div_cnt3+1;
    else if(div_cnt3==5)
        div_cnt3<=0;     
    
    assign cnt_valid3=(div_cnt3>=1) && (div_cnt3<=5);
    assign end_div_cnt3=(div_cnt3==5);    
    /*********************************************************************************/  

用状态机管理计数器(更好的方法)

无start_pulse

reg [15:0] dly_cnt;
reg [2:0] state;

always @(posedge clk or negedge rst_n)
if(rst_n==0) begin
    dly_cnt<=0;
    state=0;
end
else case(state)
    0:  if(cnt_end) begin
            dly_cnt<=0;
            state<=1;
        end
        else
            dly_cnt<=dly_cnt+1;
    1:  if(cnt_end) begin
            dly_cnt<=0;
            state<=2;
        end
        else
            dly_cnt<=dly_cnt+1;      
  endcase
 
assign cnt_end=(state==0 && dly_cnt==15-1) || (state==1 && dly_cnt==31-1);  

有start_pulse

reg start_pulse;
initial begin
    start_pulse=0;
    wait(rst_n==1);
    @(posedge clk) #1 start_pulse=1;
    @(posedge clk) #1 start_pulse=0; 
end

//1)
reg [15:0] dly_cnt;
reg [2:0] state;

always @(posedge clk or negedge rst_n)
if(rst_n==0) begin
    dly_cnt<=0;
    state=0;
end
else case(state)
    0: if(start_pulse) state<=1;
    1:  if(cnt_end) begin
            dly_cnt<=0;
            state<=2;
        end
        else
            dly_cnt<=dly_cnt+1;
    2:  if(cnt_end) begin
            dly_cnt<=0;
            state<=0;
        end
        else
            dly_cnt<=dly_cnt+1;     
  endcase
 
assign cnt_end=(state==1 && dly_cnt==15-1) || (state==2 && dly_cnt==31-1); 

rom_data的写法

reg [0: 32*(ARG_NMAX-1)-1] rom={
        32'h12345678,
        32'h23456789,
        32'h3456789a,
        32'h456789ab, 
        32'hffabcdef,            
        32'h56789abc,
        32'h6789abcd,
        32'h789abcde,
        32'h89abcdef, 
        32'hffabcdef,
        32'h89abcdef,    
        32'hffabcdef
        };   

reg [31:0] rom_data;
reg [7:0] cmd;
reg [7:0] length;
always @(posedge clk or negedge rst_n)
if(rst_n==0)
    rom_data<=32'h00;
else if(rom_index>=1 && rom_index<ARG_NMAX)
    rom_data<=rom[32*(rom_index-1) +:32]; 

zynq的gpio拆分

`timescale 1ns / 1ps

module gpio_sep(
    output [2:0] GPIO_I,
    input [2:0] GPIO_T,
    input [2:0] GPIO_O,
    
    input gpio_i0,
    input gpio_i1,
    input gpio_i2,
    
    output gpio_t0,
    output gpio_t1,
    output gpio_t2,
   
    output gpio_o0,
    output gpio_o1,
    output gpio_o2
    );
    
    assign GPIO_I={gpio_i2,gpio_i1,gpio_i0};
    assign {gpio_t2,gpio_t1,gpio_t0}=GPIO_T;
    assign {gpio_o2,gpio_o1,gpio_o0}=GPIO_O;       
endmodule

verilog模块参数定义方法

	module axi4_stream_ip_v1_0_S00_AXIS #
	(
		parameter integer C_S_AXIS_TDATA_WIDTH	= 32
	)
	(
		// AXI4Stream sink: Clock
		input wire  S_AXIS_ACLK,
		// AXI4Stream sink: Reset
		input wire  S_AXIS_ARESETN,
		// Ready to accept data in
		output wire  S_AXIS_TREADY,
		// Data in
		input wire [C_S_AXIS_TDATA_WIDTH-1 : 0] S_AXIS_TDATA,
		// Byte qualifier
		input wire [(C_S_AXIS_TDATA_WIDTH/8)-1 : 0] S_AXIS_TSTRB,
Clone this wiki locally