From e3ea51ade3640444f7c88bfb217c9502b26f53fa Mon Sep 17 00:00:00 2001 From: Istvan Csomortani Date: Tue, 17 Oct 2017 13:10:06 +0100 Subject: [PATCH] avl_dacfifo: Refactor the fifo + Build both the read and write logic around an FSM + Consistent naming of registers and wires + Add support for burst lenghts higher than one, current burst lenght is 64 + Fix all the bugs, and make it work (first bring up with adrv9371x/a10soc) --- library/altera/avl_dacfifo/avl_dacfifo.v | 106 ++-- .../altera/avl_dacfifo/avl_dacfifo_constr.sdc | 56 +- library/altera/avl_dacfifo/avl_dacfifo_hw.tcl | 7 +- library/altera/avl_dacfifo/avl_dacfifo_rd.v | 532 ++++++++++------- library/altera/avl_dacfifo/avl_dacfifo_wr.v | 535 +++++++++++------- .../altera/avl_dacfifo/util_dacfifo_bypass.v | 4 +- .../a10soc/a10soc_plddr4_dacfifo_qsys.tcl | 3 + 7 files changed, 730 insertions(+), 513 deletions(-) diff --git a/library/altera/avl_dacfifo/avl_dacfifo.v b/library/altera/avl_dacfifo/avl_dacfifo.v index 5cf223ce9..23460d776 100644 --- a/library/altera/avl_dacfifo/avl_dacfifo.v +++ b/library/altera/avl_dacfifo/avl_dacfifo.v @@ -40,9 +40,10 @@ module avl_dacfifo #( parameter DAC_DATA_WIDTH = 64, parameter DAC_MEM_ADDRESS_WIDTH = 8, parameter DMA_DATA_WIDTH = 64, - parameter DMA_MEM_ADDRESS_WIDTH = 8, + parameter DMA_MEM_ADDRESS_WIDTH = 10, parameter AVL_DATA_WIDTH = 512, parameter AVL_ADDRESS_WIDTH = 25, + parameter AVL_BURST_LENGTH = 127, parameter AVL_BASE_ADDRESS = 32'h00000000, parameter AVL_ADDRESS_LIMIT = 32'h1fffffff) ( @@ -63,7 +64,7 @@ module avl_dacfifo #( input dac_valid, output reg [(DAC_DATA_WIDTH-1):0] dac_data, output reg dac_dunf, - output dac_xfer_out, + output reg dac_xfer_out, input bypass, @@ -75,12 +76,12 @@ module avl_dacfifo #( output reg [(AVL_ADDRESS_WIDTH-1):0] avl_address, output reg [ 6:0] avl_burstcount, output reg [ 63:0] avl_byteenable, - output reg avl_read, + output avl_read, input [(AVL_DATA_WIDTH-1):0] avl_readdata, input avl_readdata_valid, input avl_ready, - output reg avl_write, - output reg [(AVL_DATA_WIDTH-1):0] avl_writedata); + output avl_write, + output [(AVL_DATA_WIDTH-1):0] avl_writedata); localparam FIFO_BYPASS = (DAC_DATA_WIDTH == DMA_DATA_WIDTH) ? 1 : 0; @@ -91,11 +92,7 @@ module avl_dacfifo #( reg dac_bypass_m1 = 1'b0; reg dac_bypass = 1'b0; reg dac_xfer_out_m1 = 1'b0; - reg dac_xfer_out_int = 1'b0; reg dac_xfer_out_bypass = 1'b0; - reg avl_xfer_wren = 1'b0; - reg avl_dma_xfer_req = 1'b0; - reg avl_dma_xfer_req_m1 = 1'b0; // internal signals @@ -103,16 +100,18 @@ module avl_dacfifo #( wire dma_ready_bypass_s; wire avl_read_s; wire avl_write_s; - wire [(AVL_DATA_WIDTH-1):0] avl_writedata_s; wire [ 24:0] avl_wr_address_s; wire [ 24:0] avl_rd_address_s; wire [ 24:0] avl_last_address_s; - wire [ 63:0] avl_last_byteenable_s; - wire [ 5:0] avl_wr_burstcount_s; - wire [ 5:0] avl_rd_burstcount_s; + wire [ 6:0] avl_last_burstcount_s; + wire [ 7:0] dma_last_beats_s; + wire [ 6:0] avl_wr_burstcount_s; + wire [ 6:0] avl_rd_burstcount_s; wire [ 63:0] avl_wr_byteenable_s; wire [ 63:0] avl_rd_byteenable_s; + wire avl_xfer_wren_s; wire avl_xfer_out_s; + wire avl_xfer_in_s; wire [(DAC_DATA_WIDTH-1):0] dac_data_fifo_s; wire [(DAC_DATA_WIDTH-1):0] dac_data_bypass_s; wire dac_xfer_fifo_out_s; @@ -123,7 +122,8 @@ module avl_dacfifo #( .AVL_DATA_WIDTH (AVL_DATA_WIDTH), .DMA_DATA_WIDTH (DMA_DATA_WIDTH), .AVL_DDR_BASE_ADDRESS (AVL_BASE_ADDRESS), - .DMA_MEM_ADDRESS_WIDTH(DMA_MEM_ADDRESS_WIDTH) + .DMA_MEM_ADDRESS_WIDTH(DMA_MEM_ADDRESS_WIDTH), + .AVL_BURST_LENGTH (AVL_BURST_LENGTH) ) i_wr ( .dma_clk (dma_clk), .dma_data (dma_data), @@ -132,25 +132,27 @@ module avl_dacfifo #( .dma_valid (dma_valid), .dma_xfer_req (dma_xfer_req), .dma_xfer_last (dma_xfer_last), + .dma_last_beats (dma_last_beats_s), .avl_last_address (avl_last_address_s), - .avl_last_byteenable (avl_last_byteenable_s), + .avl_last_burstcount (avl_last_burstcount_s), .avl_clk (avl_clk), .avl_reset (avl_reset), .avl_address (avl_wr_address_s), .avl_burstcount (avl_wr_burstcount_s), .avl_byteenable (avl_wr_byteenable_s), - .avl_ready (avl_ready), - .avl_write (avl_write_s), - .avl_data (avl_writedata_s), - .avl_xfer_req (avl_xfer_out_s) - ); + .avl_waitrequest (~avl_ready), + .avl_write (avl_write), + .avl_data (avl_writedata), + .avl_xfer_req_out (avl_xfer_out_s), + .avl_xfer_req_in (avl_xfer_in_s)); avl_dacfifo_rd #( .AVL_DATA_WIDTH(AVL_DATA_WIDTH), .DAC_DATA_WIDTH(DAC_DATA_WIDTH), .AVL_DDR_BASE_ADDRESS(AVL_BASE_ADDRESS), .AVL_DDR_ADDRESS_LIMIT(AVL_ADDRESS_LIMIT), - .DAC_MEM_ADDRESS_WIDTH(DAC_MEM_ADDRESS_WIDTH) + .DAC_MEM_ADDRESS_WIDTH(DAC_MEM_ADDRESS_WIDTH), + .AVL_BURST_LENGTH (AVL_BURST_LENGTH) ) i_rd ( .dac_clk(dac_clk), .dac_reset(dac_rst), @@ -163,49 +165,29 @@ module avl_dacfifo #( .avl_address(avl_rd_address_s), .avl_burstcount(avl_rd_burstcount_s), .avl_byteenable(avl_rd_byteenable_s), - .avl_ready(avl_ready), + .avl_waitrequest(~avl_ready), .avl_readdatavalid(avl_readdata_valid), - .avl_read(avl_read_s), + .avl_read(avl_read), .avl_data(avl_readdata), .avl_last_address(avl_last_address_s), - .avl_last_byteenable(avl_last_byteenable_s), - .avl_xfer_req(avl_xfer_out_s)); + .avl_last_burstcount(avl_last_burstcount_s), + .dma_last_beats(dma_last_beats_s), + .avl_xfer_req_in(avl_xfer_out_s), + .avl_xfer_req_out(avl_xfer_in_s)); // avalon address multiplexer and output registers - always @(posedge avl_clk) begin - avl_dma_xfer_req_m1 <= dma_xfer_req; - avl_dma_xfer_req <= avl_dma_xfer_req_m1; - end - - always @(posedge avl_clk) begin - if (avl_reset == 1'b1) begin - avl_xfer_wren <= 1'b0; - end else begin - if (avl_dma_xfer_req == 1'b1) begin - avl_xfer_wren <= 1'b1; - end - if (avl_xfer_out_s == 1'b1) begin - avl_xfer_wren <= 1'b0; - end - end - end + assign avl_xfer_wren_s = ~avl_xfer_in_s; always @(posedge avl_clk) begin if (avl_reset == 1'b1) begin avl_address <= 0; avl_burstcount <= 0; avl_byteenable <= 0; - avl_read <= 0; - avl_write <= 0; - avl_writedata <= 0; - end else begin - avl_address <= (avl_xfer_wren == 1'b1) ? avl_wr_address_s : avl_rd_address_s; - avl_burstcount <= (avl_xfer_wren == 1'b1) ? avl_wr_burstcount_s : avl_rd_burstcount_s; - avl_byteenable <= (avl_xfer_wren == 1'b1) ? avl_wr_byteenable_s : avl_rd_byteenable_s; - avl_read <= avl_read_s; - avl_write <= avl_write_s; - avl_writedata <= avl_writedata_s; + end else if (avl_ready) begin + avl_address <= (avl_xfer_wren_s == 1'b1) ? avl_wr_address_s : avl_rd_address_s; + avl_burstcount <= (avl_xfer_wren_s == 1'b1) ? avl_wr_burstcount_s : avl_rd_burstcount_s; + avl_byteenable <= (avl_xfer_wren_s == 1'b1) ? avl_wr_byteenable_s : avl_rd_byteenable_s; end end @@ -255,7 +237,7 @@ module avl_dacfifo #( if (dac_valid) begin dac_data <= (dac_bypass) ? dac_data_bypass_s : dac_data_fifo_s; end - dac_xfer_out_int <= (dac_bypass) ? dac_xfer_out_bypass : dac_xfer_fifo_out_s; + dac_xfer_out <= (dac_bypass) ? dac_xfer_out_bypass : dac_xfer_fifo_out_s; dac_dunf <= (dac_bypass) ? dac_dunf_bypass_s : dac_dunf_fifo_s; end @@ -268,28 +250,12 @@ module avl_dacfifo #( if (dac_valid) begin dac_data <= dac_data_fifo_s; end - dac_xfer_out_int <= dac_xfer_fifo_out_s; + dac_xfer_out <= dac_xfer_fifo_out_s; dac_dunf <= dac_dunf_fifo_s; end end endgenerate - // the ad_mem_asym memory read interface has a 3 clock cycle delay, from the - // moment of the address change until a valid data arrives on the bus; - // because the dac_xfer_out is going to validate the outgoing samples (in conjunction - // with the DAC VALID, which is free a running signal), this module will compensate - // this delay, to prevent duplicated samples in the beginning of the - // transaction - - util_delay #( - .DATA_WIDTH(1), - .DELAY_CYCLES(3) - ) i_delay ( - .clk(dac_clk), - .reset(dac_rst), - .din(dac_xfer_out_int), - .dout(dac_xfer_out)); - endmodule diff --git a/library/altera/avl_dacfifo/avl_dacfifo_constr.sdc b/library/altera/avl_dacfifo/avl_dacfifo_constr.sdc index c98781fde..d2476e841 100644 --- a/library/altera/avl_dacfifo/avl_dacfifo_constr.sdc +++ b/library/altera/avl_dacfifo/avl_dacfifo_constr.sdc @@ -1,36 +1,36 @@ # CDC paths -set_false_path -from [get_registers *avl_dacfifo_rd:i_rd|dac_mem_rd_address_g*] \ - -to [get_registers *avl_dacfifo_rd:i_rd|avl_mem_rd_address_m1*] -set_false_path -from [get_registers *avl_dacfifo_rd:i_rd|avl_mem_wr_address_g*] \ - -to [get_registers *avl_dacfifo_rd:i_rd|dac_mem_wr_address_m1*] -set_false_path -from [get_registers *avl_dacfifo_wr:i_wr|avl_xfer_req*] \ - -to [get_registers *avl_dacfifo_rd:i_rd|dac_avl_xfer_req_m1*] +set_false_path -from [get_registers *avl_dacfifo_rd:i_rd|dac_mem_raddr_g*] \ + -to [get_registers *avl_dacfifo_rd:i_rd|avl_mem_raddr_m1*] +set_false_path -from [get_registers *avl_dacfifo_rd:i_rd|avl_mem_waddr_g*] \ + -to [get_registers *avl_dacfifo_rd:i_rd|dac_mem_waddr_m1*] +set_false_path -from [get_registers *avl_dacfifo_rd:i_rd|avl_xfer_req_out*] \ + -to [get_registers *avl_dacfifo_rd:i_rd|dac_avl_xfer_req_m1*] +set_false_path -from [get_registers *avl_dacfifo_rd:i_rd|avl_mem_laddr_toggle*] \ + -to [get_registers *avl_dacfifo_rd:i_rd|dac_mem_laddr_toggle_m[0]] +set_false_path -to [get_registers *avl_dacfifo_rd:i_rd|dac_mem_laddr*] +set_false_path -to [get_registers *avl_dacfifo_rd:i_rd|dac_avl_last_transfer_m1*] +set_false_path -to [get_registers *avl_dacfifo_rd:i_rd|dac_dma_last_beats_m1*] -set_false_path -to [get_registers *avl_dacfifo_rd:i_rd|dac_avl_last_transfer_m1*] -set_false_path -to [get_registers *avl_dacfifo_rd:i_rd|dac_avl_last_beats_m1*] +set_false_path -from [get_registers *avl_dacfifo_wr:i_wr|avl_xfer_req_lp*] \ + -to [get_registers *avl_dacfifo_wr:i_wr|dma_xfer_req_lp_m1*] +set_false_path -from [get_registers *avl_dacfifo_wr:i_wr|avl_xfer_req_out*] \ + -to [get_registers *avl_dacfifo_wr:i_wr|dma_avl_xfer_req_out_m1*] +set_false_path -from [get_registers *avl_dacfifo_wr:i_wr|avl_mem_raddr_g*] \ + -to [get_registers *avl_dacfifo_wr:i_wr|dma_mem_raddr_m1*] +set_false_path -from [get_registers *avl_dacfifo_wr:i_wr|dma_xfer_req*] \ + -to [get_registers *avl_dacfifo_wr:i_wr|avl_dma_xfer_req_m1*] +set_false_path -from [get_registers *avl_dacfifo_wr:i_wr|dma_mem_waddr_g*] \ + -to [get_registers *avl_dacfifo_wr:i_wr|avl_mem_waddr_m1*] +set_false_path -from [get_registers *avl_dacfifo_wr:i_wr|dma_last_beats*] \ + -to [get_registers *avl_dacfifo_wr:i_wr|avl_dma_last_beats_m1*] -set_false_path -from [get_registers *avl_dacfifo_wr:i_wr|avl_mem_rd_address_g*] \ - -to [get_registers *avl_dacfifo_wr:i_wr|dma_mem_rd_address_m1*] -set_false_path -from [get_registers *avl_dacfifo_wr:i_wr|avl_write_xfer_req*] \ - -to [get_registers *avl_dacfifo_wr:i_wr|dma_avl_xfer_req_m1*] -set_false_path -from [get_registers *avl_dacfifo_wr:i_wr|dma_mem_read_control*] \ - -to [get_registers *avl_dacfifo_wr:i_wr|avl_mem_fetch_wr_address_m1*] -set_false_path -from [get_registers *avl_dacfifo_wr:i_wr|dma_last_beat_ack*] \ - -to [get_registers *avl_dacfifo_wr:i_wr|avl_last_beat_req_m1*] -set_false_path -to [get_registers *avl_dacfifo_wr:i_wr|avl_dma_xfer_req_m1*] -set_false_path -from [get_registers *avl_dacfifo_wr:i_wr|dma_mem_wr_address_d*] \ - -to [get_registers *avl_dacfifo_wr:i_wr|avl_mem_wr_address*] +set_false_path -from [get_registers *util_dacfifo_bypass:i_dacfifo_bypass|dac_mem_raddr_g*] \ + -to [get_registers *util_dacfifo_bypass:i_dacfifo_bypass|dma_mem_raddr_m1*] -set_false_path -from [get_registers *avl_dacfifo_wr:i_wr|dma_mem_last_beats*] \ - -to [get_registers *avl_dacfifo_wr:i_wr|avl_last_beats_m1*] - -set_false_path -from [get_registers *util_dacfifo_bypass:i_dacfifo_bypass|dac_mem_raddr_g*] \ - -to [get_registers *util_dacfifo_bypass:i_dacfifo_bypass|dma_mem_raddr_m1*] - -set_false_path -from [get_registers *util_dacfifo_bypass:i_dacfifo_bypass|dma_mem_waddr_g*] \ - -to [get_registers *util_dacfifo_bypass:i_dacfifo_bypass|dac_mem_waddr_m1*] -set_false_path -to [get_registers *util_dacfifo_bypass:i_dacfifo_bypass|dac_xfer_out_m1*] +set_false_path -from [get_registers *util_dacfifo_bypass:i_dacfifo_bypass|dma_mem_waddr_g*] \ + -to [get_registers *util_dacfifo_bypass:i_dacfifo_bypass|dac_mem_waddr_m1*] +set_false_path -to [get_registers *util_dacfifo_bypass:i_dacfifo_bypass|dac_xfer_out_m1*] set_false_path -to [get_registers *avl_dacfifo:*avl_dma_xfer_req_m1*] set_false_path -to [get_registers *avl_dacfifo:*dac_xfer_out_m1*] diff --git a/library/altera/avl_dacfifo/avl_dacfifo_hw.tcl b/library/altera/avl_dacfifo/avl_dacfifo_hw.tcl index 75eaa0a03..6c3c3473b 100644 --- a/library/altera/avl_dacfifo/avl_dacfifo_hw.tcl +++ b/library/altera/avl_dacfifo/avl_dacfifo_hw.tcl @@ -3,12 +3,12 @@ package require qsys source ../../scripts/adi_env.tcl source ../../scripts/adi_ip_alt.tcl -ad_ip_create avl_dacfifo {Avalon DDR DAC Fifo} -set_module_property ELABORATION_CALLBACK p_avl_dacfifo +ad_ip_create avl_dacfifo {Avalon DDR DAC Fifo} p_avl_dacfifo_elab ad_ip_files avl_dacfifo [list\ $ad_hdl_dir/library/common/util_delay.v \ $ad_hdl_dir/library/common/ad_b2g.v \ $ad_hdl_dir/library/common/ad_g2b.v \ + $ad_hdl_dir/library/common/ad_mem.v \ util_dacfifo_bypass.v \ avl_dacfifo_byteenable_coder.v \ avl_dacfifo_byteenable_decoder.v \ @@ -26,6 +26,7 @@ ad_ip_parameter DMA_DATA_WIDTH INTEGER 64 ad_ip_parameter DMA_MEM_ADDRESS_WIDTH INTEGER 8 ad_ip_parameter AVL_DATA_WIDTH INTEGER 512 ad_ip_parameter AVL_ADDRESS_WIDTH INTEGER 25 +ad_ip_parameter AVL_BURST_LENGTH INTEGER 127 ad_ip_parameter AVL_BASE_ADDRESS INTEGER 0 ad_ip_parameter AVL_ADDRESS_LIMIT INTEGER 0x800000 @@ -72,7 +73,7 @@ set_interface_property amm_ddr addressUnits WORDS # elaborate -proc p_avl_dacfifo {} { +proc p_avl_dacfifo_elab {} { # read parameters diff --git a/library/altera/avl_dacfifo/avl_dacfifo_rd.v b/library/altera/avl_dacfifo/avl_dacfifo_rd.v index cbcce0c75..cefd38ae1 100644 --- a/library/altera/avl_dacfifo/avl_dacfifo_rd.v +++ b/library/altera/avl_dacfifo/avl_dacfifo_rd.v @@ -39,6 +39,7 @@ module avl_dacfifo_rd #( parameter AVL_DATA_WIDTH = 512, parameter DAC_DATA_WIDTH = 64, + parameter AVL_BURST_LENGTH = 127, parameter AVL_DDR_BASE_ADDRESS = 0, parameter AVL_DDR_ADDRESS_LIMIT = 1048576, parameter DAC_MEM_ADDRESS_WIDTH = 8)( @@ -53,16 +54,18 @@ module avl_dacfifo_rd #( input avl_clk, input avl_reset, output reg [24:0] avl_address, - output reg [ 5:0] avl_burstcount, - output reg [63:0] avl_byteenable, - input avl_ready, + output reg [ 6:0] avl_burstcount, + output [63:0] avl_byteenable, + input avl_waitrequest, input avl_readdatavalid, output reg avl_read, input [AVL_DATA_WIDTH-1:0] avl_data, input [24:0] avl_last_address, - input [63:0] avl_last_byteenable, - input avl_xfer_req); + input [ 6:0] avl_last_burstcount, + input [ 7:0] dma_last_beats, + input avl_xfer_req_in, + output reg avl_xfer_req_out); // Max supported MEM_RATIO is 16 localparam MEM_RATIO = AVL_DATA_WIDTH/DAC_DATA_WIDTH; @@ -72,186 +75,296 @@ module avl_dacfifo_rd #( (MEM_RATIO == 8) ? (DAC_MEM_ADDRESS_WIDTH - 3) : (MEM_RATIO == 16) ? (DAC_MEM_ADDRESS_WIDTH - 4) : (DAC_MEM_ADDRESS_WIDTH - 5); - localparam AVL_MEM_THRESHOLD_LO = 8; - localparam AVL_MEM_THRESHOLD_HI = {(AVL_MEM_ADDRESS_WIDTH){1'b1}} - 7; + localparam AVL_MEM_THRESHOLD_LO = AVL_BURST_LENGTH; + localparam AVL_MEM_THRESHOLD_HI = {(AVL_MEM_ADDRESS_WIDTH){1'b1}} - AVL_BURST_LENGTH; + localparam DAC_MEM_THRESHOLD = 2 * (AVL_BURST_LENGTH * MEM_RATIO); localparam MEM_WIDTH_DIFF = (MEM_RATIO > 16) ? 5 : (MEM_RATIO > 8) ? 4 : (MEM_RATIO > 4) ? 3 : (MEM_RATIO > 2) ? 2 : (MEM_RATIO > 1) ? 1 : 1; + localparam AVL_BYTE_DATA_WIDTH = AVL_DATA_WIDTH/8; + localparam AVL_ARINCR = AVL_BURST_LENGTH * AVL_BYTE_DATA_WIDTH; + + // FSM state definition + + localparam IDLE = 5'b00001; + localparam XFER_STAGING = 5'b00010; + localparam XFER_FULL_BURST = 5'b00100; + localparam XFER_PARTIAL_BURST = 5'b01000; + localparam XFER_END = 5'b10000; + // internal register - reg [AVL_MEM_ADDRESS_WIDTH-1:0] avl_mem_wr_address; - reg [AVL_MEM_ADDRESS_WIDTH-1:0] avl_mem_wr_address_g; - reg [DAC_MEM_ADDRESS_WIDTH-1:0] avl_mem_rd_address; - reg [DAC_MEM_ADDRESS_WIDTH-1:0] avl_mem_rd_address_m1; - reg [DAC_MEM_ADDRESS_WIDTH-1:0] avl_mem_rd_address_m2; - reg avl_mem_wr_enable; + reg [AVL_MEM_ADDRESS_WIDTH-1:0] avl_mem_waddr; + reg [AVL_MEM_ADDRESS_WIDTH-1:0] avl_mem_laddr; + reg avl_mem_laddr_toggle; + reg [AVL_MEM_ADDRESS_WIDTH-1:0] avl_mem_waddr_g; + reg [DAC_MEM_ADDRESS_WIDTH-1:0] avl_mem_raddr; + reg [DAC_MEM_ADDRESS_WIDTH-1:0] avl_mem_raddr_m1; + reg [DAC_MEM_ADDRESS_WIDTH-1:0] avl_mem_raddr_m2; reg avl_mem_request_data; - reg [AVL_DATA_WIDTH-1:0] avl_mem_data; - reg [AVL_MEM_ADDRESS_WIDTH-1:0] avl_mem_address_diff; - reg avl_read_inprogress; - reg avl_last_transfer; + reg [AVL_MEM_ADDRESS_WIDTH-1:0] avl_mem_addr_diff; + reg [ 4:0] avl_read_state; + reg [ 7:0] avl_burstcounter; + reg avl_read_int; + reg avl_inread; + + reg [AVL_MEM_ADDRESS_WIDTH-1:0] dac_mem_waddr; + reg [AVL_MEM_ADDRESS_WIDTH-1:0] dac_mem_waddr_m1; + reg [AVL_MEM_ADDRESS_WIDTH-1:0] dac_mem_waddr_m2; + reg [DAC_MEM_ADDRESS_WIDTH-1:0] dac_mem_laddr; + reg [DAC_MEM_ADDRESS_WIDTH-1:0] dac_mem_raddr; + reg [DAC_MEM_ADDRESS_WIDTH-1:0] dac_mem_raddr_g; + reg [DAC_MEM_ADDRESS_WIDTH-1:0] dac_mem_addr_diff; + reg [ 7:0] dac_mem_laddr_waddr; + reg [ 7:0] dac_mem_laddr_raddr; - reg [AVL_MEM_ADDRESS_WIDTH-1:0] dac_mem_wr_address; - reg [AVL_MEM_ADDRESS_WIDTH-1:0] dac_mem_wr_address_m1; - reg [AVL_MEM_ADDRESS_WIDTH-1:0] dac_mem_wr_address_m2; - reg [DAC_MEM_ADDRESS_WIDTH-1:0] dac_mem_wr_last_address; - reg [DAC_MEM_ADDRESS_WIDTH-1:0] dac_mem_rd_address; - reg [DAC_MEM_ADDRESS_WIDTH-1:0] dac_mem_rd_address_g; - reg [DAC_MEM_ADDRESS_WIDTH-1:0] dac_mem_address_diff; - reg [DAC_MEM_ADDRESS_WIDTH-1:0] dac_mem_rd_last_address; - reg dac_mem_last_transfer_active; reg dac_avl_xfer_req; reg dac_avl_xfer_req_m1; reg dac_avl_xfer_req_m2; - reg dac_avl_last_transfer_m1; - reg dac_avl_last_transfer_m2; - reg dac_avl_last_transfer; - reg [MEM_WIDTH_DIFF-1:0] dac_avl_last_beats_m1; - reg [MEM_WIDTH_DIFF-1:0] dac_avl_last_beats_m2; - reg [MEM_WIDTH_DIFF-1:0] dac_avl_last_beats; + reg [ 7:0] dac_dma_last_beats_m1; + reg [ 7:0] dac_dma_last_beats_m2; + reg [ 7:0] dac_dma_last_beats; + reg [ 3:0] dac_mem_laddr_toggle_m; + reg [DAC_MEM_ADDRESS_WIDTH-1:0] dac_mem_laddr_b; + reg dac_mem_renable; + reg dac_mem_valid; + reg dac_xfer_req_b; // internal signals - wire [AVL_MEM_ADDRESS_WIDTH-1:0] avl_mem_rd_address_s; - wire [AVL_MEM_ADDRESS_WIDTH:0] avl_mem_address_diff_s; - wire [DAC_MEM_ADDRESS_WIDTH:0] dac_mem_address_diff_s; + wire avl_fifo_reset_s; + wire [AVL_MEM_ADDRESS_WIDTH-1:0] avl_mem_raddr_s; + wire [AVL_MEM_ADDRESS_WIDTH:0] avl_mem_addr_diff_s; + wire [AVL_MEM_ADDRESS_WIDTH-1:0] avl_mem_waddr_b2g_s; + wire [DAC_MEM_ADDRESS_WIDTH-1:0] avl_mem_raddr_g2b_s; + wire [DAC_MEM_ADDRESS_WIDTH-1:0] avl_mem_laddr_s; + wire avl_read_int_s; - wire [DAC_MEM_ADDRESS_WIDTH:0] dac_mem_wr_address_s; - wire [AVL_MEM_ADDRESS_WIDTH-1:0] dac_mem_wr_address_g2b_s; - wire [AVL_MEM_ADDRESS_WIDTH-1:0] avl_mem_wr_address_b2g_s; - wire [DAC_MEM_ADDRESS_WIDTH-1:0] avl_mem_rd_address_g2b_s; - wire [DAC_MEM_ADDRESS_WIDTH-1:0] dac_mem_rd_address_b2g_s; - wire dac_mem_rd_enable_s; + wire dac_fifo_reset_s; + wire [DAC_MEM_ADDRESS_WIDTH:0] dac_mem_addr_diff_s; + wire [DAC_MEM_ADDRESS_WIDTH-1:0] dac_mem_waddr_s; + wire [AVL_MEM_ADDRESS_WIDTH-1:0] dac_mem_waddr_g2b_s; + wire [DAC_MEM_ADDRESS_WIDTH-1:0] dac_mem_raddr_b2g_s; wire [DAC_DATA_WIDTH-1:0] dac_mem_data_s; + wire dac_mem_laddr_wea_s; + wire dac_mem_laddr_rea_s; + wire [DAC_MEM_ADDRESS_WIDTH-1:0] dac_mem_laddr_s; + wire dac_mem_dunf_s; + wire dac_xfer_req_s; - wire [MEM_WIDTH_DIFF-1:0] avl_last_beats_s; - wire avl_last_transfer_s; - wire avl_read_en_s; - wire avl_mem_wr_enable_s; - wire avl_last_readdatavalid_s; - - // ========================================================================== // An asymmetric memory to transfer data from Avalon interface to DAC // interface - // ========================================================================== alt_mem_asym_rd i_mem_asym ( .mem_i_wrclock (avl_clk), - .mem_i_wren (avl_mem_wr_enable), - .mem_i_wraddress (avl_mem_wr_address), - .mem_i_datain (avl_mem_data), + .mem_i_wren (avl_readdatavalid), + .mem_i_wraddress (avl_mem_waddr), + .mem_i_datain (avl_data), .mem_i_rdclock (dac_clk), - .mem_i_rdaddress (dac_mem_rd_address), + .mem_i_rdaddress (dac_mem_raddr), .mem_o_dataout (dac_mem_data_s)); - // ========================================================================== - // Avalon Memory Mapped interface access - // ========================================================================== + // the fifo reset is the dma_xfer_req + + assign avl_fifo_reset_s = avl_reset || ~avl_xfer_req_out; + assign dac_fifo_reset_s = dac_reset || ~dac_avl_xfer_req; + + // loop back the avl_xfer_req to the WRITE module -- this way we can make + // sure, that in case of a new DMA transfer, the last avalon read burst is + // finished, so the upcomming avalon writes will not block the interface + + always @(posedge avl_clk) begin + if (avl_reset == 1'b1) begin + avl_xfer_req_out <= 1'b0; + end else begin + if ((avl_read_state == IDLE) || (avl_read_state == XFER_STAGING)) begin + avl_xfer_req_out <= avl_xfer_req_in; + end + end + end + + // FSM to generate the necessary Avalon Write transactions + + always @(posedge avl_clk) begin + if (avl_fifo_reset_s == 1'b1) begin + avl_read_state <= IDLE; + end else begin + case (avl_read_state) + IDLE : begin + if (avl_xfer_req_in == 1'b1) begin + avl_read_state <= XFER_STAGING; + end else begin + avl_read_state <= IDLE; + end + end + XFER_STAGING : begin + if (avl_mem_request_data == 1'b1) begin + if (avl_address + AVL_ARINCR <= avl_last_address) begin + avl_read_state <= XFER_FULL_BURST; + end else begin + avl_read_state <= XFER_PARTIAL_BURST; + end + end + end + // Avalon transaction with full burst length + XFER_FULL_BURST : begin + if (avl_burstcounter < avl_burstcount) begin + avl_read_state <= XFER_FULL_BURST; + end else begin + avl_read_state <= XFER_END; + end + end + // Avalon transaction with the remaining data, burst length is less than + // the maximum supported burst length + XFER_PARTIAL_BURST : begin + if (avl_burstcounter < avl_burstcount) begin + avl_read_state <= XFER_PARTIAL_BURST; + end else begin + avl_read_state <= XFER_END; + end + end + XFER_END : begin + avl_read_state <= IDLE; + end + default : begin + avl_read_state <= IDLE; + end + endcase + end + end + + // FSM outputs + + assign avl_read_int_s = ((avl_read_state == XFER_FULL_BURST) || + (avl_read_state == XFER_PARTIAL_BURST)) ? 1 : 0; // Avalon address generation and read control signaling always @(posedge avl_clk) begin - if ((avl_reset == 1'b1) || (avl_xfer_req == 1'b0)) begin + if (avl_fifo_reset_s == 1'b1) begin avl_address <= AVL_DDR_BASE_ADDRESS; end else begin - if (avl_readdatavalid == 1'b1) begin - avl_address <= (avl_address < avl_last_address) ? avl_address + 1 : 0; + if (avl_read_state == XFER_END) begin + avl_address <= (avl_address < avl_last_address) ? avl_address + (avl_burstcount * AVL_BYTE_DATA_WIDTH) : AVL_DDR_BASE_ADDRESS; end end end - assign avl_read_en_s = avl_xfer_req & avl_mem_request_data; - always @(posedge avl_clk) begin if (avl_reset == 1'b1) begin avl_read <= 1'b0; - avl_read_inprogress <= 1'b0; + avl_inread <= 1'b0; + avl_read_int <= 1'b0; end else begin - if ((avl_read_inprogress == 1'b0) && (avl_read_en_s == 1'b1)) begin - avl_read <= 1'b1; - avl_read_inprogress <= 1'b1; - end else if (avl_read_inprogress == 1'b1) begin - avl_read <= 1'b0; - if (avl_readdatavalid == 1'b1) begin - avl_read_inprogress <= 1'b0; + avl_read_int <= avl_read_int_s; + if (avl_read == 1'b0) begin + if ((avl_waitrequest == 1'b0) && (avl_read_int == 1'b1) && (avl_inread == 1'b0)) begin + avl_read <= 1'b1; + avl_inread <= 1'b1; end + end else if ((avl_read == 1'b1) && (avl_waitrequest == 1'b0)) begin + avl_read <= 1'b0; + end + if (avl_read_state == XFER_END) begin + avl_inread <= 1'b0; end end end - assign avl_last_transfer_s = (avl_address == avl_last_address) ? 1'b1 : 1'b0; + // Avalon burstcount + always @(posedge avl_clk) begin - avl_burstcount <= 1'b1; - avl_byteenable <= (avl_last_transfer_s) ? avl_last_byteenable : {64{1'b1}}; - avl_last_transfer <= avl_last_transfer_s; + if (avl_fifo_reset_s == 1'b1) begin + avl_burstcounter <= 8'b0; + end else begin + if ((avl_read_int == 1'b1) && (avl_readdatavalid == 1'b1)) begin + avl_burstcounter <= (avl_burstcounter < avl_burstcount) ? avl_burstcounter + 1'b1 : 1'b0; + end else if (avl_read_state == XFER_END) begin + avl_burstcounter <= 8'b0; + end + end end + always @(posedge avl_clk) begin + if (avl_fifo_reset_s) begin + avl_burstcount <= 'b0; + end else begin + if (avl_read_state == XFER_PARTIAL_BURST) begin + avl_burstcount <= avl_last_burstcount; + end else begin + avl_burstcount <= AVL_BURST_LENGTH; + end + end + end + + assign avl_byteenable = {64{1'b1}}; + // write data from Avalon interface into the async FIFO - assign avl_mem_wr_enable_s = avl_readdatavalid & avl_ready; always @(posedge avl_clk) begin - if (avl_reset == 1'b1) begin - avl_mem_data <= 0; - avl_mem_wr_enable <= 0; + if (avl_fifo_reset_s == 1'b1) begin + avl_mem_waddr <= 'b0; + avl_mem_waddr_g <= 'b0; + avl_mem_laddr <= 'b0; + avl_mem_laddr_toggle <= 1'b0; end else begin - avl_mem_wr_enable <= avl_mem_wr_enable_s; - if (avl_mem_wr_enable_s == 1'b1) begin - avl_mem_data <= avl_data; + if (avl_readdatavalid == 1'b1) begin + avl_mem_waddr <= avl_mem_waddr + 1'b1; end - end - end - - always @(posedge avl_clk) begin - if ((avl_reset == 1'b1) || (avl_xfer_req == 1'b0)) begin - avl_mem_wr_address <= 0; - avl_mem_wr_address_g <= 0; - end else begin - if (avl_mem_wr_enable == 1'b1) begin - avl_mem_wr_address <= avl_mem_wr_address + 1; + if (avl_read_state == XFER_END) begin + avl_mem_laddr <= avl_mem_waddr - 1'b1; + avl_mem_laddr_toggle <= ~avl_mem_laddr_toggle; end - avl_mem_wr_address_g <= avl_mem_wr_address_b2g_s; + avl_mem_waddr_g <= avl_mem_waddr_b2g_s; end end ad_b2g #( .DATA_WIDTH(AVL_MEM_ADDRESS_WIDTH) - ) i_avl_mem_wr_address_b2g ( - .din (avl_mem_wr_address), - .dout (avl_mem_wr_address_b2g_s)); + ) i_avl_mem_wr_addr_b2g ( + .din (avl_mem_waddr), + .dout (avl_mem_waddr_b2g_s)); - // ========================================================================== // control the FIFO to prevent overflow, underflow is monitored - // ========================================================================== - assign avl_mem_rd_address_s = (MEM_RATIO == 1) ? avl_mem_rd_address : - (MEM_RATIO == 2) ? avl_mem_rd_address[(DAC_MEM_ADDRESS_WIDTH-1):1] : - (MEM_RATIO == 4) ? avl_mem_rd_address[(DAC_MEM_ADDRESS_WIDTH-1):2] : - (MEM_RATIO == 8) ? avl_mem_rd_address[(DAC_MEM_ADDRESS_WIDTH-1):3] : - (MEM_RATIO == 16) ? avl_mem_rd_address[(DAC_MEM_ADDRESS_WIDTH-1):4] : - avl_mem_rd_address[(DAC_MEM_ADDRESS_WIDTH-1):5]; + assign avl_mem_raddr_s = (MEM_RATIO == 1) ? avl_mem_raddr : + (MEM_RATIO == 2) ? avl_mem_raddr[(DAC_MEM_ADDRESS_WIDTH-1):1] : + (MEM_RATIO == 4) ? avl_mem_raddr[(DAC_MEM_ADDRESS_WIDTH-1):2] : + (MEM_RATIO == 8) ? avl_mem_raddr[(DAC_MEM_ADDRESS_WIDTH-1):3] : + (MEM_RATIO == 16) ? avl_mem_raddr[(DAC_MEM_ADDRESS_WIDTH-1):4] : + avl_mem_raddr[(DAC_MEM_ADDRESS_WIDTH-1):5]; - assign avl_mem_address_diff_s = {1'b1, avl_mem_wr_address} - avl_mem_rd_address_s; + assign avl_mem_laddr_s = (MEM_RATIO == 1) ? avl_mem_laddr : + (MEM_RATIO == 2) ? {avl_mem_laddr, 1'b0} : + (MEM_RATIO == 4) ? {avl_mem_laddr, 2'b0} : + (MEM_RATIO == 8) ? {avl_mem_laddr, 3'b0} : + (MEM_RATIO == 16) ? {avl_mem_laddr, 4'b0} : + {avl_mem_laddr, 5'b0}; + + assign avl_mem_addr_diff_s = {1'b1, avl_mem_waddr} - avl_mem_raddr_s; always @(posedge avl_clk) begin - if (avl_xfer_req == 1'b0) begin - avl_mem_address_diff <= 'd0; - avl_mem_rd_address <= 'd0; - avl_mem_rd_address_m1 <= 'd0; - avl_mem_rd_address_m2 <= 'd0; + if (avl_fifo_reset_s == 1'b1) begin + avl_mem_addr_diff <= 'd0; + avl_mem_raddr <= 'd0; + avl_mem_raddr_m1 <= 'd0; + avl_mem_raddr_m2 <= 'd0; avl_mem_request_data <= 'd0; end else begin - avl_mem_rd_address_m1 <= dac_mem_rd_address_g; - avl_mem_rd_address_m2 <= avl_mem_rd_address_m1; - avl_mem_rd_address <= avl_mem_rd_address_g2b_s; - avl_mem_address_diff <= avl_mem_address_diff_s[AVL_MEM_ADDRESS_WIDTH-1:0]; - if (avl_mem_address_diff >= AVL_MEM_THRESHOLD_HI) begin + avl_mem_raddr_m1 <= dac_mem_raddr_g; + avl_mem_raddr_m2 <= avl_mem_raddr_m1; + avl_mem_raddr <= avl_mem_raddr_g2b_s; + avl_mem_addr_diff <= avl_mem_addr_diff_s[AVL_MEM_ADDRESS_WIDTH-1:0]; + if (avl_xfer_req_out == 1'b0) begin avl_mem_request_data <= 1'b0; - end else if (avl_mem_address_diff <= AVL_MEM_THRESHOLD_LO) begin + end else if (avl_mem_addr_diff >= AVL_MEM_THRESHOLD_HI) begin + avl_mem_request_data <= 1'b0; + end else if (avl_mem_addr_diff <= AVL_MEM_THRESHOLD_LO) begin avl_mem_request_data <= 1'b1; end end @@ -259,75 +372,91 @@ module avl_dacfifo_rd #( ad_g2b #( .DATA_WIDTH(DAC_MEM_ADDRESS_WIDTH) - ) i_avl_mem_rd_address_g2b ( - .din (avl_mem_rd_address_m2), - .dout (avl_mem_rd_address_g2b_s)); + ) i_avl_mem_rd_addr_g2b ( + .din (avl_mem_raddr_m2), + .dout (avl_mem_raddr_g2b_s)); - avl_dacfifo_byteenable_decoder #( - .MEM_RATIO (MEM_RATIO), - .LAST_BEATS_WIDTH (MEM_WIDTH_DIFF) - ) i_byteenable_decoder ( - .avl_clk (avl_clk), - .avl_byteenable (avl_last_byteenable), - .avl_enable (1'b1), - .avl_last_beats (avl_last_beats_s) - ); - - // ========================================================================== // Push data from the async FIFO to the DAC // Data flow is controlled by the DAC, no back-pressure. If FIFO is not // ready, data will be dropped - // ========================================================================== - assign dac_mem_wr_address_s = (MEM_RATIO == 1) ? dac_mem_wr_address : - (MEM_RATIO == 2) ? {dac_mem_wr_address, 1'b0} : - (MEM_RATIO == 4) ? {dac_mem_wr_address, 2'b0} : - (MEM_RATIO == 8) ? {dac_mem_wr_address, 3'b0} : - (MEM_RATIO == 16) ? {dac_mem_wr_address, 4'b0} : - {dac_mem_wr_address, 5'b0}; + assign dac_mem_waddr_s = (MEM_RATIO == 1) ? dac_mem_waddr : + (MEM_RATIO == 2) ? {dac_mem_waddr, 1'b0} : + (MEM_RATIO == 4) ? {dac_mem_waddr, 2'b0} : + (MEM_RATIO == 8) ? {dac_mem_waddr, 3'b0} : + (MEM_RATIO == 16) ? {dac_mem_waddr, 4'b0} : + {dac_mem_waddr, 5'b0}; - assign dac_mem_address_diff_s = {1'b1, dac_mem_wr_address_s} - dac_mem_rd_address; + assign dac_mem_addr_diff_s = {1'b1, dac_mem_waddr_s} - dac_mem_raddr; always @(posedge dac_clk) begin if (dac_reset == 1'b1) begin - dac_mem_wr_address_m2 <= 0; - dac_mem_wr_address_m1 <= 0; - dac_mem_wr_address <= 0; - dac_mem_wr_last_address <= 0; + dac_mem_waddr_m2 <= 0; + dac_mem_waddr_m1 <= 0; + dac_mem_waddr <= 0; + dac_mem_laddr <= 0; + dac_mem_laddr_toggle_m <= 4'b0; end else begin - dac_mem_wr_address_m1 <= avl_mem_wr_address_g; - dac_mem_wr_address_m2 <= dac_mem_wr_address_m1; - dac_mem_wr_address <= dac_mem_wr_address_g2b_s; - dac_mem_wr_last_address <= (dac_avl_last_transfer == 1'b1) ? dac_mem_wr_address_s : dac_mem_wr_last_address; + dac_mem_waddr_m1 <= avl_mem_waddr_g; + dac_mem_waddr_m2 <= dac_mem_waddr_m1; + dac_mem_waddr <= dac_mem_waddr_g2b_s; + dac_mem_laddr_toggle_m <= {dac_mem_laddr_toggle_m[2:0], avl_mem_laddr_toggle}; + dac_mem_laddr <= (dac_mem_laddr_toggle_m[2] ^ dac_mem_laddr_toggle_m[1]) ? + avl_mem_laddr_s : + dac_mem_laddr; end end + // A buffer for storing the dac_mem_laddr (the address of the last avalon + // beat inside the CDC fifo) + // If the stored data sequence is smaller, it can happen that multiple + // dac_mem_laddr values exist in the same time. This buffers stores this + // values and make sure that they are feeded to the read logic in order. + + assign dac_mem_laddr_wea_s = dac_mem_laddr_toggle_m[3] ^ dac_mem_laddr_toggle_m[2]; + assign dac_mem_laddr_rea_s = ((dac_mem_raddr == dac_mem_laddr_b) && + (dac_xfer_req == 1'b1)) ? 1'b1 :1'b0; + + always @(posedge dac_clk) begin + if (dac_fifo_reset_s == 1'b1) begin + dac_mem_laddr_waddr <= 0; + dac_mem_laddr_raddr <= 0; + end else begin + dac_mem_laddr_waddr <= (dac_mem_laddr_wea_s == 1'b1) ? dac_mem_laddr_waddr + 1 : dac_mem_laddr_waddr; + dac_mem_laddr_raddr <= (dac_mem_laddr_rea_s == 1'b1) ? dac_mem_laddr_raddr + 1 : dac_mem_laddr_raddr; + end + end + + ad_mem #( + .DATA_WIDTH (DAC_MEM_ADDRESS_WIDTH), + .ADDRESS_WIDTH (8)) + i_mem ( + .clka (dac_clk), + .wea (dac_mem_laddr_wea_s), + .addra (dac_mem_laddr_waddr), + .dina (dac_mem_laddr), + .clkb (dac_clk), + .addrb (dac_mem_laddr_raddr), + .doutb (dac_mem_laddr_s)); + ad_g2b #( .DATA_WIDTH(AVL_MEM_ADDRESS_WIDTH) - ) i_dac_mem_wr_address_g2b ( - .din (dac_mem_wr_address_m2), - .dout (dac_mem_wr_address_g2b_s)); - - assign avl_last_readdatavalid_s = (avl_last_transfer & avl_readdatavalid); - always @(posedge dac_clk) begin - if (dac_reset == 1'b1) begin - dac_avl_last_transfer_m1 <= 0; - dac_avl_last_transfer_m2 <= 0; - dac_avl_last_transfer <= 0; - end else begin - dac_avl_last_transfer_m1 <= avl_last_readdatavalid_s; - dac_avl_last_transfer_m2 <= dac_avl_last_transfer_m1; - dac_avl_last_transfer <= dac_avl_last_transfer_m2; - end - end + ) i_dac_mem_wr_addr_g2b ( + .din (dac_mem_waddr_m2), + .dout (dac_mem_waddr_g2b_s)); + assign dac_xfer_req_s = dac_avl_xfer_req & dac_mem_valid; always @(posedge dac_clk) begin if (dac_reset == 1'b1) begin dac_avl_xfer_req_m2 <= 0; dac_avl_xfer_req_m1 <= 0; dac_avl_xfer_req <= 0; + dac_xfer_req_b <= 1'b0; + dac_xfer_req <= 1'b0; end else begin - dac_avl_xfer_req_m1 <= avl_xfer_req; + dac_xfer_req_b <= dac_xfer_req_s; + dac_xfer_req <= dac_xfer_req_b; + dac_avl_xfer_req_m1 <= avl_xfer_req_out; dac_avl_xfer_req_m2 <= dac_avl_xfer_req_m1; dac_avl_xfer_req <= dac_avl_xfer_req_m2; end @@ -335,67 +464,60 @@ module avl_dacfifo_rd #( always @(posedge dac_clk) begin if (dac_reset == 1'b1) begin - dac_mem_last_transfer_active <= 1'b0; + dac_dma_last_beats_m2 <= 0; + dac_dma_last_beats_m1 <= 0; + dac_dma_last_beats <= 0; end else begin - if (dac_avl_last_transfer == 1'b1) begin - dac_mem_last_transfer_active <= 1'b1; - end else if (dac_mem_rd_address == dac_mem_rd_last_address) begin - dac_mem_last_transfer_active <= 1'b0; - end + dac_dma_last_beats_m1 <= dma_last_beats; + dac_dma_last_beats_m2 <= dac_dma_last_beats_m1; + dac_dma_last_beats <= dac_dma_last_beats_m2; end end always @(posedge dac_clk) begin - if (dac_reset == 1'b1) begin - dac_avl_last_beats_m2 <= 0; - dac_avl_last_beats_m1 <= 0; - dac_avl_last_beats <= 0; + if (dac_fifo_reset_s == 1'b1) begin + dac_mem_renable = 1'b0; + dac_mem_valid = 1'b0; end else begin - dac_avl_last_beats_m1 <= avl_last_beats_s; - dac_avl_last_beats_m2 <= dac_avl_last_beats_m1; - dac_avl_last_beats <= dac_avl_last_beats_m2; + if (dac_mem_dunf_s == 1'b1) begin + dac_mem_renable = 1'b0; + end else if (dac_mem_addr_diff_s[DAC_MEM_ADDRESS_WIDTH-1:0] >= DAC_MEM_THRESHOLD) begin + dac_mem_renable = 1'b1; + end + dac_mem_valid <= (dac_mem_renable) ? dac_valid : 1'b0; end end - assign dac_mem_rd_enable_s = (dac_mem_address_diff[DAC_MEM_ADDRESS_WIDTH-1:0] == 1'b0) ? 0 : (dac_xfer_req & dac_valid); + assign dac_mem_dunf_s = (dac_mem_addr_diff_s[DAC_MEM_ADDRESS_WIDTH-1:0] == {DAC_MEM_ADDRESS_WIDTH{1'b0}}) ? 1'b1 : 1'b0; always @(posedge dac_clk) begin - if ((dac_reset == 1'b1) || ((dac_avl_xfer_req == 1'b0) && (dac_xfer_req == 1'b0))) begin - dac_mem_rd_address <= 0; - dac_mem_rd_address_g <= 0; - dac_mem_address_diff <= 0; - dac_mem_rd_last_address <= 0; + if (dac_fifo_reset_s == 1'b1) begin + dac_mem_raddr <= 0; + dac_mem_raddr_g <= 0; + dac_mem_addr_diff <= 0; + dac_mem_laddr_b <= 0; end else begin - dac_mem_address_diff <= dac_mem_address_diff_s[DAC_MEM_ADDRESS_WIDTH-1:0]; - dac_mem_rd_last_address <= dac_mem_wr_last_address + dac_avl_last_beats; - if (dac_mem_rd_enable_s == 1'b1) begin - dac_mem_rd_address <= ((dac_mem_rd_address == dac_mem_rd_last_address) && (dac_mem_last_transfer_active == 1'b1)) ? - (dac_mem_wr_last_address + {MEM_WIDTH_DIFF{1'b1}} + 1) : - (dac_mem_rd_address + 1); + dac_mem_laddr_b <= dac_mem_laddr_s; + dac_mem_addr_diff <= dac_mem_addr_diff_s[DAC_MEM_ADDRESS_WIDTH-1:0]; + if (dac_mem_valid) begin + if ((dac_dma_last_beats != {MEM_WIDTH_DIFF{1'b1}}) && + (dac_mem_raddr == (dac_mem_laddr_b + dac_dma_last_beats))) begin + dac_mem_raddr <= dac_mem_raddr + (MEM_RATIO - dac_dma_last_beats); + end else begin + dac_mem_raddr <= dac_mem_raddr + 1'b1; + end end - dac_mem_rd_address_g <= dac_mem_rd_address_b2g_s; + dac_mem_raddr_g <= dac_mem_raddr_b2g_s; end end ad_b2g #( .DATA_WIDTH(DAC_MEM_ADDRESS_WIDTH) - ) i_dac_mem_rd_address_b2g ( - .din (dac_mem_rd_address), - .dout (dac_mem_rd_address_b2g_s)); + ) i_dac_mem_rd_addr_b2g ( + .din (dac_mem_raddr), + .dout (dac_mem_raddr_b2g_s)); always @(posedge dac_clk) begin - if (dac_reset == 1'b1) begin - dac_xfer_req <= 0; - end else begin - if ((dac_avl_xfer_req == 1'b1) && (dac_mem_address_diff > 0)) begin - dac_xfer_req <= 1'b1; - end else if ((dac_avl_xfer_req == 1'b0) && (dac_mem_address_diff_s[DAC_MEM_ADDRESS_WIDTH-1:0] == 0)) begin - dac_xfer_req <= 1'b0; - end - end - end - - always @(posedge dac_clk) begin - if ((dac_reset == 1'b1) || (dac_xfer_req == 1'b0)) begin + if ((dac_fifo_reset_s == 1'b1) || (dac_xfer_req_b == 1'b0)) begin dac_data <= 0; end else begin dac_data <= dac_mem_data_s; @@ -403,10 +525,10 @@ module avl_dacfifo_rd #( end always @(posedge dac_clk) begin - if ((dac_reset == 1'b1) || (dac_xfer_req == 1'b0)) begin + if (dac_fifo_reset_s == 1'b1) begin dac_dunf <= 1'b0; end else begin - dac_dunf <= (dac_mem_address_diff == 0) ? 1'b1 : 1'b0; + dac_dunf <= (dac_mem_addr_diff == 0) ? 1'b1 : 1'b0; end end diff --git a/library/altera/avl_dacfifo/avl_dacfifo_wr.v b/library/altera/avl_dacfifo/avl_dacfifo_wr.v index f4a7a7d51..57e950445 100644 --- a/library/altera/avl_dacfifo/avl_dacfifo_wr.v +++ b/library/altera/avl_dacfifo/avl_dacfifo_wr.v @@ -39,9 +39,10 @@ module avl_dacfifo_wr #( parameter AVL_DATA_WIDTH = 512, parameter DMA_DATA_WIDTH = 64, + parameter AVL_BURST_LENGTH = 128, parameter AVL_DDR_BASE_ADDRESS = 0, parameter AVL_DDR_ADDRESS_LIMIT = 1048576, - parameter DMA_MEM_ADDRESS_WIDTH = 8)( + parameter DMA_MEM_ADDRESS_WIDTH = 10)( input dma_clk, input [DMA_DATA_WIDTH-1:0] dma_data, @@ -51,18 +52,21 @@ module avl_dacfifo_wr #( input dma_xfer_req, input dma_xfer_last, + output reg [ 7:0] dma_last_beats, + input avl_clk, input avl_reset, output reg [24:0] avl_address, - output [ 5:0] avl_burstcount, + output reg [ 6:0] avl_burstcount, output [63:0] avl_byteenable, - input avl_ready, + input avl_waitrequest, output reg avl_write, output reg [AVL_DATA_WIDTH-1:0] avl_data, output reg [24:0] avl_last_address, - output reg [63:0] avl_last_byteenable, - output reg avl_xfer_req); + output reg [ 6:0] avl_last_burstcount, + output reg avl_xfer_req_out, + input avl_xfer_req_in); localparam MEM_RATIO = AVL_DATA_WIDTH/DMA_DATA_WIDTH; // Max supported MEM_RATIO is 16 localparam AVL_MEM_ADDRESS_WIDTH = (MEM_RATIO == 1) ? DMA_MEM_ADDRESS_WIDTH : @@ -77,126 +81,164 @@ module avl_dacfifo_wr #( (MEM_RATIO > 2) ? 2 : (MEM_RATIO > 1) ? 1 : 1; - localparam DMA_BUF_THRESHOLD_HI = {(DMA_MEM_ADDRESS_WIDTH){1'b1}} - 4; + localparam DMA_BUF_THRESHOLD_HI = {(DMA_MEM_ADDRESS_WIDTH){1'b1}} - AVL_BURST_LENGTH; localparam DMA_BYTE_DATA_WIDTH = DMA_DATA_WIDTH/8; localparam AVL_BYTE_DATA_WIDTH = AVL_DATA_WIDTH/8; - wire dma_resetn; + // FSM state definition + + localparam IDLE = 5'b00001; + localparam XFER_STAGING = 5'b00010; + localparam XFER_FULL_BURST = 5'b00100; + localparam XFER_PARTIAL_BURST = 5'b01000; + localparam XFER_END = 5'b10000; + + wire dma_reset; + wire dma_fifo_reset_s; wire dma_mem_wea_s; - wire [DMA_MEM_ADDRESS_WIDTH :0] dma_mem_address_diff_s; - wire [DMA_MEM_ADDRESS_WIDTH-1:0] dma_mem_rd_address_s; - wire [AVL_MEM_ADDRESS_WIDTH-1:0] dma_mem_rd_address_g2b_s; + wire [DMA_MEM_ADDRESS_WIDTH :0] dma_mem_addr_diff_s; + wire [DMA_MEM_ADDRESS_WIDTH-1:0] dma_mem_raddr_s; + wire [DMA_MEM_ADDRESS_WIDTH-1:0] dma_mem_waddr_b2g_s; + wire [AVL_MEM_ADDRESS_WIDTH-1:0] dma_mem_raddr_g2b_s; - wire [AVL_DATA_WIDTH-1:0] avl_mem_rdata_s; - wire avl_mem_fetch_wr_address_s; - wire avl_mem_readen_s; - wire [AVL_MEM_ADDRESS_WIDTH :0] avl_mem_address_diff_s; - wire avl_write_transfer_s; - wire avl_last_transfer_req_s; - wire avl_xfer_req_init_s; - wire avl_pending_write_cycle_s; - wire avl_last_beat_req_pos_s; - wire avl_last_beat_req_neg_s; - wire [AVL_MEM_ADDRESS_WIDTH-1:0] avl_mem_rd_address_b2g_s; - wire avl_last_beats_full; + wire avl_fifo_reset_s; + wire avl_write_int_s; + wire [AVL_MEM_ADDRESS_WIDTH-1:0] avl_mem_raddr_b2g_s; + wire [DMA_MEM_ADDRESS_WIDTH-1:0] avl_mem_waddr_m2_g2b_s; + wire [AVL_MEM_ADDRESS_WIDTH-1:0] avl_mem_addr_diff_s; + wire [AVL_MEM_ADDRESS_WIDTH:0] avl_mem_waddr_s; + wire [AVL_DATA_WIDTH-1:0] avl_data_s; + wire avl_xfer_req_lp_s; - reg [DMA_MEM_ADDRESS_WIDTH-1:0] dma_mem_wr_address; - reg [AVL_MEM_ADDRESS_WIDTH-1:0] dma_mem_wr_address_d; - reg [AVL_MEM_ADDRESS_WIDTH-1:0] dma_mem_rd_address_m1; - reg [AVL_MEM_ADDRESS_WIDTH-1:0] dma_mem_rd_address_m2; - reg [AVL_MEM_ADDRESS_WIDTH-1:0] dma_mem_rd_address; - reg dma_mem_read_control; - reg [DMA_MEM_ADDRESS_WIDTH-1:0] dma_mem_address_diff; - reg dma_last_beat_ack; - reg [MEM_WIDTH_DIFF-1:0] dma_mem_last_beats; - reg dma_avl_xfer_req_m1; - reg dma_avl_xfer_req; + reg [DMA_MEM_ADDRESS_WIDTH-1:0] dma_mem_waddr; + reg [DMA_MEM_ADDRESS_WIDTH-1:0] dma_mem_waddr_g; + reg [AVL_MEM_ADDRESS_WIDTH-1:0] dma_mem_raddr_m1; + reg [AVL_MEM_ADDRESS_WIDTH-1:0] dma_mem_raddr_m2; + reg [AVL_MEM_ADDRESS_WIDTH-1:0] dma_mem_raddr; + reg [DMA_MEM_ADDRESS_WIDTH-1:0] dma_mem_addr_diff; + reg dma_xfer_req_d; + reg dma_xfer_req_lp_m1; + reg dma_xfer_req_lp_m2; + reg dma_xfer_req_lp; + reg dma_avl_xfer_req_out_m1; + reg dma_avl_xfer_req_out_m2; + reg dma_avl_xfer_req_out; - reg [AVL_MEM_ADDRESS_WIDTH-1:0] avl_mem_rd_address; - reg [AVL_MEM_ADDRESS_WIDTH-1:0] avl_mem_rd_address_g; - reg [AVL_MEM_ADDRESS_WIDTH-1:0] avl_mem_wr_address; - reg avl_mem_fetch_wr_address; - reg avl_mem_fetch_wr_address_m1; - reg avl_mem_fetch_wr_address_m2; - reg [ 1:0] avl_write_d; - reg avl_mem_readen; - reg avl_write_transfer; - reg avl_last_beat_req_m1; - reg avl_last_beat_req_m2; - reg avl_last_beat_req; + reg [ 4:0] avl_write_state; + reg avl_write_d; + reg [AVL_MEM_ADDRESS_WIDTH-1:0] avl_mem_raddr; + reg [AVL_MEM_ADDRESS_WIDTH-1:0] avl_mem_raddr_g; + reg [DMA_MEM_ADDRESS_WIDTH-1:0] avl_mem_waddr; + reg [DMA_MEM_ADDRESS_WIDTH-1:0] avl_mem_waddr_m1; + reg [DMA_MEM_ADDRESS_WIDTH-1:0] avl_mem_waddr_m2; + reg [AVL_MEM_ADDRESS_WIDTH-1:0] avl_mem_addr_diff; reg avl_dma_xfer_req; reg avl_dma_xfer_req_m1; reg avl_dma_xfer_req_m2; - reg [MEM_WIDTH_DIFF-1:0] avl_last_beats; - reg [MEM_WIDTH_DIFF-1:0] avl_last_beats_m1; - reg [MEM_WIDTH_DIFF-1:0] avl_last_beats_m2; - reg avl_write_xfer_req; + reg [ 7:0] avl_dma_last_beats; + reg [ 7:0] avl_dma_last_beats_m1; + reg [ 7:0] avl_dma_last_beats_m2; + reg [ 3:0] avl_xfer_pburst_offset; + reg [ 7:0] avl_burst_counter; + reg avl_last_burst; + reg avl_init_burst; + reg avl_endof_burst; + reg [ 1:0] avl_mem_rvalid; + reg avl_xfer_req_lp; - // An asymmetric memory to transfer data from DMAC interface to AXI Memory Map + // An asymmetric memory to transfer data from DMAC interface to Avalon Memory Map // interface alt_mem_asym_wr i_mem_asym ( .mem_i_wrclock (dma_clk), .mem_i_wren (dma_mem_wea_s), - .mem_i_wraddress (dma_mem_wr_address), + .mem_i_wraddress (dma_mem_waddr), .mem_i_datain (dma_data), .mem_i_rdclock (avl_clk), - .mem_i_rdaddress (avl_mem_rd_address), - .mem_o_dataout (avl_mem_rdata_s)); + .mem_i_rdaddress (avl_mem_raddr), + .mem_o_dataout (avl_data_s)); // the fifo reset is the dma_xfer_req - assign dma_resetn = dma_xfer_req; - - // write address generation - - assign dma_mem_wea_s = dma_ready & dma_valid & dma_xfer_req; + assign dma_reset = ~dma_xfer_req_d & dma_xfer_req; + assign dma_fifo_reset_s = (~dma_xfer_req_lp & dma_xfer_req_lp_m2); + assign avl_fifo_reset_s = (avl_reset == 1'b1) || + (avl_dma_xfer_req_m2 & ~avl_dma_xfer_req); always @(posedge dma_clk) begin - if (dma_resetn == 1'b0) begin - dma_mem_wr_address <= 0; - dma_mem_read_control <= 1'b0; - dma_mem_last_beats <= 0; + dma_xfer_req_d <= dma_xfer_req; + end + + always @(posedge dma_clk) begin + if (dma_reset) begin + dma_xfer_req_lp_m1 <= 1'b0; + dma_xfer_req_lp_m2 <= 1'b0; + dma_xfer_req_lp <= 1'b0; + dma_avl_xfer_req_out_m1 <= 1'b0; + dma_avl_xfer_req_out_m2 <= 1'b0; + dma_avl_xfer_req_out <= 1'b0; end else begin - if (dma_mem_wea_s == 1'b1) begin - dma_mem_wr_address <= dma_mem_wr_address + 1; - end - if (dma_mem_wr_address[MEM_WIDTH_DIFF-1:0] == {MEM_WIDTH_DIFF{1'b1}}) begin - dma_mem_read_control <= ~dma_mem_read_control; - dma_mem_wr_address_d <= dma_mem_wr_address[DMA_MEM_ADDRESS_WIDTH-1:MEM_WIDTH_DIFF] + 1; - end - end - if ((dma_xfer_last == 1'b1) && (dma_mem_wea_s == 1'b1)) begin - dma_mem_last_beats <= dma_mem_wr_address[MEM_WIDTH_DIFF-1:0]; + dma_xfer_req_lp_m1 <= avl_xfer_req_lp; + dma_xfer_req_lp_m2 <= dma_xfer_req_lp_m1; + dma_xfer_req_lp <= dma_xfer_req_lp_m2; + dma_avl_xfer_req_out_m1 <= avl_xfer_req_out; + dma_avl_xfer_req_out_m2 <= dma_avl_xfer_req_out_m1; + dma_avl_xfer_req_out <= dma_avl_xfer_req_out_m2; end end - // The memory module request data until reaches the high threshold. + // write address generation - assign dma_mem_address_diff_s = {1'b1, dma_mem_wr_address} - dma_mem_rd_address_s; - assign dma_mem_rd_address_s = (MEM_RATIO == 1) ? dma_mem_rd_address : - (MEM_RATIO == 2) ? {dma_mem_rd_address, 1'b0} : - (MEM_RATIO == 4) ? {dma_mem_rd_address, 2'b0} : - (MEM_RATIO == 8) ? {dma_mem_rd_address, 3'b0} : - (MEM_RATIO == 16) ? {dma_mem_rd_address, 4'b0} : - {dma_mem_rd_address, 5'b0}; + assign dma_mem_wea_s = dma_ready & dma_valid & dma_xfer_req_lp; always @(posedge dma_clk) begin - if (dma_resetn == 1'b0) begin - dma_mem_address_diff <= 'b0; - dma_mem_rd_address_m1 <= 'b0; - dma_mem_rd_address_m2 <= 'b0; - dma_mem_rd_address <= 'b0; + if (dma_fifo_reset_s == 1'b1) begin + dma_mem_waddr <= 0; + dma_mem_waddr_g <= 0; + dma_last_beats <= 0; + end else begin + if (dma_mem_wea_s == 1'b1) begin + dma_mem_waddr <= dma_mem_waddr + 1'b1; + end + end + if ((dma_xfer_last == 1'b1) && (dma_mem_wea_s == 1'b1)) begin + dma_last_beats <= dma_mem_waddr[MEM_WIDTH_DIFF-1:0]; + end + dma_mem_waddr_g <= dma_mem_waddr_b2g_s; + end + + ad_b2g # ( + .DATA_WIDTH(DMA_MEM_ADDRESS_WIDTH) + ) i_dma_mem_waddr_b2g ( + .din (dma_mem_waddr), + .dout (dma_mem_waddr_b2g_s)); + + // The memory module request data until reaches the high threshold. + + assign dma_mem_addr_diff_s = {1'b1, dma_mem_waddr} - dma_mem_raddr_s; + assign dma_mem_raddr_s = (MEM_RATIO == 1) ? {dma_mem_raddr, {0{1'b0}}} : + (MEM_RATIO == 2) ? {dma_mem_raddr, {1{1'b0}}} : + (MEM_RATIO == 4) ? {dma_mem_raddr, {2{1'b0}}} : + (MEM_RATIO == 8) ? {dma_mem_raddr, {3{1'b0}}} : + (MEM_RATIO == 16) ? {dma_mem_raddr, {4{1'b0}}} : + {dma_mem_raddr, {5{1'b0}}}; + + always @(posedge dma_clk) begin + if (dma_fifo_reset_s == 1'b1) begin + dma_mem_addr_diff <= 'b0; + dma_mem_raddr_m1 <= 'b0; + dma_mem_raddr_m2 <= 'b0; + dma_mem_raddr <= 'b0; dma_ready_out <= 1'b0; end else begin - dma_mem_rd_address_m1 <= avl_mem_rd_address_g; - dma_mem_rd_address_m2 <= dma_mem_rd_address_m1; - dma_mem_rd_address <= dma_mem_rd_address_g2b_s; - dma_mem_address_diff <= dma_mem_address_diff_s[DMA_MEM_ADDRESS_WIDTH-1:0]; - if (dma_mem_address_diff >= DMA_BUF_THRESHOLD_HI) begin - dma_ready_out <= 1'b0; + dma_mem_raddr_m1 <= avl_mem_raddr_g; + dma_mem_raddr_m2 <= dma_mem_raddr_m1; + dma_mem_raddr <= dma_mem_raddr_g2b_s; + dma_mem_addr_diff <= dma_mem_addr_diff_s[DMA_MEM_ADDRESS_WIDTH-1:0]; + if (dma_xfer_req_lp == 1'b1) begin + dma_ready_out <= (dma_mem_addr_diff >= DMA_BUF_THRESHOLD_HI) ? 1'b0 : 1'b1; end else begin - dma_ready_out <= 1'b1; + dma_ready_out <= 1'b0; end end end @@ -204,170 +246,253 @@ module avl_dacfifo_wr #( ad_g2b #( .DATA_WIDTH(AVL_MEM_ADDRESS_WIDTH) ) i_dma_mem_rd_address_g2b ( - .din (dma_mem_rd_address_m2), - .dout (dma_mem_rd_address_g2b_s)); + .din (dma_mem_raddr_m2), + .dout (dma_mem_raddr_g2b_s)); - // last DMA beat - - always @(posedge dma_clk) begin - dma_avl_xfer_req_m1 <= avl_write_xfer_req; - dma_avl_xfer_req <= dma_avl_xfer_req_m1; + always @(posedge avl_clk) begin + if (avl_reset == 1'b1) begin + avl_dma_xfer_req_m1 <= 'b0; + avl_dma_xfer_req_m2 <= 'b0; + avl_dma_xfer_req <= 'b0; + end else begin + avl_dma_xfer_req_m1 <= dma_xfer_req; + avl_dma_xfer_req_m2 <= avl_dma_xfer_req_m1; + avl_dma_xfer_req <= avl_dma_xfer_req_m2; + end end - always @(posedge dma_clk) begin - if (dma_avl_xfer_req == 1'b0) begin - dma_last_beat_ack <= 1'b0; + assign avl_xfer_req_lp_s = avl_dma_xfer_req & ~avl_xfer_req_in; + always @(posedge avl_clk) begin + if (avl_reset == 1'b1) begin + avl_xfer_req_lp <= 1'b0; end else begin - if ((dma_xfer_req == 1'b1) && (dma_xfer_last == 1'b1)) begin - dma_last_beat_ack <= 1'b1; + avl_xfer_req_lp <= avl_xfer_req_lp_s; + end + end + + // FSM to generate the necessary Avalon Write transactions + + always @(posedge avl_clk) begin + if (avl_fifo_reset_s == 1'b1) begin + avl_write_state <= IDLE; + avl_last_burst <= 1'b0; + avl_init_burst <= 1'b0; + avl_endof_burst <= 1'b0; + end else begin + case (avl_write_state) + IDLE : begin + if (avl_dma_xfer_req == 1'b1) begin + avl_write_state <= XFER_STAGING; + end else begin + avl_write_state <= IDLE; + end + end + XFER_STAGING : begin + avl_endof_burst <= 1'b0; + if (avl_xfer_req_lp == 1'b1) begin + // there are enough data for one transaction + if (avl_mem_addr_diff >= AVL_BURST_LENGTH) begin + avl_write_state <= XFER_FULL_BURST; + avl_init_burst <= 1'b1; + end else begin + avl_write_state <= XFER_STAGING; + end + end else if ((avl_dma_xfer_req == 1'b0) && (avl_xfer_pburst_offset == 4'b0)) begin // DMA transfer was finished + if (avl_mem_addr_diff >= AVL_BURST_LENGTH) begin + avl_write_state <= XFER_FULL_BURST; + avl_init_burst <= 1'b1; + end else if ((avl_mem_addr_diff > 0) || + (avl_dma_last_beats[MEM_WIDTH_DIFF-1:0] != {MEM_WIDTH_DIFF{1'b1}})) begin + avl_write_state <= XFER_PARTIAL_BURST; + avl_last_burst <= 1'b1; + end else begin + avl_write_state <= XFER_END; + end + end else begin + avl_write_state <= XFER_STAGING; + end + end + // Avalon transaction with full burst length + XFER_FULL_BURST : begin + avl_init_burst <= 1'b0; + if ((avl_burst_counter < avl_burstcount) || ((avl_waitrequest) || (avl_write))) begin + avl_write_state <= XFER_FULL_BURST; + end else begin + avl_write_state <= XFER_STAGING; + avl_endof_burst <= 1'b1; + end + end + // Avalon transaction with the remaining data, burst length is less than + // the maximum supported burst length + XFER_PARTIAL_BURST : begin + avl_last_burst <= 1'b0; + if ((avl_burst_counter < avl_burstcount) || ((avl_waitrequest) || (avl_write))) begin + avl_write_state <= XFER_PARTIAL_BURST; + end else begin + avl_write_state <= XFER_END; + end + end + XFER_END : begin + avl_write_state <= IDLE; + end + default : begin + avl_write_state <= IDLE; + end + endcase + end + end + + // FSM outputs + + assign avl_write_int_s = ((avl_write_state == XFER_FULL_BURST) || + (avl_write_state == XFER_PARTIAL_BURST)) ? 1'b1 : 1'b0; + + always @(posedge avl_clk) begin + if (avl_fifo_reset_s == 1'b1) begin + avl_mem_waddr_m1 <= 'b0; + avl_mem_waddr_m2 <= 'b0; + avl_mem_waddr <= 'b0; + avl_xfer_pburst_offset <= 4'b1111; + end else begin + avl_mem_waddr_m1 <= dma_mem_waddr_g; + avl_mem_waddr_m2 <= avl_mem_waddr_m1; + avl_mem_waddr <= avl_mem_waddr_m2_g2b_s; + if ((avl_dma_xfer_req == 0) && (avl_xfer_pburst_offset > 0)) begin + avl_xfer_pburst_offset <= avl_xfer_pburst_offset - 4'b1; end end end - // transfer the mem_write address to the avalons clock domain + ad_g2b # ( + .DATA_WIDTH(DMA_MEM_ADDRESS_WIDTH) + ) i_avl_mem_waddr_g2b ( + .din (avl_mem_waddr_m2), + .dout (avl_mem_waddr_m2_g2b_s)); - assign avl_mem_fetch_wr_address_s = avl_mem_fetch_wr_address ^ avl_mem_fetch_wr_address_m2; + // ASYNC MEM read control + + assign avl_mem_waddr_s = (MEM_RATIO == 1) ? {avl_mem_waddr[(DMA_MEM_ADDRESS_WIDTH-1):0]} : + (MEM_RATIO == 2) ? {avl_mem_waddr[(DMA_MEM_ADDRESS_WIDTH-1):1]} : + (MEM_RATIO == 4) ? {avl_mem_waddr[(DMA_MEM_ADDRESS_WIDTH-1):2]} : + (MEM_RATIO == 8) ? {avl_mem_waddr[(DMA_MEM_ADDRESS_WIDTH-1):3]} : + {avl_mem_waddr[(DMA_MEM_ADDRESS_WIDTH-1):4]}; + assign avl_mem_addr_diff_s = {1'b1, avl_mem_waddr_s} - avl_mem_raddr; always @(posedge avl_clk) begin - if ((avl_reset == 1'b1) || (avl_write_xfer_req == 1'b0)) begin - avl_mem_fetch_wr_address_m1 <= 0; - avl_mem_fetch_wr_address_m2 <= 0; - avl_mem_fetch_wr_address <= 0; - avl_mem_wr_address <= 0; + if (avl_fifo_reset_s == 1'b1) begin + avl_mem_addr_diff <= 'b0; end else begin - avl_mem_fetch_wr_address_m1 <= dma_mem_read_control; - avl_mem_fetch_wr_address_m2 <= avl_mem_fetch_wr_address_m1; - avl_mem_fetch_wr_address <= avl_mem_fetch_wr_address_m2; - if (avl_mem_fetch_wr_address_s == 1'b1) begin - avl_mem_wr_address <= dma_mem_wr_address_d; - end + avl_mem_addr_diff <= avl_mem_addr_diff_s[(AVL_MEM_ADDRESS_WIDTH-1):0]; end end - // Avalon write address and fifo read address generation - - assign avl_mem_address_diff_s = {1'b1, avl_mem_wr_address} - avl_mem_rd_address; - assign avl_mem_readen_s = (avl_mem_address_diff_s[AVL_MEM_ADDRESS_WIDTH-1:0] == 0) ? 0 : (avl_write_xfer_req & avl_ready); - assign avl_write_transfer_s = avl_write & avl_ready; - always @(posedge avl_clk) begin - if ((avl_reset == 1'b1) || (avl_write_xfer_req == 1'b0)) begin - avl_address <= AVL_DDR_BASE_ADDRESS; - avl_data <= 0; - avl_write_transfer <= 1'b0; - avl_mem_readen <= 0; - avl_mem_rd_address <= 0; - avl_mem_rd_address_g <= 0; + if (avl_fifo_reset_s == 1'b1) begin + avl_mem_rvalid <= 2'b0; + avl_mem_raddr <= 'b0; + avl_mem_raddr_g <= 'b0; end else begin - if (avl_write_transfer == 1'b1) begin - avl_address <= (avl_address < AVL_DDR_ADDRESS_LIMIT) ? avl_address + 1 : 0; + if (~avl_waitrequest && avl_write) begin + avl_mem_rvalid[0] <= 1'b1; + avl_mem_rvalid[1] <= avl_mem_rvalid[0]; + end else begin + avl_mem_rvalid <= {avl_mem_rvalid[0], 1'b0}; end - if (avl_write_transfer_s == 1'b1) begin - avl_mem_rd_address <= avl_mem_rd_address + 1; + if (~avl_waitrequest && avl_write) begin + avl_mem_raddr <= avl_mem_raddr + 1'b1; end - avl_data <= avl_mem_rdata_s; - avl_mem_rd_address_g <= avl_mem_rd_address_b2g_s; - avl_write_transfer <= avl_write_transfer_s; - avl_mem_readen <= avl_mem_readen_s; + if (avl_write_state == XFER_END) begin + avl_mem_raddr <= 'b0; + end + avl_mem_raddr_g <= avl_mem_raddr_b2g_s; end end ad_b2g #( .DATA_WIDTH(AVL_MEM_ADDRESS_WIDTH) ) i_avl_mem_rd_address_b2g ( - .din (avl_mem_rd_address), - .dout (avl_mem_rd_address_b2g_s)); + .din (avl_mem_raddr), + .dout (avl_mem_raddr_b2g_s)); - // avalon write signaling - - assign avl_last_transfer_req_s = avl_last_beat_req & ~avl_mem_readen & ~avl_xfer_req; - assign avl_pending_write_cycle_s = ~avl_write & ~avl_write_d[0] & ~avl_write_d[1]; - - // min distance between two consecutive writes is three avalon clock cycles, - // this constraint comes from ad_mem_asym + // Avalon write address always @(posedge avl_clk) begin - if (avl_reset == 1'b1) begin - avl_write <= 1'b0; - avl_write_d <= 1'b0; + if (avl_fifo_reset_s == 1'b1) begin + avl_address <= AVL_DDR_BASE_ADDRESS; end else begin - if ((((avl_mem_readen == 1'b1) && (avl_write_xfer_req == 1'b1)) || - ((avl_last_transfer_req_s == 1'b1) && (avl_write_xfer_req == 1'b1))) && - (avl_pending_write_cycle_s == 1'b1)) begin - avl_write <= 1'b1; - end else begin - avl_write <= 1'b0; + if (avl_endof_burst == 1'b1) begin + avl_address <= (avl_address < AVL_DDR_ADDRESS_LIMIT) ? avl_address + (AVL_BURST_LENGTH * AVL_BYTE_DATA_WIDTH) : AVL_DDR_BASE_ADDRESS; end - avl_write_d <= {avl_write_d[0], avl_write}; end end - assign avl_xfer_req_init_s = ~avl_dma_xfer_req & avl_dma_xfer_req_m2; + // Avalon write - assign avl_last_beats_full = &avl_last_beats; always @(posedge avl_clk) begin - if (avl_reset == 1'b1) begin - avl_last_beat_req_m1 <= 1'b0; - avl_last_beat_req_m2 <= 1'b0; - avl_last_beat_req <= 1'b0; - avl_write_xfer_req <= 1'b0; - avl_dma_xfer_req_m1 <= 1'b0; - avl_dma_xfer_req_m2 <= 1'b0; - avl_dma_xfer_req <= 1'b0; + if ((avl_fifo_reset_s == 1'b1) || (avl_write_state == XFER_END)) begin + avl_write <= 1'b0; + avl_write_d <= 1'b0; + avl_data <= 'b0; end else begin - avl_last_beat_req_m1 <= dma_last_beat_ack; - avl_last_beat_req_m2 <= avl_last_beat_req_m1; - avl_last_beat_req <= avl_last_beat_req_m2; - avl_dma_xfer_req_m1 <= dma_xfer_req; - avl_dma_xfer_req_m2 <= avl_dma_xfer_req_m1; - avl_dma_xfer_req <= avl_dma_xfer_req_m2; - if (avl_xfer_req_init_s == 1'b1) begin - avl_write_xfer_req <= 1'b1; - end else if ((avl_last_beat_req == 1'b1) && - (avl_write == 1'b1) && - (avl_mem_readen == avl_last_beats_full)) begin - avl_write_xfer_req <= 1'b0; + if (~avl_waitrequest) begin + avl_write_d <= (avl_init_burst || avl_last_burst) || + (avl_write_int_s & avl_mem_rvalid[1]); + avl_write <= avl_write_d; + avl_data <= avl_data_s; + end + end + end + + // Avalon burstcount & counter + + always @(posedge avl_clk) begin + if (avl_reset) begin + avl_burstcount <= 'b1; + avl_burst_counter <= 'b0; + end else begin + if (avl_last_burst) begin + if (avl_dma_last_beats[MEM_WIDTH_DIFF-1:0] != {MEM_WIDTH_DIFF{1'b1}}) begin + avl_burstcount <= avl_mem_addr_diff + 1; + end else begin + avl_burstcount <= avl_mem_addr_diff; + end + end else if (avl_write_state != XFER_PARTIAL_BURST) begin + avl_burstcount <= AVL_BURST_LENGTH; + end + if (avl_write_state == XFER_STAGING) begin + avl_burst_counter <= 'b0; + end else if (avl_write_d && ~avl_waitrequest) begin + avl_burst_counter <= avl_burst_counter + 1'b1; end end end // generate avl_byteenable signal - assign avl_last_beat_req_pos_s = ~avl_last_beat_req & avl_last_beat_req_m2; - assign avl_last_beat_req_neg_s = avl_last_beat_req & ~avl_last_beat_req_m2; always @(posedge avl_clk) begin if (avl_reset == 1'b1) begin - avl_last_beats_m1 <= 1'b0; - avl_last_beats_m2 <= 1'b0; - avl_last_beats <= 1'b0; + avl_dma_last_beats_m1 <= 8'b0; + avl_dma_last_beats_m2 <= 8'b0; + avl_dma_last_beats <= 8'b0; end else begin - avl_last_beats_m1 <= dma_mem_last_beats; - avl_last_beats_m2 <= avl_last_beats_m1; - avl_last_beats <= (avl_last_beat_req_pos_s == 1'b1) ? avl_last_beats_m2 : avl_last_beats; + avl_dma_last_beats_m1 <= dma_last_beats; + avl_dma_last_beats_m2 <= avl_dma_last_beats_m1; + avl_dma_last_beats <= (avl_write_int_s) ? avl_dma_last_beats_m2 : avl_dma_last_beats; end end - avl_dacfifo_byteenable_coder #( - .MEM_RATIO(MEM_RATIO), - .LAST_BEATS_WIDTH(MEM_WIDTH_DIFF) - ) i_byteenable_coder ( - .avl_clk (avl_clk), - .avl_last_beats (avl_last_beats), - .avl_enable (avl_last_beat_req), - .avl_byteenable (avl_byteenable)); - - assign avl_burstcount = 6'b1; + assign avl_byteenable = {64{1'b1}}; // save the last address and byteenable always @(posedge avl_clk) begin if (avl_reset == 1'b1) begin avl_last_address <= 0; - avl_last_byteenable <= 0; + avl_last_burstcount <= 'b0; end else begin - if ((avl_write == 1'b1) && (avl_last_beat_req == 1'b1)) begin + if (avl_write && ~avl_waitrequest) begin avl_last_address <= avl_address; - avl_last_byteenable <= avl_byteenable; + avl_last_burstcount <= avl_burstcount; end end end @@ -377,12 +502,12 @@ module avl_dacfifo_wr #( always @(posedge avl_clk) begin if (avl_reset == 1'b1) begin - avl_xfer_req <= 1'b0; + avl_xfer_req_out <= 1'b0; end else begin - if (avl_last_beat_req_neg_s == 1'b1) begin - avl_xfer_req <= 1'b1; - end else if ((avl_xfer_req == 1'b1) && (avl_dma_xfer_req == 1'b1)) begin - avl_xfer_req <= 1'b0; + if (avl_write_state == XFER_END) begin + avl_xfer_req_out <= 1'b1; + end else if (avl_write_state == XFER_STAGING) begin + avl_xfer_req_out <= 1'b0; end end end diff --git a/library/altera/avl_dacfifo/util_dacfifo_bypass.v b/library/altera/avl_dacfifo/util_dacfifo_bypass.v index cafa65554..e83dea971 100644 --- a/library/altera/avl_dacfifo/util_dacfifo_bypass.v +++ b/library/altera/avl_dacfifo/util_dacfifo_bypass.v @@ -168,7 +168,7 @@ module util_dacfifo_bypass #( dma_mem_waddr_g <= 'h0; end else begin if (dma_mem_wea_s == 1'b1) begin - dma_mem_waddr <= dma_mem_waddr + 1; + dma_mem_waddr <= dma_mem_waddr + 1'b1; end dma_mem_waddr_g <= b2g(dma_mem_waddr); end @@ -227,7 +227,7 @@ module util_dacfifo_bypass #( dac_mem_raddr_g <= 'h0; end else begin if (dac_mem_rea_s == 1'b1) begin - dac_mem_raddr <= dac_mem_raddr + 1; + dac_mem_raddr <= dac_mem_raddr + 1'b1; end dac_mem_raddr_g <= b2g(dac_mem_raddr); end diff --git a/projects/common/a10soc/a10soc_plddr4_dacfifo_qsys.tcl b/projects/common/a10soc/a10soc_plddr4_dacfifo_qsys.tcl index 6400cf4ea..0a8306a3e 100644 --- a/projects/common/a10soc/a10soc_plddr4_dacfifo_qsys.tcl +++ b/projects/common/a10soc/a10soc_plddr4_dacfifo_qsys.tcl @@ -67,6 +67,9 @@ set_instance_parameter_value $dac_fifo_name {AVL_DATA_WIDTH} {512} set_instance_parameter_value $dac_fifo_name {AVL_ADDRESS_WIDTH} {25} set_instance_parameter_value $dac_fifo_name {AVL_BASE_ADDRESS} {0} set_instance_parameter_value $dac_fifo_name {AVL_ADDRESS_LIMIT} {0x8fffffff} +set_instance_parameter_value $dac_fifo_name {DAC_MEM_ADDRESS_WIDTH} {12} +set_instance_parameter_value $dac_fifo_name {DMA_MEM_ADDRESS_WIDTH} {12} +set_instance_parameter_value $dac_fifo_name {AVL_BURST_LENGTH} {64} add_connection sys_clk.clk_reset sys_ddr4_cntrl.global_reset_reset_sink add_connection sys_ddr4_cntrl.emif_usr_reset_reset_source $dac_fifo_name.avl_reset