diff --git a/docs/regmap/adi_regmap_spi_engine.txt b/docs/regmap/adi_regmap_spi_engine.txt index 908b04bf33..225a08f324 100644 --- a/docs/regmap/adi_regmap_spi_engine.txt +++ b/docs/regmap/adi_regmap_spi_engine.txt @@ -9,7 +9,7 @@ ENDTITLE REG 0x00 VERSION -Version of the peripheral. Follows semantic versioning. Current version 1.03.01. +Version of the peripheral. Follows semantic versioning. Current version 1.04.00. ENDREG FIELD @@ -19,13 +19,13 @@ RO ENDFIELD FIELD -[15:8] 0x00000003 +[15:8] 0x00000004 VERSION_MINOR RO ENDFIELD FIELD -[7:0] 0x00000001 +[7:0] 0x00000000 VERSION_PATCH RO ENDFIELD @@ -447,6 +447,21 @@ ENDFIELD ############################################################################################ ############################################################################################ +REG +0x43 +OFFLOAD0_SDO_SRC_SEL +ENDREG + +FIELD +[31:0] 0x00000000 +OFFLOAD0_SDO_SRC_SEL +RW +Selects data source for SDO offload. 0=SDO memory, 1=SDO stream (DMA). +ENDFIELD + +############################################################################################ +############################################################################################ + REG 0x44 OFFLOAD0_CDM_FIFO diff --git a/library/spi_engine/axi_spi_engine/axi_spi_engine.v b/library/spi_engine/axi_spi_engine/axi_spi_engine.v index 2c0a9f37c9..fd276eba47 100644 --- a/library/spi_engine/axi_spi_engine/axi_spi_engine.v +++ b/library/spi_engine/axi_spi_engine/axi_spi_engine.v @@ -123,6 +123,7 @@ module axi_spi_engine #( output offload0_sdo_wr_en, output [(DATA_WIDTH-1):0] offload0_sdo_wr_data, + output offload0_sdo_src_sel, output offload0_mem_reset, output offload0_enable, @@ -133,7 +134,7 @@ module axi_spi_engine #( input [7:0] offload_sync_data ); - localparam PCORE_VERSION = 'h010301; + localparam PCORE_VERSION = 'h010400; localparam S_AXI = 0; localparam UP_FIFO = 1; @@ -298,6 +299,7 @@ module axi_spi_engine #( reg offload0_enable_reg; reg offload0_mem_reset_reg; + reg offload0_sdo_src_sel_reg; wire offload0_enabled_s; // the software reset should reset all the registers @@ -306,12 +308,14 @@ module axi_spi_engine #( up_irq_mask <= 'h00; offload0_enable_reg <= 1'b0; offload0_mem_reset_reg <= 1'b0; + offload0_sdo_src_sel_reg <= 1'b0; end else begin if (up_wreq_s) begin case (up_waddr_s) 8'h20: up_irq_mask <= up_wdata_s; 8'h40: offload0_enable_reg <= up_wdata_s[0]; 8'h42: offload0_mem_reset_reg <= up_wdata_s[0]; + 8'h43: offload0_sdo_src_sel_reg <= up_wdata_s[0]; endcase end end @@ -362,6 +366,7 @@ module axi_spi_engine #( 8'h3c: up_rdata_ff <= sdi_fifo_out_data; /* PEEK register */ 8'h40: up_rdata_ff <= {offload0_enable_reg}; 8'h41: up_rdata_ff <= {offload0_enabled_s}; + 8'h43: up_rdata_ff <= {offload0_sdo_src_sel_reg}; 8'h80: up_rdata_ff <= CFG_INFO_0; 8'h81: up_rdata_ff <= CFG_INFO_1; 8'h82: up_rdata_ff <= CFG_INFO_2; @@ -649,6 +654,15 @@ module axi_spi_engine #( .out_clk (spi_clk), .out_bits (offload0_mem_reset)); + sync_bits #( + .NUM_OF_BITS (1), + .ASYNC_CLK (ASYNC_SPI_CLK) + ) i_offload_sdo_src_sel_sync ( + .in_bits (offload0_sdo_src_sel_reg), + .out_resetn (spi_resetn), + .out_clk (spi_clk), + .out_bits (offload0_sdo_src_sel)); + sync_bits #( .NUM_OF_BITS (3), .ASYNC_CLK (ASYNC_SPI_CLK) diff --git a/library/spi_engine/axi_spi_engine/axi_spi_engine_constr.ttcl b/library/spi_engine/axi_spi_engine/axi_spi_engine_constr.ttcl index 3170323468..1f2de49275 100644 --- a/library/spi_engine/axi_spi_engine/axi_spi_engine_constr.ttcl +++ b/library/spi_engine/axi_spi_engine/axi_spi_engine_constr.ttcl @@ -26,6 +26,9 @@ set_false_path -quiet \ set_false_path -quiet \ -to [get_cells -quiet -hierarchical -filter {NAME =~ *i_offload_enabled_sync/cdc_sync_stage1_reg* && IS_SEQUENTIAL}] +set_false_path -quiet \ + -to [get_cells -quiet -hierarchical -filter {NAME =~ *i_offload_sdo_src_sel_sync/cdc_sync_stage1_reg* && IS_SEQUENTIAL}] + set_false_path -quiet \ -to [get_cells -quiet -hierarchical -filter {NAME =~ *i_offload_mem_reset_sync/cdc_sync_stage1_reg* && IS_SEQUENTIAL}] diff --git a/library/spi_engine/axi_spi_engine/axi_spi_engine_ip.tcl b/library/spi_engine/axi_spi_engine/axi_spi_engine_ip.tcl index b775c377c7..c8252389a7 100644 --- a/library/spi_engine/axi_spi_engine/axi_spi_engine_ip.tcl +++ b/library/spi_engine/axi_spi_engine/axi_spi_engine_ip.tcl @@ -57,6 +57,7 @@ adi_add_bus "spi_engine_offload_ctrl0" "master" \ { "offload0_cmd_wr_data" "cmd_wr_data"} \ { "offload0_sdo_wr_en" "sdo_wr_en"} \ { "offload0_sdo_wr_data" "sdo_wr_data"} \ + { "offload0_sdo_src_sel" "sdo_src_sel"} \ { "offload0_enable" "enable"} \ { "offload0_enabled" "enabled"} \ { "offload0_mem_reset" "mem_reset"} \ diff --git a/library/spi_engine/interfaces/interfaces_ip.tcl b/library/spi_engine/interfaces/interfaces_ip.tcl index fa1cc602e8..8626dc48f8 100644 --- a/library/spi_engine/interfaces/interfaces_ip.tcl +++ b/library/spi_engine/interfaces/interfaces_ip.tcl @@ -39,6 +39,7 @@ adi_if_ports output 1 cmd_wr_en adi_if_ports output 16 cmd_wr_data adi_if_ports output 1 sdo_wr_en adi_if_ports output -1 sdo_wr_data +adi_if_ports output 1 sdo_src_sel adi_if_ports output 1 mem_reset adi_if_ports output 1 enable adi_if_ports input 1 enabled diff --git a/library/spi_engine/spi_engine_execution/spi_engine_execution.v b/library/spi_engine/spi_engine_execution/spi_engine_execution.v index f0a58bcc93..82dbf5b8b9 100644 --- a/library/spi_engine/spi_engine_execution/spi_engine_execution.v +++ b/library/spi_engine/spi_engine_execution/spi_engine_execution.v @@ -137,6 +137,8 @@ module spi_engine_execution #( reg sdo_enabled = 1'b0; reg sdi_enabled = 1'b0; + wire sdo_enabled_io; + wire sdi_enabled_io; wire [2:0] inst = cmd[14:12]; wire [2:0] inst_d1 = cmd_d1[14:12]; @@ -163,7 +165,7 @@ module spi_engine_execution #( wire end_of_sdi_latch; - wire sample_sdo; + wire sdo_io_ready; (* direct_enable = "yes" *) wire cs_gen; @@ -192,7 +194,6 @@ module spi_engine_execution #( .sdo_idle_state(sdo_idle_state), .left_aligned(left_aligned), .word_length(word_length), - .sample_sdo(sample_sdo), .sdo_io_ready(sdo_io_ready), .transfer_active(transfer_active), .trigger_tx(trigger_tx), @@ -201,8 +202,6 @@ module spi_engine_execution #( .cs_activate(cs_activate), .end_of_sdi_latch(end_of_sdi_latch)); - assign sample_sdo = sdo_data_valid && ((trigger_tx && last_bit) || (wait_for_io || exec_transfer_cmd)); - assign cs_gen = inst_d1 == CMD_CHIPSELECT && ((cs_sleep_counter_compare == 1'b1) || cs_sleep_early_exit) && (cs_sleep_repeat == 1'b0) @@ -215,6 +214,8 @@ module spi_engine_execution #( sdi_enabled <= cmd[9]; end end + assign sdo_enabled_io = (exec_transfer_cmd) ? cmd[8] : sdo_enabled; + assign sdi_enabled_io = (exec_transfer_cmd) ? cmd[9] : sdi_enabled; always @(posedge clk) begin if (cmd_ready & cmd_valid) @@ -386,9 +387,9 @@ module spi_engine_execution #( assign sync = cmd_d1[7:0]; assign io_ready1 = (sdi_data_valid == 1'b0 || sdi_data_ready == 1'b1) && - (sdo_enabled == 1'b0 || last_transfer == 1'b1 || sdo_io_ready == 1'b1); + (sdo_enabled_io == 1'b0 || sdo_io_ready == 1'b1); assign io_ready2 = (sdi_enabled == 1'b0 || sdi_data_ready == 1'b1) && - (sdo_enabled == 1'b0 || last_transfer == 1'b1 || sdo_data_valid == 1'b1); + (sdo_enabled_io == 1'b0 || last_transfer == 1'b1 || sdo_io_ready == 1'b1); always @(posedge clk) begin if (idle == 1'b1) begin @@ -407,14 +408,11 @@ module spi_engine_execution #( wait_for_io <= 1'b0; end else begin if (exec_transfer_cmd == 1'b1) begin - wait_for_io <= 1'b1; - transfer_active <= 1'b0; + wait_for_io <= !io_ready1; + transfer_active <= io_ready1; end else if (wait_for_io == 1'b1 && io_ready1 == 1'b1) begin wait_for_io <= 1'b0; - if (last_transfer == 1'b0) - transfer_active <= 1'b1; - else - transfer_active <= 1'b0; + transfer_active <= !last_transfer; end else if (transfer_active == 1'b1 && end_of_word == 1'b1) begin if (last_transfer == 1'b1 || io_ready2 == 1'b0) transfer_active <= 1'b0; diff --git a/library/spi_engine/spi_engine_execution/spi_engine_execution_shiftreg.v b/library/spi_engine/spi_engine_execution/spi_engine_execution_shiftreg.v index 428c09797d..856b899d1b 100644 --- a/library/spi_engine/spi_engine_execution/spi_engine_execution_shiftreg.v +++ b/library/spi_engine/spi_engine_execution/spi_engine_execution_shiftreg.v @@ -55,7 +55,7 @@ module spi_engine_execution_shiftreg #( // spi data input [(DATA_WIDTH-1):0] sdo_data, input sdo_data_valid, - output reg sdo_data_ready, + output sdo_data_ready, output [(NUM_OF_SDI * DATA_WIDTH-1):0] sdi_data, output reg sdi_data_valid, input sdi_data_ready, @@ -69,8 +69,7 @@ module spi_engine_execution_shiftreg #( input [7:0] word_length, // timing from main fsm - input sample_sdo, - output reg sdo_io_ready, + output sdo_io_ready, input transfer_active, input trigger_tx, input trigger_rx, @@ -81,19 +80,27 @@ module spi_engine_execution_shiftreg #( reg [7:0] sdi_counter = 8'b0; reg [(DATA_WIDTH-1):0] data_sdo_shift = 'h0; - reg [(DATA_WIDTH-1):0] aligned_sdo_data, sdo_data_d; + reg [(DATA_WIDTH-1):0] aligned_sdo_data, sdo_data_reg; + reg data_sdo_v; + wire sdo_toshiftreg; wire last_sdi_bit; reg [SDI_DELAY+1:0] trigger_rx_d = {(SDI_DELAY+2){1'b0}}; wire trigger_rx_s; wire [2:0] current_instr = current_cmd[14:12]; - always @(posedge clk) begin + // sdo data handshake + assign sdo_data_ready = (!data_sdo_v) || sdo_toshiftreg; + assign sdo_io_ready = data_sdo_v; + always @(posedge clk ) begin if (resetn == 1'b0) begin - sdo_data_ready <= 1'b0; - end else if (sdo_toshiftreg) begin - sdo_data_ready <= 1'b1; - end else if (sdo_data_valid == 1'b1) begin - sdo_data_ready <= 1'b0; + data_sdo_v <= 1'b0; + end else begin + if (sdo_data_ready && sdo_data_valid) begin + data_sdo_v <= 1'b1; + sdo_data_reg <= sdo_data; + end else if (sdo_toshiftreg) begin + data_sdo_v <= 1'b0; + end end end @@ -101,16 +108,8 @@ module spi_engine_execution_shiftreg #( always @(posedge clk ) begin if (resetn == 1'b0) begin aligned_sdo_data <= 0; - sdo_io_ready <= 1'b0; end else begin - if (transfer_active == 1'b1 && trigger_tx == 1'b1) begin - sdo_io_ready <= 1'b0; - end - if (sample_sdo) begin - sdo_data_d <= sdo_data; - sdo_io_ready <= 1'b1; - end - aligned_sdo_data <= sdo_data_d << left_aligned; + aligned_sdo_data <= sdo_data_reg << left_aligned; end end @@ -130,7 +129,6 @@ module spi_engine_execution_shiftreg #( assign sdo_int = data_sdo_shift[DATA_WIDTH-1]; assign sdo_toshiftreg = (transfer_active && trigger_tx && first_bit && sdo_enabled); - // In case of an interface with high clock rate (SCLK > 50MHz), the latch of // the SDI line can be delayed with 1, 2 or 3 SPI core clock cycle. // Taking the fact that in high SCLK frequencies the pre-scaler most likely will diff --git a/library/spi_engine/spi_engine_offload/spi_engine_offload.v b/library/spi_engine/spi_engine_offload/spi_engine_offload.v index d1d294037a..ed7ffd6da7 100644 --- a/library/spi_engine/spi_engine_offload/spi_engine_offload.v +++ b/library/spi_engine/spi_engine_offload/spi_engine_offload.v @@ -52,6 +52,7 @@ module spi_engine_offload #( input ctrl_sdo_wr_en, input [(DATA_WIDTH-1):0] ctrl_sdo_wr_data, + input ctrl_sdo_src_sel, input ctrl_enable, output ctrl_enabled, @@ -95,7 +96,7 @@ module spi_engine_offload #( localparam SDO_SOURCE_MEM = 1'b0; reg spi_active = 1'b0; - reg sdo_source_select = SDO_SOURCE_MEM; + wire sdo_source_select; reg [CMD_MEM_ADDRESS_WIDTH-1:0] ctrl_cmd_wr_addr = 'h00; reg [CMD_MEM_ADDRESS_WIDTH-1:0] spi_cmd_rd_addr = 'h00; @@ -111,10 +112,12 @@ module spi_engine_offload #( wire [CMD_MEM_ADDRESS_WIDTH-1:0] spi_cmd_rd_addr_next; wire spi_enable; wire trigger_posedge; + reg sdo_mem_valid; + assign sdo_source_select = ctrl_sdo_src_sel; assign cmd_valid = spi_active; assign sdo_data_valid = (sdo_source_select == SDO_SOURCE_STREAM) ? - s_axis_sdo_valid : spi_active; + s_axis_sdo_valid : (spi_active && sdo_mem_valid); assign s_axis_sdo_ready = (sdo_source_select == SDO_SOURCE_STREAM) ? sdo_data_ready : 1'b0; assign offload_sdi_valid = sdi_data_valid; @@ -278,7 +281,7 @@ module spi_engine_offload #( if (!spi_active) begin // start offload when we have a valid trigger, offload is enabled and // the DMA is enabled - if (trigger_posedge && spi_enable && (offload_sdi_ready || (SDO_STREAMING && s_axis_sdo_valid))) + if (trigger_posedge && spi_enable) spi_active <= 1'b1; end else if (cmd_ready && (spi_cmd_rd_addr_next == ctrl_cmd_wr_addr)) begin spi_active <= 1'b0; @@ -286,26 +289,6 @@ module spi_engine_offload #( end end - always @(posedge spi_clk ) begin - if (!spi_resetn) begin - sdo_source_select <= SDO_SOURCE_MEM; - end else begin - if (SDO_STREAMING) begin - if (sdo_source_select == SDO_SOURCE_MEM) begin - // switch to streaming sdo after we're done with reading the sdo memory - if (sdo_data_valid && sdo_data_ready && (spi_sdo_rd_addr+1 == ctrl_sdo_wr_addr)|| (ctrl_sdo_wr_addr==0 && spi_active) ) begin - sdo_source_select <= SDO_SOURCE_STREAM; - end - end else begin - // switch back to sdo memory after last command accepted - if (cmd_ready && (spi_cmd_rd_addr_next == ctrl_cmd_wr_addr)) begin - sdo_source_select <= SDO_SOURCE_MEM; - end - end - end - end - end - always @(posedge spi_clk) begin if (!cmd_valid) begin spi_cmd_rd_addr <= 'h00; @@ -322,6 +305,18 @@ module spi_engine_offload #( end end + always @(posedge spi_clk ) begin + if (!spi_resetn) begin + sdo_mem_valid <= 1'b0; + end else begin + if (!spi_active && trigger_posedge && spi_enable) begin + sdo_mem_valid <= (ctrl_sdo_wr_addr != 'h00); // if ctrl_sdo_wr_addr is 0, mem is empty + end else if (sdo_data_ready && spi_active && sdo_mem_valid && (spi_sdo_rd_addr + 1'b1 == ctrl_sdo_wr_addr)) begin + sdo_mem_valid <= 1'b0; + end + end + end + always @(posedge ctrl_clk) begin if (ctrl_mem_reset) ctrl_cmd_wr_addr <= 'h00; diff --git a/library/spi_engine/spi_engine_offload/spi_engine_offload_ip.tcl b/library/spi_engine/spi_engine_offload/spi_engine_offload_ip.tcl index 0b1170a243..5a6aabf756 100644 --- a/library/spi_engine/spi_engine_offload/spi_engine_offload_ip.tcl +++ b/library/spi_engine/spi_engine_offload/spi_engine_offload_ip.tcl @@ -54,6 +54,7 @@ adi_add_bus "spi_engine_offload_ctrl" "slave" \ { "ctrl_cmd_wr_data" "cmd_wr_data"} \ { "ctrl_sdo_wr_en" "sdo_wr_en"} \ { "ctrl_sdo_wr_data" "sdo_wr_data"} \ + { "ctrl_sdo_src_sel" "sdo_src_sel"} \ { "ctrl_enable" "enable"} \ { "ctrl_enabled" "enabled"} \ { "ctrl_mem_reset" "mem_reset"} \