AXI_BVALID/AXI_BREADY的异步处理

本文探讨了AXI协议中AXI_BVALID和AXI_BREADY信号的异步处理,强调了保持信号周期一致性和握手关系的重要性。通过使用计数器、格雷码转换以及双时钟域同步,实现有效的信号传输。同时,文中指出在目标时钟域的计数器接近满时,需要提前拉低A_AXI_BREADY以预留同步时间。测试表明,该方法在不同时钟周期下均能正确工作。

AXI_BVALID/AXI_BREADY的异步处理

AXI_BVALID/AXI_BREADY的异步处理本质上是单比特信号的异步处理,但其对持续总cycle数也需要保持一致。并且需要考虑到VALID/READY的握手关系。

思路是用一个计数器对源时钟域的A_AXI_BVALID&A_AXI_BREADY做计数,然后转换成格雷码,再同步到目标时钟域去,再转换成顺序计数码,在目标时钟域根据B_AXI_BREADY生成对应的B_AXI_BVALID。同时需要注意把目标时钟域的计数器反过来同步到源时钟域,判断存储的bvalid个数即将满的时候把A_AXI_BREADY拉低,需要预留一定的反向同步时间。

以下是RTL代码:

module bvalid_sync(

input  a_axi_rstn,
input  a_axi_clk,
input  a_axi_bvalid,
output a_axi_bready,

input  b_axi_rstn,
input  b_axi_clk,
input  b_axi_bready,
output b_axi_bvalid
);

reg [3:0] cnt_a_axi_bvalid;
always @ (posedge a_axi_clk)
begin
  if (a_axi_rstn == 0)
    cnt_a_axi_bvalid <= 'd0;
  else if (a_axi_bvalid & a_axi_bready)
    cnt_a_axi_bvalid <= cnt_a_axi_bvalid + 'd1;
end

function [3:0] bin2gray; 
input [3:0] data_bin;
begin
bin2gray[3] = data_bin[3];
bin2gray[2] = data_bin[3]^data_bin[2];
bin2gray[1] = data_bin[2]^data_bin[1];
bin2gray[0] = data_bin[1]^data_bin[0];
end
e
`timescale 1ns / 1ps module dma_ctrl( input wire clk , // output ui_clk input wire rst_n , // output ui_clk_sync_rst //wr_fifo input wire wf_wr_clk , input wire wf_wr_en , input wire [15:0] wf_wr_data , //rd_fifo input wire rf_rd_clk , input wire rf_rd_en , output wire rf_rd_req , output wire [15:0] rf_rd_data , // 写地址通道 output wire [3:0] s_axi_awid ,//写地址主机ID号,当只有一个从机一个主机时,该信号为0即可/ output reg [27:0] s_axi_awaddr ,//写地址通道地址; output wire [7:0] s_axi_awlen ,//突发长度/ output wire [2:0] s_axi_awsize ,//突发大小/ output wire [1:0] s_axi_awburst ,//突发类型:固定、递增、回绕。/ output wire [0:0] s_axi_awlock ,//总线锁信号,从没使用过,信号一般默认为 0;/ output wire [3:0] s_axi_awcache ,//缓存模式:一般使用的是无缓存模式,一般默认 4'b0;/ output wire [2:0] s_axi_awprot ,//没用,全给 0/ output wire [3:0] s_axi_awqos ,//没用,全给 0/ output reg s_axi_awvalid ,//地址的有效信号,主机发出; input wire s_axi_awready ,//从机发出/ //写数据通道 output wire [127:0] s_axi_wdata ,//写数据信号/ output wire [15:0] s_axi_wstrb ,//字节有效信号,1 为有效/ output reg s_axi_wlast ,//最后一个数据有效信号/ output reg s_axi_wvalid ,//数据有效信号/ input wire s_axi_wready ,//从机发出 //写响应通道 input wire [3:0] s_axi_bid ,//从机发出,和 awid 匹配/ input wire [1:0] s_axi_bresp ,//写响应操作信号,指明数据状态,从机发出,返回 2"b0 表示成功响应/ input wire s_axi_bvalid ,//从机发出,表示响应有效/ output wire s_axi_bready ,//主机发出,一般直接拉高/ //读地址通道 output wire [3:0] s_axi_arid ,//读地址主机 ID 号,当只有一个从机一个主机时,该信号为0即可/ output reg [27:0] s_axi_araddr ,//读地址通道地址/ output wire [7:0] s_axi_arlen ,//突发长度/ output wire [2:0] s_axi_arsize ,//突发大小/ output wire [1:0] s_axi_arburst ,//突发类型:0:固定、1:递增、回绕。 output wire [0:0] s_axi_arlock ,//总线锁信号,从没使用过,信号一般默认为 0;/ output wire [3:0] s_axi_arcache ,//缓存模式:一般使用的是无缓存模式,一般默认 4'b0;/ output wire [2:0] s_axi_arprot ,//没用,全给 0/ output wire [3:0] s_axi_arqos ,//没用,全给 0/ output reg s_axi_arvalid ,//地址的有效信号,主机发出/ input wire s_axi_arready ,//从机发出/ //读数据通道 input wire [3:0] s_axi_rid ,//和 arid 匹配,从机发出/ input wire [127:0] s_axi_rdata ,//读数据信号,从机发出/ input wire [1:0] s_axi_rresp ,//读数据响应信号,从机发出/ input wire s_axi_rlast ,//最后一个数据有效信号,从机发出/ input wire s_axi_rvalid ,//读数据有效信号,从机发出/ output wire s_axi_rready //主机发出 ); localparam burst_len = 31;//突发长度 localparam HSYNC = 1280, VSYNC = 720 ; localparam axi_addr = 512;//burst_len * 2^s_axi_arsize localparam pic_data0 = HSYNC * VSYNC * 2,//一帧数据的大小 pic_data1 = HSYNC * VSYNC * 4; localparam IDLE = 6'b000_001, WR_ADDR = 6'b000_010, WR_DATA = 6'b000_100, WR_RES = 6'b001_000, RD_ADDR = 6'b010_000, RD_DATA = 6'b100_000; // 写地址通道 assign s_axi_awid = 4'b0 ; assign s_axi_awlen = burst_len; assign s_axi_awsize = 3'b100 ;//2^4 = 16 assign s_axi_awburst = 2'b01 ; assign s_axi_awlock = 0 ; assign s_axi_awcache = 0 ; assign s_axi_awprot = 0 ; assign s_axi_awqos = 0 ; //写数据通道 assign s_axi_wstrb = 16'hff_ff; //写响应通道 assign s_axi_bready = 1; //读地址通道 assign s_axi_arid = 4'b0 ; assign s_axi_arlen = burst_len; assign s_axi_arsize = 3'b100 ; assign s_axi_arburst = 2'b01 ; assign s_axi_arlock = 0 ; assign s_axi_arcache = 0 ; assign s_axi_arprot = 0 ; assign s_axi_arqos = 0 ; //读数据通道 assign s_axi_rready = 1; //state reg [5:0] curr_state,next_state; wire [7:0] wf_data_cnt;//写FIFO计数 wire [7:0] rf_data_cnt;//读FIFO计数 reg [7:0] wr_data_cnt;//写数据计数 wire wf_rd_en; wire rf_wr_en; assign wf_rd_en = s_axi_wvalid && s_axi_wready; assign rf_wr_en = s_axi_rvalid && s_axi_rready; assign rf_rd_req = (rf_data_cnt > 10) ? 1 : 0; //模拟读FIFO的读使能 //reg rf_rd_en; //always @(posedge clk ) begin // if(!rst_n) // rf_rd_en <= 0; // else if(rf_data_cnt > burst_len) // rf_rd_en <= 1; // else // rf_rd_en <= rf_rd_en; //end //-----------------------------帧缓存----------------------------- reg wr_select; reg rd_select; wire pic_rd_done; reg pic_rd_done_last; reg [27:0] wr_base_addr; reg [27:0] rd_base_addr; reg pic_done; //写地址最后一帧信号 always @(posedge clk or negedge rst_n) begin if(!rst_n) pic_rd_done_last <= 0; else if(s_axi_awvalid && s_axi_awready && s_axi_awaddr == rd_base_addr + pic_data0 - axi_addr) pic_rd_done_last <= 1; else if(pic_rd_done_last && s_axi_bvalid) pic_rd_done_last <= 0; end assign pic_rd_done = pic_rd_done_last && s_axi_bvalid; //写选择 always @(posedge clk or negedge rst_n) begin if(!rst_n) wr_select <= 0; else if(pic_rd_done) wr_select <= ~wr_select; else wr_select <= wr_select; end //读选择 always @(posedge clk or negedge rst_n) begin if(!rst_n) rd_select <= 1; else if(pic_rd_done) rd_select <= wr_select; else rd_select <= rd_select; end //写地址 always @(*) begin if(wr_select == 0) wr_base_addr = pic_data0; else wr_base_addr = 0; end //读地址 always @(*) begin if(rd_select == 0) rd_base_addr = pic_data0; else rd_base_addr = 0; end //写操作开始信号 always @(posedge clk or negedge rst_n) begin if(!rst_n) pic_done <= 0; else if(s_axi_awaddr == pic_data0 - axi_addr && s_axi_awvalid && s_axi_awready) pic_done <= 1; else pic_done <= pic_done; end //-----------------------------state one----------------------------- always @(posedge clk or negedge rst_n) begin if(!rst_n) curr_state <= IDLE; else curr_state <= next_state; end //-----------------------------state two----------------------------- always @(*) begin if(!rst_n) next_state = IDLE; else begin case(curr_state) IDLE :begin if(wf_data_cnt > burst_len) next_state = WR_ADDR; else if(rf_data_cnt < burst_len && pic_done) next_state = RD_ADDR; else next_state = IDLE; end WR_ADDR :begin if(s_axi_awvalid && s_axi_awready) next_state = WR_DATA; else next_state = WR_ADDR; end WR_DATA :begin if(s_axi_wlast && s_axi_wvalid && s_axi_wready) next_state = WR_RES; else next_state = WR_DATA; end WR_RES :begin if(s_axi_bresp == 2'b0 && s_axi_bvalid && s_axi_bready) next_state = IDLE; else next_state = WR_RES; end RD_ADDR :begin if(s_axi_arvalid && s_axi_arready) next_state = RD_DATA; else next_state = RD_ADDR; end RD_DATA :begin if(s_axi_rresp == 2'b0 && s_axi_rlast && s_axi_rvalid && s_axi_rready) next_state = IDLE; else next_state = RD_DATA; end default :next_state = IDLE; endcase end end //-----------------------------state three----------------------------- //写地址 always @(posedge clk or negedge rst_n) begin if(!rst_n) s_axi_awaddr <= 0; else if(pic_rd_done) s_axi_awaddr <= wr_base_addr; else if(s_axi_awvalid && s_axi_awready) s_axi_awaddr <= s_axi_awaddr + axi_addr; else s_axi_awaddr <= s_axi_awaddr; end //写地址有效信号 always @(posedge clk or negedge rst_n) begin if(!rst_n) s_axi_awvalid <= 0; else if(curr_state == WR_ADDR) begin if(s_axi_awvalid && s_axi_awready) s_axi_awvalid <= 0; else s_axi_awvalid <= 1; end else s_axi_awvalid <= s_axi_awvalid; end //写数据计数 always @(posedge clk or negedge rst_n) begin if(!rst_n) wr_data_cnt <= 0; else if(wr_data_cnt == burst_len && s_axi_wvalid && s_axi_wready) wr_data_cnt <= 0; else if(curr_state == WR_DATA && s_axi_wvalid && s_axi_wready) wr_data_cnt <= wr_data_cnt + 1; else wr_data_cnt <= wr_data_cnt; end //写数据最后一位 always @(posedge clk or negedge rst_n) begin if(!rst_n) s_axi_wlast <= 0; else if(wr_data_cnt == burst_len && s_axi_wvalid && s_axi_wready) s_axi_wlast <= 0; else if(wr_data_cnt == burst_len - 1 && s_axi_wvalid && s_axi_wready) s_axi_wlast <= 1; else s_axi_wlast <= s_axi_wlast; end // 写数据有效信号 always @(posedge clk or negedge rst_n) begin if(!rst_n) s_axi_wvalid <= 0; else if (s_axi_wlast && s_axi_wvalid && s_axi_wready) begin // 一次突发写完成 s_axi_wvalid <= 0; end else if (curr_state == WR_DATA && wf_data_cnt > 0) begin // 在写数据状态且FIFO有数据 s_axi_wvalid <= 1; end else begin // 其他所有情况,都应无效 s_axi_wvalid <= 0; end end //读地址 always @(posedge clk or negedge rst_n) begin if(!rst_n) s_axi_araddr <= 0; else if(s_axi_arvalid && s_axi_arready && curr_state == RD_ADDR) begin if(rd_select == 0 && (s_axi_araddr == pic_data0 - axi_addr || s_axi_araddr == pic_data1 - axi_addr)) s_axi_araddr <= 0; else if(rd_select == 1 && (s_axi_araddr == pic_data1 - axi_addr || s_axi_araddr == pic_data0 - axi_addr)) s_axi_araddr <= pic_data0; else s_axi_araddr <= s_axi_araddr + axi_addr; end end //读地址有效信号 always @(posedge clk or negedge rst_n) begin if(!rst_n) s_axi_arvalid <= 0; else if(curr_state == RD_ADDR) begin if(s_axi_arvalid && s_axi_arready) s_axi_arvalid <= 0; else s_axi_arvalid <= 1; end else s_axi_arvalid <= s_axi_arvalid; end //-----------------------------fifo ctrl----------------------------- wr_fifo wr_fifo_u ( .rst(~rst_n), // input wire rst .wr_clk(wf_wr_clk), // input wire wr_clk .rd_clk(clk), // input wire rd_clk .din(wf_wr_data), // input wire [15 : 0] din .wr_en(wf_wr_en), // input wire wr_en .rd_en(wf_rd_en), // input wire rd_en .dout(s_axi_wdata), // output wire [127 : 0] dout // .full(full), // output wire full // .empty(empty), // output wire empty .rd_data_count(wf_data_cnt) // output wire [7 : 0] rd_data_count ); rd_fifo rd_fifo_u ( .rst(~rst_n), // input wire rst .wr_clk(clk), // input wire wr_clk .rd_clk(rf_rd_clk), // input wire rd_clk .din(s_axi_rdata), // input wire [127 : 0] din .wr_en(rf_wr_en), // input wire wr_en .rd_en(rf_rd_en), // input wire rd_en .dout(rf_rd_data), // output wire [15 : 0] dout // .full(full), // output wire full // .empty(empty), // output wire empty .wr_data_count(rf_data_cnt) // output wire [7 : 0] wr_data_count ); endmodule 以上FPGA 代码中,解读下以下代码:always @(posedge clk or negedge rst_n) begin if(!rst_n) rd_select <= 1; else if(pic_rd_done) rd_select <= wr_select; else rd_select <= rd_select; end
10-29
`default_nettype none // UART Top-Level Module // Integrates transmitter and receiver with a shared baud rate generator // Provides a unified interface for UART communication module uart_top ( // Clock and Reset input wire clk, // System clock input wire rst_n, // Active-low asynchronous reset // AXI4-Lite Slave Interface input wire s_axi_awvalid, // Write address valid input wire [4:0] s_axi_awaddr, // Write address (32 aligned) output reg s_axi_awready, // Write address ready input wire s_axi_wvalid, // Write data valid input wire [31:0] s_axi_wdata, // Write data input wire [3:0] s_axi_wstrb, // Write strobe output reg s_axi_wready, // Write data ready output reg s_axi_bvalid, // Write response valid output reg [1:0] s_axi_bresp, // Write response input wire s_axi_bready, // Write response ready input wire s_axi_arvalid, // Read address valid input wire [4:0] s_axi_araddr, // Read address (32 aligned) output reg s_axi_arready, // Read address ready output reg s_axi_rvalid, // Read data valid output reg [31:0] s_axi_rdata, // Read data output reg [1:0] s_axi_rresp, // Read response input wire s_axi_rready, // Read data ready // UART Serial Interface output wire uart_tx, // UART transmit line input wire uart_rx, // UART receive line // Interrupt Output output wire irq // Active-high interrupt signal ); // Parameters matching the specification localparam TX_FIFO_ADDR = 5'h00; // Transmit FIFO write port localparam RX_FIFO_ADDR = 5'h04; // Receive FIFO read port localparam STATUS_ADDR = 5'h08; // Status register localparam CTRL_ADDR = 5'h0C; // Control register localparam BAUD_DIV_ADDR = 5'h10; // Baud rate divisor localparam INT_EN_ADDR = 5'h14; // Interrupt enable localparam INT_STS_ADDR = 5'h18; // Interrupt status // Register widths localparam DATA_WIDTH = 8; // Data width for FIFOs localparam BAUD_WIDTH = 16; // Baud rate divisor width localparam FIFO_DEPTH = 4; // FIFO depth in bits (16 entries) // Control register bit fields localparam PARITY_EN_POS = 2; // Parity enable position localparam DATA_BITS_POS = 0; // Data bits position localparam STOP_BITS_POS = 4; // Stop bits position localparam LOOPBACK_EN_POS = 8; // Loopback enable position // Status register bit fields localparam RX_FIFO_CNT_POS = 16; // RX FIFO count position localparam TX_FIFO_CNT_POS = 0; // TX FIFO count position // Interrupt enable/status bit fields localparam TX_EMPTY_EN_POS = 0; // TX empty interrupt enable localparam RX_READY_EN_POS = 1; // RX ready interrupt enable localparam TX_EMPTY_STS_POS = 0; // TX empty interrupt status localparam RX_READY_STS_POS = 1; // RX ready interrupt status // Register storage reg [31:0] ctrl_reg; // Control register reg [BAUD_WIDTH-1:0] baud_div_reg; // Baud rate divisor register reg [31:0] int_en_reg; // Interrupt enable register reg [31:0] int_sts_reg; // Interrupt status register // FIFO signals wire tx_fifo_wr_en; // TX FIFO write enable wire tx_fifo_full; // TX FIFO full flag reg tx_fifo_rd_en; // TX FIFO read enable wire [DATA_WIDTH-1:0] tx_fifo_dout; // TX FIFO data output wire [FIFO_DEPTH-1:0] tx_fifo_cnt; // TX FIFO count wire rx_fifo_wr_en; // RX FIFO write enable wire rx_fifo_empty; // RX FIFO empty flag reg rx_fifo_rd_en; // RX FIFO read enable wire [DATA_WIDTH-1:0] rx_fifo_din; // RX FIFO data input wire [FIFO_DEPTH-1:0] rx_fifo_cnt; // RX FIFO count // Baud rate generator signals wire baud_ce; // Baud rate clock enable // Transmitter signals wire tx_en; // Transmit enable wire tx_busy; // Transmit busy flag // Receiver signals wire rx_valid; // Received data valid wire [7:0] rx_data; // Received data wire framing_error; // Framing error flag wire parity_error; // Parity error flag wire overrun_error; // Overrun error flag // Loopback signal wire loopback_tx; // Interrupt signal assign irq = (int_en_reg[TX_EMPTY_EN_POS] & int_sts_reg[TX_EMPTY_STS_POS]) | (int_en_reg[RX_READY_EN_POS] & int_sts_reg[RX_READY_STS_POS]); // AXI4-Lite Write Address Channel always @(posedge clk or negedge rst_n) begin if (!rst_n) begin s_axi_awready <= 1'b0; end else begin s_axi_awready <= s_axi_awvalid; end end // AXI4-Lite Write Data Channel always @(posedge clk or negedge rst_n) begin if (!rst_n) begin s_axi_wready <= 1'b0; end else begin s_axi_wready <= s_axi_wvalid; end end // AXI4-Lite Write Response Channel always @(posedge clk or negedge rst_n) begin if (!rst_n) begin s_axi_bvalid <= 1'b0; s_axi_bresp <= 2'b00; end else begin if (s_axi_wvalid && s_axi_wready && !s_axi_bvalid) begin s_axi_bvalid <= 1'b1; s_axi_bresp <= 2'b00; // OKAY response end else if (s_axi_bvalid && s_axi_bready) begin s_axi_bvalid <= 1'b0; end end end // AXI4-Lite Read Address Channel always @(posedge clk or negedge rst_n) begin if (!rst_n) begin s_axi_arready <= 1'b0; end else begin s_axi_arready <= s_axi_arvalid; end end // AXI4-Lite Read Data Channel always @(posedge clk or negedge rst_n) begin if (!rst_n) begin s_axi_rvalid <= 1'b0; s_axi_rdata <= 32'h00000000; s_axi_rresp <= 2'b00; end else begin if (s_axi_arvalid && s_axi_arready && !s_axi_rvalid) begin s_axi_rvalid <= 1'b1; s_axi_rresp <= 2'b00; // OKAY response // Read data based on address case (s_axi_araddr) RX_FIFO_ADDR: s_axi_rdata <= {24'h000000, rx_fifo_din}; STATUS_ADDR: s_axi_rdata <= {rx_fifo_cnt, 16'h0000, tx_fifo_cnt, 16'h0000}; CTRL_ADDR: s_axi_rdata <= ctrl_reg; BAUD_DIV_ADDR: s_axi_rdata <= {16'h0000, baud_div_reg}; INT_EN_ADDR: s_axi_rdata <= int_en_reg; INT_STS_ADDR: s_axi_rdata <= int_sts_reg; default: s_axi_rdata <= 32'h00000000; endcase end else if (s_axi_rvalid && s_axi_rready) begin s_axi_rvalid <= 1'b0; end end end // AXI4-Lite Write Logic always @(posedge clk or negedge rst_n) begin if (!rst_n) begin ctrl_reg <= 32'h00000000; baud_div_reg <= {BAUD_WIDTH{1'b0}}; int_en_reg <= 32'h00000000; int_sts_reg <= 32'h00000000; end else begin if (s_axi_awvalid && s_axi_awready && s_axi_wvalid && s_axi_wready) begin case (s_axi_awaddr) TX_FIFO_ADDR: begin // Writing to TX FIFO is handled by tx_fifo_wr_en end CTRL_ADDR: begin if (s_axi_wstrb[0]) ctrl_reg[7:0] <= s_axi_wdata[7:0]; if (s_axi_wstrb[1]) ctrl_reg[15:8] <= s_axi_wdata[15:8]; if (s_axi_wstrb[2]) ctrl_reg[23:16] <= s_axi_wdata[23:16]; if (s_axi_wstrb[3]) ctrl_reg[31:24] <= s_axi_wdata[31:24]; end BAUD_DIV_ADDR: begin if (s_axi_wstrb[0]) baud_div_reg[7:0] <= s_axi_wdata[7:0]; if (s_axi_wstrb[1]) baud_div_reg[15:8] <= s_axi_wdata[15:8]; end INT_EN_ADDR: begin if (s_axi_wstrb[0]) int_en_reg[7:0] <= s_axi_wdata[7:0]; if (s_axi_wstrb[1]) int_en_reg[15:8] <= s_axi_wdata[15:8]; if (s_axi_wstrb[2]) int_en_reg[23:16] <= s_axi_wdata[23:16]; if (s_axi_wstrb[3]) int_en_reg[31:24] <= s_axi_wdata[31:24]; end INT_STS_ADDR: begin // Write 1 to clear interrupt status bits if (s_axi_wstrb[0]) int_sts_reg[1:0] <= int_sts_reg[1:0] & ~s_axi_wdata[1:0]; end endcase end end end // TX FIFO write enable logic assign tx_fifo_wr_en = s_axi_awvalid && s_axi_awready && s_axi_wvalid && s_axi_wready && (s_axi_awaddr == TX_FIFO_ADDR); // RX FIFO read enable logic always @(posedge clk or negedge rst_n) begin if (!rst_n) begin rx_fifo_rd_en <= 1'b0; end else begin rx_fifo_rd_en <= (s_axi_arvalid && s_axi_arready && (s_axi_araddr == RX_FIFO_ADDR)); end end // TX FIFO read enable logic always @(posedge clk or negedge rst_n) begin if (!rst_n) begin tx_fifo_rd_en <= 1'b0; end else begin tx_fifo_rd_en <= tx_en; end end // Interrupt status update logic always @(posedge clk or negedge rst_n) begin if (!rst_n) begin int_sts_reg <= 32'h00000000; end else begin // Update TX empty status if (tx_fifo_empty && !tx_busy) begin int_sts_reg[TX_EMPTY_STS_POS] <= 1'b1; end else if (int_sts_reg[TX_EMPTY_STS_POS] && s_axi_awvalid && s_axi_awready && s_axi_wvalid && s_axi_wready && (s_axi_awaddr == TX_FIFO_ADDR)) begin int_sts_reg[TX_EMPTY_STS_POS] <= 1'b0; end // Update RX ready status if (!rx_fifo_empty) begin int_sts_reg[RX_READY_STS_POS] <= 1'b1; end else if (int_sts_reg[RX_READY_STS_POS] && rx_fifo_rd_en) begin int_sts_reg[RX_READY_STS_POS] <= 1'b0; end // Clear interrupts when written to INT_STS register if (s_axi_awvalid && s_axi_awready && s_axi_wvalid && s_axi_wready && (s_axi_awaddr == INT_STS_ADDR)) begin int_sts_reg[1:0] <= int_sts_reg[1:0] & ~s_axi_wdata[1:0]; end end end // Baud rate generator instance baud_rate_generator #( .WIDTH(BAUD_WIDTH) ) baud_gen_inst ( .clk(clk), .rst_n(rst_n), .divisor(baud_div_reg), .baud_ce(baud_ce) ); // UART transmitter instance uart_tx #( .DATA_BITS(ctrl_reg[DATA_BITS_POS+:2]), .PARITY_EN(ctrl_reg[PARITY_EN_POS+:2]), .STOP_BITS(ctrl_reg[STOP_BITS_POS+:2]) ) uart_tx_inst ( .clk(clk), .rst_n(rst_n), .baud_ce(baud_ce), .tx_en(tx_en), .data_in(tx_fifo_dout), .tx_out(uart_tx), .tx_busy(tx_busy) ); // UART receiver instance uart_rx #( .DATA_BITS(ctrl_reg[DATA_BITS_POS+:2]), .PARITY_EN(ctrl_reg[PARITY_EN_POS+:2]), .STOP_BITS(ctrl_reg[STOP_BITS_POS+:2]) ) uart_rx_inst ( .clk(clk), .rst_n(rst_n), .baud_ce(baud_ce), .rx_in(ctrl_reg[LOOPBACK_EN_POS] ? loopback_tx : uart_rx), .rx_valid(rx_valid), .data_out(rx_data), .framing_error(framing_error), .parity_error(parity_error), .overrun_error(overrun_error) ); // TX FIFO instance (using inferred memory) reg [DATA_WIDTH-1:0] tx_fifo [0:15]; reg [3:0] tx_fifo_wr_ptr; reg [3:0] tx_fifo_rd_ptr; reg [4:0] tx_fifo_count; assign tx_fifo_full = (tx_fifo_count == 5'd16); assign tx_fifo_empty = (tx_fifo_count == 5'd0); assign tx_fifo_cnt = tx_fifo_count[3:0]; assign tx_fifo_dout = tx_fifo[tx_fifo_rd_ptr]; // TX FIFO write logic always @(posedge clk or negedge rst_n) begin if (!rst_n) begin tx_fifo_wr_ptr <= 4'd0; tx_fifo_count <= 5'd0; end else begin if (tx_fifo_wr_en && !tx_fifo_full) begin tx_fifo[tx_fifo_wr_ptr] <= s_axi_wdata[7:0]; tx_fifo_wr_ptr <= tx_fifo_wr_ptr + 1; tx_fifo_count <= tx_fifo_count + 1; end end end // TX FIFO read logic always @(posedge clk or negedge rst_n) begin if (!rst_n) begin tx_fifo_rd_ptr <= 4'd0; end else begin if (tx_fifo_rd_en && !tx_fifo_empty) begin tx_fifo_rd_ptr <= tx_fifo_rd_ptr + 1; tx_fifo_count <= tx_fifo_count - 1; end end end // TX enable logic assign tx_en = !tx_fifo_empty && !tx_busy; // RX FIFO instance (using inferred memory) reg [DATA_WIDTH-1:0] rx_fifo [0:15]; reg [3:0] rx_fifo_wr_ptr; reg [3:0] rx_fifo_rd_ptr; reg [4:0] rx_fifo_count; assign rx_fifo_empty = (rx_fifo_count == 5'd0); assign rx_fifo_cnt = rx_fifo_count[3:0]; assign rx_fifo_din = rx_fifo[rx_fifo_rd_ptr]; // RX FIFO write logic always @(posedge clk or negedge rst_n) begin if (!rst_n) begin rx_fifo_wr_ptr <= 4'd0; rx_fifo_count <= 5'd0; end else begin if (rx_valid) begin rx_fifo[rx_fifo_wr_ptr] <= rx_data; rx_fifo_wr_ptr <= rx_fifo_wr_ptr + 1; rx_fifo_count <= rx_fifo_count + 1; end end end // RX FIFO read logic always @(posedge clk or negedge rst_n) begin if (!rst_n) begin rx_fifo_rd_ptr <= 4'd0; end else begin if (rx_fifo_rd_en && !rx_fifo_empty) begin rx_fifo_rd_ptr <= rx_fifo_rd_ptr + 1; rx_fifo_count <= rx_fifo_count - 1; end end end // Loopback connection assign loopback_tx = uart_tx; endmodule 这个模块有什么语法问题
最新发布
11-11
“`timescale 1ns / 1ps module tb_Top_NUC; //仅用于测试 //wr_fifo Interface reg wrfifo_clr; reg wrfifo_clk; reg [15:0] wrfifo_din; reg wrfifo_wren; /////////////////////////////////////// wire mmcm_locked; wire ui_clk; wire init_calib_complete; reg aresetn; reg sys_clk_i; reg sys_rst; reg [15:0] expect_rd_data; initial sys_clk_i = 1'b1; always #2.5 sys_clk_i = ~sys_clk_i; wire [13:0] ddr3_addr; wire [2:0] ddr3_ba; wire ddr3_cas_n; wire [0:0] ddr3_ck_n; wire [0:0] ddr3_ck_p; wire [0:0] ddr3_cke; wire ddr3_ras_n; wire ddr3_reset_n; wire ddr3_we_n; wire [15:0] ddr3_dq; wire [1:0] ddr3_dqs_n; wire [1:0] ddr3_dqs_p; wire [0:0] ddr3_cs_n; wire [1:0] ddr3_dm; wire [0:0] ddr3_odt; parameter RD_AXI_BYTE_ADDR_BEGIN = 0 ; parameter RD_AXI_BYTE_ADDR_END = 4095 ; parameter WR_AXI_BYTE_ADDR_BEGIN = 0 ; parameter WR_AXI_BYTE_ADDR_END = 4095 ; parameter AXI_DATA_WIDTH = 64 ; parameter AXI_ADDR_WIDTH = 32 ; parameter AXI_ID_WIDTH = 4 ; parameter AXI_ID = 4'b0000; parameter AXI_BURST_LEN = 8'd15 ; //burst length = AXI_BURST_LEN+1 parameter RD_FIFO_ADDR_DEPTH = 16 ; parameter WR_FIFO_ADDR_DEPTH = 64 ; // Master Interface Write Address Ports wire [AXI_ID_WIDTH-1:0] m_axi_awid ; wire [AXI_ADDR_WIDTH-1:0] m_axi_awaddr ; wire [7:0] m_axi_awlen ; wire [2:0] m_axi_awsize ; wire [1:0] m_axi_awburst ; wire [0:0] m_axi_awlock ; wire [3:0] m_axi_awcache ; wire [2:0] m_axi_awprot ; wire [3:0] m_axi_awqos ; wire [3:0] m_axi_awregion; wire m_axi_awvalid ; wire m_axi_awready; // Master Interface Write Data Ports wire [AXI_DATA_WIDTH-1:0] m_axi_wdata ; wire [AXI_DATA_WIDTH/8-1:0] m_axi_wstrb ; wire m_axi_wlast ; wire m_axi_wvalid ; wire m_axi_wready ; // Master Interface Write Response Ports wire [AXI_ID_WIDTH-1:0] m_axi_bid ; wire [1:0] m_axi_bresp ; wire m_axi_bvalid ; wire m_axi_bready ; // Master Interface Read Address Ports wire [AXI_ID_WIDTH-1:0] m_axi_arid ; wire [AXI_ADDR_WIDTH-1:0] m_axi_araddr ; wire [7:0] m_axi_arlen ; wire [2:0] m_axi_arsize ; wire [1:0] m_axi_arburst ; wire [0:0] m_axi_arlock ; wire [3:0] m_axi_arcache ; wire [2:0] m_axi_arprot ; wire [3:0] m_axi_arqos ; wire [3:0] m_axi_arregion; wire m_axi_arvalid ; wire m_axi_arready; // Master Interface Read Data Ports wire [AXI_ID_WIDTH-1:0] m_axi_rid ; wire [AXI_DATA_WIDTH-1:0] m_axi_rdata ; wire [1:0] m_axi_rresp ; wire m_axi_rlast ; wire m_axi_rvalid ; wire m_axi_rready ; parameter TDATA_WIDTH = 128 ; parameter TDEST_WIDTH = 1 ; parameter TID_WIDTH = 1 ; //实时数据流输入 reg [0:0] s_axis_tid_s; reg [0:0] s_axis_tdest_s; reg [TDATA_WIDTH-1:0] s_axis_tdata_s; reg [(TDATA_WIDTH>>3)-1:0] s_axis_tstrb_s; reg [(TDATA_WIDTH>>3)-1:0] s_axis_tkeep_s; reg s_axis_tlast_s; reg s_axis_tuser_s; reg s_axis_tvalid_s; wire s_axis_tready_s=1'b1;/////////////////////////////////////////////////////////// //实时数据流输出 wire [0:0] m_axis_tid_s; wire [0:0] m_axis_tdest_s; wire [TDATA_WIDTH-1:0] m_axis_tdata_s; wire [(TDATA_WIDTH>>3)-1:0] m_axis_tstrb_s; wire [(TDATA_WIDTH>>3)-1:0] m_axis_tkeep_s; wire m_axis_tlast_s; wire m_axis_tuser_s; wire m_axis_tvalid_s; reg m_axis_tready_s=1'b1;//////////////////////////////////////////////////////////// parameter SIM_DATA_BEGIN = 1; parameter SIM_DATA_CNT = 4096; initial sys_clk_i = 1'b1; always #2.5 sys_clk_i = ~sys_clk_i; initial wrfifo_clk = 1'b1; always #5 wrfifo_clk = ~wrfifo_clk; initial begin sys_rst = 1'b0; aresetn = 1'b0; expect_rd_data = 16'd0; wrfifo_clr = 1'b1; wrfifo_wren = 1'b0; wrfifo_din = 16'd0; #201; // 等待201ns,确保时钟稳定 // 释放复位 sys_rst = 1'b1; aresetn = 1'b1; // 等待DDR3控制器的锁相环锁定 @(posedge mmcm_locked); #200; wrfifo_clr = 1'b0; @(posedge init_calib_complete); #200; //wr_data(SIM_DATA_BEGIN,SIM_DATA_CNT);//4096个数据 #8000; //rd_data(SIM_DATA_BEGIN,SIM_DATA_CNT);//4096个数据 #5000; $display("SIM is successfully"); $stop; end task wr_data; input [15:0]data_begin; input [15:0]wr_data_cnt; begin wrfifo_wren = 1'b0; s_axis_tvalid_s=1'b0; wrfifo_din = data_begin; @(posedge wrfifo_clk); #1 wrfifo_wren = 1'b1; repeat(wr_data_cnt) begin @(posedge wrfifo_clk); #1 wrfifo_din = wrfifo_din + 1'b1; end #1 wrfifo_wren = 1'b0; end endtask task rd_data; input [15:0]data_begin; input [15:0]rd_data_cnt; integer k,i,j; begin s_axis_tvalid_s=1'b0; for(k=0;k<4;k=k+1) begin s_axis_tdata_s=data_begin-1; for(i=0;i<16;i=i+1) begin for ( j=0 ;j<64-1 ;j=j+1 ) begin @(posedge wrfifo_clk); #1; if(i==0&&j==0) begin s_axis_tuser_s=1'b1; end else begin s_axis_tuser_s=1'b0; end s_axis_tdata_s=s_axis_tdata_s+1'd1; s_axis_tvalid_s=1'b1; s_axis_tlast_s=1'b0; end @(posedge wrfifo_clk); s_axis_tuser_s=1'b0; s_axis_tlast_s=1'b1; s_axis_tvalid_s=1'b1; s_axis_tdata_s=s_axis_tdata_s+1'd1; end end end endtask Top_NUC # ( .TDATA_WIDTH (TDATA_WIDTH ), .TDEST_WIDTH (TDEST_WIDTH ), .TID_WIDTH (TID_WIDTH ), .WR_FIFO_DW (16 ), .RD_FIFO_DW (256 ), .RD_AXI_BYTE_ADDR_BEGIN(RD_AXI_BYTE_ADDR_BEGIN ), .RD_AXI_BYTE_ADDR_END (RD_AXI_BYTE_ADDR_END ), .WD_AXI_BYTE_ADDR_BEGIN(WR_AXI_BYTE_ADDR_BEGIN ), .WD_AXI_BYTE_ADDR_END (WR_AXI_BYTE_ADDR_END ), .AXI_DATA_WIDTH (AXI_DATA_WIDTH ), .AXI_ADDR_WIDTH (AXI_ADDR_WIDTH ), .AXI_ID_WIDTH (AXI_ID_WIDTH ), .AXI_ID (AXI_ID ), .AXI_BURST_LEN (AXI_BURST_LEN ), .WR_FIFO_ADDR_DEPTH (WR_FIFO_ADDR_DEPTH ), .RD_FIFO_ADDR_DEPTH (RD_FIFO_ADDR_DEPTH ) ) Top_NUC_inst ( .aclk (ui_clk ), .aresetn (~init_calib_complete),/////////////////////////////// //仅用于测试 .wrfifo_clr (wrfifo_clr ), .wrfifo_clk (wrfifo_clk ), .wrfifo_wren (wrfifo_wren ), .wrfifo_din (wrfifo_din ), .wrfifo_full ( ), .wrfifo_wr_cnt ( ), ///////////////////////////////////////////////////////////////////////////// .s_axis_tid_s (s_axis_tid_s ), .s_axis_tdest_s (s_axis_tdest_s ), .s_axis_tdata_s (s_axis_tdata_s ), .s_axis_tstrb_s (s_axis_tstrb_s ), .s_axis_tkeep_s (s_axis_tkeep_s ), .s_axis_tlast_s (s_axis_tlast_s ), .s_axis_tuser_s (s_axis_tuser_s ), .s_axis_tvalid_s (s_axis_tvalid_s ), .s_axis_tready_s (s_axis_tready_s ), .m_axis_tid_s (m_axis_tid_s ), .m_axis_tdest_s (m_axis_tdest_s ), .m_axis_tdata_s (m_axis_tdata_s ), .m_axis_tstrb_s (m_axis_tstrb_s ), .m_axis_tkeep_s (m_axis_tkeep_s ), .m_axis_tlast_s (m_axis_tlast_s ), .m_axis_tuser_s (m_axis_tuser_s ), .m_axis_tvalid_s (m_axis_tvalid_s ), .m_axis_tready_s (m_axis_tready_s ), .m_axi_awid (m_axi_awid ), .m_axi_awaddr (m_axi_awaddr ), .m_axi_awlen (m_axi_awlen ), .m_axi_awsize (m_axi_awsize ), .m_axi_awburst (m_axi_awburst ), .m_axi_awlock (m_axi_awlock ), .m_axi_awcache (m_axi_awcache ), .m_axi_awprot (m_axi_awprot ), .m_axi_awqos (m_axi_awqos ), .m_axi_awregion (m_axi_awregion ), .m_axi_awvalid (m_axi_awvalid ), .m_axi_awready (m_axi_awready ), .m_axi_wdata (m_axi_wdata ), .m_axi_wstrb (m_axi_wstrb ), .m_axi_wlast (m_axi_wlast ), .m_axi_wvalid (m_axi_wvalid ), .m_axi_wready (m_axi_wready ), .m_axi_bid (m_axi_bid ), .m_axi_bresp (m_axi_bresp ), .m_axi_bvalid (m_axi_bvalid ), .m_axi_bready (m_axi_bready ), .m_axi_arid (m_axi_arid ), .m_axi_araddr (m_axi_araddr ), .m_axi_arlen (m_axi_arlen ), .m_axi_arsize (m_axi_arsize ), .m_axi_arburst (m_axi_arburst ), .m_axi_arlock (m_axi_arlock ), .m_axi_arcache (m_axi_arcache ), .m_axi_arprot (m_axi_arprot ), .m_axi_arqos (m_axi_arqos ), .m_axi_arregion (m_axi_arregion ), .m_axi_arvalid (m_axi_arvalid ), .m_axi_arready (m_axi_arready ), .m_axi_rid (m_axi_rid ), .m_axi_rdata (m_axi_rdata ), .m_axi_rresp (m_axi_rresp ), .m_axi_rlast (m_axi_rlast ), .m_axi_rvalid (m_axi_rvalid ), .m_axi_rready (m_axi_rready ) ); mig_7series_0 u_mig_7series_0 ( // Memory interface ports .ddr3_addr (ddr3_addr ), .ddr3_ba (ddr3_ba ), .ddr3_cas_n (ddr3_cas_n ), .ddr3_ck_n (ddr3_ck_n ), .ddr3_ck_p (ddr3_ck_p ), .ddr3_cke (ddr3_cke ), .ddr3_ras_n (ddr3_ras_n ), .ddr3_reset_n (ddr3_reset_n ), .ddr3_we_n (ddr3_we_n ), .ddr3_dq (ddr3_dq ), .ddr3_dqs_n (ddr3_dqs_n ), .ddr3_dqs_p (ddr3_dqs_p ), .init_calib_complete (init_calib_complete ), .ddr3_cs_n (ddr3_cs_n ),///////////////////////////////////// .ddr3_dm (ddr3_dm ), .ddr3_odt (ddr3_odt ), // Application interface ports .ui_clk (ui_clk ), .ui_clk_sync_rst (ui_clk_sync_rst ), .mmcm_locked (mmcm_locked ), .aresetn (aresetn ), .app_sr_req (1'b0 ), .app_ref_req (1'b0 ), .app_zq_req (1'b0 ), .app_sr_active ( ), .app_ref_ack ( ), .app_zq_ack ( ), // Slave Interface Write Address Ports .s_axi_awid (m_axi_awid ), .s_axi_awaddr (m_axi_awaddr ), .s_axi_awlen (m_axi_awlen ), .s_axi_awsize (m_axi_awsize ), .s_axi_awburst (m_axi_awburst ), .s_axi_awlock (m_axi_awlock ), .s_axi_awcache (m_axi_awcache ), .s_axi_awprot (m_axi_awprot ), .s_axi_awqos (m_axi_awqos ), .s_axi_awvalid (m_axi_awvalid ), .s_axi_awready (m_axi_awready ), // Slave Interface Write Data Ports .s_axi_wdata (m_axi_wdata ), .s_axi_wstrb (m_axi_wstrb ), .s_axi_wlast (m_axi_wlast ), .s_axi_wvalid (m_axi_wvalid ), .s_axi_wready (m_axi_wready ), // Slave Interface Write Response Ports .s_axi_bid (m_axi_bid ), .s_axi_bresp (m_axi_bresp ), .s_axi_bvalid (m_axi_bvalid ), .s_axi_bready (m_axi_bready ), // Slave Interface Read Address Ports .s_axi_arid (m_axi_arid ), .s_axi_araddr (m_axi_araddr ), .s_axi_arlen (m_axi_arlen ), .s_axi_arsize (m_axi_arsize ), .s_axi_arburst (m_axi_arburst ), .s_axi_arlock (m_axi_arlock ), .s_axi_arcache (m_axi_arcache ), .s_axi_arprot (m_axi_arprot ), .s_axi_arqos (m_axi_arqos ), .s_axi_arvalid (m_axi_arvalid ), .s_axi_arready (m_axi_arready ), // Slave Interface Read Data Ports .s_axi_rid (m_axi_rid ), .s_axi_rdata (m_axi_rdata ), .s_axi_rresp (m_axi_rresp ), .s_axi_rlast (m_axi_rlast ), .s_axi_rvalid (m_axi_rvalid ), .s_axi_rready (m_axi_rready ), // System Clock Ports .sys_clk_i (sys_clk_i ), .sys_rst (sys_rst ) //active low ); ddr3_model ddr3_model ( .rst_n (ddr3_reset_n ), .ck (ddr3_ck_p ), .ck_n (ddr3_ck_n ), .cke (ddr3_cke ), .cs_n (ddr3_cs_n ), .ras_n (ddr3_ras_n ), .cas_n (ddr3_cas_n ), .we_n (ddr3_we_n ), .dm_tdqs(ddr3_dm ), .ba (ddr3_ba ), .addr (ddr3_addr ), .dq (ddr3_dq ), .dqs (ddr3_dqs_p ), .dqs_n (ddr3_dqs_n ), .tdqs_n ( ), .odt (ddr3_odt ) ); endmodule”分析这段代码,检查是否存在错误
06-13
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值