Skip to content

Commit 188d0a7

Browse files
committed
SPI Engine: decouple SDO data handshake from control
Switched SDO source control to software (memory-mapped register). SDO data can now be clocked in independently from the offload trigger. This allows lower latencies for executing transfers, since the data can be obtained from the DMA before the trigger. It also better separates the command path from the data path Signed-off-by: Laez Barbosa <laez.barbosa@analog.com>
1 parent a513832 commit 188d0a7

File tree

9 files changed

+87
-52
lines changed

9 files changed

+87
-52
lines changed

docs/regmap/adi_regmap_spi_engine.txt

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ ENDTITLE
99
REG
1010
0x00
1111
VERSION
12-
Version of the peripheral. Follows semantic versioning. Current version 1.03.01.
12+
Version of the peripheral. Follows semantic versioning. Current version 1.04.00.
1313
ENDREG
1414

1515
FIELD
@@ -19,13 +19,13 @@ RO
1919
ENDFIELD
2020

2121
FIELD
22-
[15:8] 0x00000003
22+
[15:8] 0x00000004
2323
VERSION_MINOR
2424
RO
2525
ENDFIELD
2626

2727
FIELD
28-
[7:0] 0x00000001
28+
[7:0] 0x00000000
2929
VERSION_PATCH
3030
RO
3131
ENDFIELD
@@ -447,6 +447,21 @@ ENDFIELD
447447
############################################################################################
448448
############################################################################################
449449

450+
REG
451+
0x43
452+
OFFLOAD0_SDO_SRC_SEL
453+
ENDREG
454+
455+
FIELD
456+
[31:0] 0x00000000
457+
OFFLOAD0_SDO_SRC_SEL
458+
RW
459+
Selects data source for SDO offload. 0=SDO memory, 1=SDO stream (DMA).
460+
ENDFIELD
461+
462+
############################################################################################
463+
############################################################################################
464+
450465
REG
451466
0x44
452467
OFFLOAD0_CDM_FIFO

library/spi_engine/axi_spi_engine/axi_spi_engine.v

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ module axi_spi_engine #(
123123

124124
output offload0_sdo_wr_en,
125125
output [(DATA_WIDTH-1):0] offload0_sdo_wr_data,
126+
output offload0_sdo_src_sel,
126127

127128
output offload0_mem_reset,
128129
output offload0_enable,
@@ -133,7 +134,7 @@ module axi_spi_engine #(
133134
input [7:0] offload_sync_data
134135
);
135136

136-
localparam PCORE_VERSION = 'h010301;
137+
localparam PCORE_VERSION = 'h010400;
137138
localparam S_AXI = 0;
138139
localparam UP_FIFO = 1;
139140

@@ -298,6 +299,7 @@ module axi_spi_engine #(
298299

299300
reg offload0_enable_reg;
300301
reg offload0_mem_reset_reg;
302+
reg offload0_sdo_src_sel_reg;
301303
wire offload0_enabled_s;
302304

303305
// the software reset should reset all the registers
@@ -306,12 +308,14 @@ module axi_spi_engine #(
306308
up_irq_mask <= 'h00;
307309
offload0_enable_reg <= 1'b0;
308310
offload0_mem_reset_reg <= 1'b0;
311+
offload0_sdo_src_sel_reg <= 1'b0;
309312
end else begin
310313
if (up_wreq_s) begin
311314
case (up_waddr_s)
312315
8'h20: up_irq_mask <= up_wdata_s;
313316
8'h40: offload0_enable_reg <= up_wdata_s[0];
314317
8'h42: offload0_mem_reset_reg <= up_wdata_s[0];
318+
8'h43: offload0_sdo_src_sel_reg <= up_wdata_s[0];
315319
endcase
316320
end
317321
end
@@ -362,6 +366,7 @@ module axi_spi_engine #(
362366
8'h3c: up_rdata_ff <= sdi_fifo_out_data; /* PEEK register */
363367
8'h40: up_rdata_ff <= {offload0_enable_reg};
364368
8'h41: up_rdata_ff <= {offload0_enabled_s};
369+
8'h43: up_rdata_ff <= {offload0_sdo_src_sel_reg};
365370
8'h80: up_rdata_ff <= CFG_INFO_0;
366371
8'h81: up_rdata_ff <= CFG_INFO_1;
367372
8'h82: up_rdata_ff <= CFG_INFO_2;
@@ -649,6 +654,15 @@ module axi_spi_engine #(
649654
.out_clk (spi_clk),
650655
.out_bits (offload0_mem_reset));
651656

657+
sync_bits #(
658+
.NUM_OF_BITS (1),
659+
.ASYNC_CLK (ASYNC_SPI_CLK)
660+
) i_offload_sdo_src_sel_sync (
661+
.in_bits (offload0_sdo_src_sel_reg),
662+
.out_resetn (spi_resetn),
663+
.out_clk (spi_clk),
664+
.out_bits (offload0_sdo_src_sel));
665+
652666
sync_bits #(
653667
.NUM_OF_BITS (3),
654668
.ASYNC_CLK (ASYNC_SPI_CLK)

library/spi_engine/axi_spi_engine/axi_spi_engine_constr.ttcl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ set_false_path -quiet \
2626
set_false_path -quiet \
2727
-to [get_cells -quiet -hierarchical -filter {NAME =~ *i_offload_enabled_sync/cdc_sync_stage1_reg* && IS_SEQUENTIAL}]
2828

29+
set_false_path -quiet \
30+
-to [get_cells -quiet -hierarchical -filter {NAME =~ *i_offload_sdo_src_sel_sync/cdc_sync_stage1_reg* && IS_SEQUENTIAL}]
31+
2932
set_false_path -quiet \
3033
-to [get_cells -quiet -hierarchical -filter {NAME =~ *i_offload_mem_reset_sync/cdc_sync_stage1_reg* && IS_SEQUENTIAL}]
3134

library/spi_engine/axi_spi_engine/axi_spi_engine_ip.tcl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ adi_add_bus "spi_engine_offload_ctrl0" "master" \
5757
{ "offload0_cmd_wr_data" "cmd_wr_data"} \
5858
{ "offload0_sdo_wr_en" "sdo_wr_en"} \
5959
{ "offload0_sdo_wr_data" "sdo_wr_data"} \
60+
{ "offload0_sdo_src_sel" "sdo_src_sel"} \
6061
{ "offload0_enable" "enable"} \
6162
{ "offload0_enabled" "enabled"} \
6263
{ "offload0_mem_reset" "mem_reset"} \

library/spi_engine/interfaces/interfaces_ip.tcl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ adi_if_ports output 1 cmd_wr_en
3939
adi_if_ports output 16 cmd_wr_data
4040
adi_if_ports output 1 sdo_wr_en
4141
adi_if_ports output -1 sdo_wr_data
42+
adi_if_ports output 1 sdo_src_sel
4243
adi_if_ports output 1 mem_reset
4344
adi_if_ports output 1 enable
4445
adi_if_ports input 1 enabled

library/spi_engine/spi_engine_execution/spi_engine_execution.v

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@ module spi_engine_execution #(
137137

138138
reg sdo_enabled = 1'b0;
139139
reg sdi_enabled = 1'b0;
140+
wire sdo_enabled_io;
141+
wire sdi_enabled_io;
140142

141143
wire [2:0] inst = cmd[14:12];
142144
wire [2:0] inst_d1 = cmd_d1[14:12];
@@ -163,7 +165,7 @@ module spi_engine_execution #(
163165

164166
wire end_of_sdi_latch;
165167

166-
wire sample_sdo;
168+
wire sdo_io_ready;
167169

168170
(* direct_enable = "yes" *) wire cs_gen;
169171

@@ -192,16 +194,14 @@ module spi_engine_execution #(
192194
.sdo_idle_state(sdo_idle_state),
193195
.left_aligned(left_aligned),
194196
.word_length(word_length),
195-
.sample_sdo(sample_sdo),
197+
.sdo_io_ready(sdo_io_ready),
196198
.transfer_active(transfer_active),
197199
.trigger_tx(trigger_tx),
198200
.trigger_rx(trigger_rx),
199201
.first_bit(first_bit),
200202
.cs_activate(cs_activate),
201203
.end_of_sdi_latch(end_of_sdi_latch));
202204

203-
assign sample_sdo = (trigger_tx && last_bit) || exec_transfer_cmd;
204-
205205
assign cs_gen = inst_d1 == CMD_CHIPSELECT
206206
&& ((cs_sleep_counter_compare == 1'b1) || cs_sleep_early_exit)
207207
&& (cs_sleep_repeat == 1'b0)
@@ -214,6 +214,8 @@ module spi_engine_execution #(
214214
sdi_enabled <= cmd[9];
215215
end
216216
end
217+
assign sdo_enabled_io = (exec_transfer_cmd) ? cmd[8] : sdo_enabled;
218+
assign sdi_enabled_io = (exec_transfer_cmd) ? cmd[9] : sdi_enabled;
217219

218220
always @(posedge clk) begin
219221
if (cmd_ready & cmd_valid)
@@ -385,9 +387,9 @@ module spi_engine_execution #(
385387
assign sync = cmd_d1[7:0];
386388

387389
assign io_ready1 = (sdi_data_valid == 1'b0 || sdi_data_ready == 1'b1) &&
388-
(sdo_enabled == 1'b0 || last_transfer == 1'b1 || sdo_data_valid == 1'b1);
390+
(sdo_enabled_io == 1'b0 || sdo_io_ready == 1'b1);
389391
assign io_ready2 = (sdi_enabled == 1'b0 || sdi_data_ready == 1'b1) &&
390-
(sdo_enabled == 1'b0 || last_transfer == 1'b1 || sdo_data_valid == 1'b1);
392+
(sdo_enabled_io == 1'b0 || last_transfer == 1'b1 || sdo_io_ready == 1'b1);
391393

392394
always @(posedge clk) begin
393395
if (idle == 1'b1) begin
@@ -406,14 +408,11 @@ module spi_engine_execution #(
406408
wait_for_io <= 1'b0;
407409
end else begin
408410
if (exec_transfer_cmd == 1'b1) begin
409-
wait_for_io <= 1'b1;
410-
transfer_active <= 1'b0;
411+
wait_for_io <= !io_ready1;
412+
transfer_active <= io_ready1;
411413
end else if (wait_for_io == 1'b1 && io_ready1 == 1'b1) begin
412414
wait_for_io <= 1'b0;
413-
if (last_transfer == 1'b0)
414-
transfer_active <= 1'b1;
415-
else
416-
transfer_active <= 1'b0;
415+
transfer_active <= !last_transfer;
417416
end else if (transfer_active == 1'b1 && end_of_word == 1'b1) begin
418417
if (last_transfer == 1'b1 || io_ready2 == 1'b0)
419418
transfer_active <= 1'b0;

library/spi_engine/spi_engine_execution/spi_engine_execution_shiftreg.v

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ module spi_engine_execution_shiftreg #(
5555
// spi data
5656
input [(DATA_WIDTH-1):0] sdo_data,
5757
input sdo_data_valid,
58-
output reg sdo_data_ready,
58+
output sdo_data_ready,
5959
output [(NUM_OF_SDI * DATA_WIDTH-1):0] sdi_data,
6060
output reg sdi_data_valid,
6161
input sdi_data_ready,
@@ -69,7 +69,7 @@ module spi_engine_execution_shiftreg #(
6969
input [7:0] word_length,
7070

7171
// timing from main fsm
72-
input sample_sdo,
72+
output sdo_io_ready,
7373
input transfer_active,
7474
input trigger_tx,
7575
input trigger_rx,
@@ -80,19 +80,27 @@ module spi_engine_execution_shiftreg #(
8080

8181
reg [7:0] sdi_counter = 8'b0;
8282
reg [(DATA_WIDTH-1):0] data_sdo_shift = 'h0;
83-
reg [(DATA_WIDTH-1):0] aligned_sdo_data, sdo_data_d;
83+
reg [(DATA_WIDTH-1):0] aligned_sdo_data, sdo_data_reg;
84+
reg data_sdo_v;
85+
wire sdo_toshiftreg;
8486
wire last_sdi_bit;
8587
reg [SDI_DELAY+1:0] trigger_rx_d = {(SDI_DELAY+2){1'b0}};
8688
wire trigger_rx_s;
8789
wire [2:0] current_instr = current_cmd[14:12];
8890

89-
always @(posedge clk) begin
91+
// sdo data handshake
92+
assign sdo_data_ready = (!data_sdo_v) || sdo_toshiftreg;
93+
assign sdo_io_ready = data_sdo_v;
94+
always @(posedge clk ) begin
9095
if (resetn == 1'b0) begin
91-
sdo_data_ready <= 1'b0;
92-
end else if (sdo_enabled == 1'b1 && first_bit == 1'b1 && trigger_tx == 1'b1 && transfer_active == 1'b1) begin
93-
sdo_data_ready <= 1'b1;
94-
end else if (sdo_data_valid == 1'b1) begin
95-
sdo_data_ready <= 1'b0;
96+
data_sdo_v <= 1'b0;
97+
end else begin
98+
if (sdo_data_ready && sdo_data_valid) begin
99+
data_sdo_v <= 1'b1;
100+
sdo_data_reg <= sdo_data;
101+
end else if (sdo_toshiftreg) begin
102+
data_sdo_v <= 1'b0;
103+
end
96104
end
97105
end
98106

@@ -101,10 +109,7 @@ module spi_engine_execution_shiftreg #(
101109
if (resetn == 1'b0) begin
102110
aligned_sdo_data <= 0;
103111
end else begin
104-
if (sample_sdo) begin
105-
sdo_data_d <= sdo_data;
106-
end
107-
aligned_sdo_data <= sdo_data_d << left_aligned;
112+
aligned_sdo_data <= sdo_data_reg << left_aligned;
108113
end
109114
end
110115

@@ -122,6 +127,7 @@ module spi_engine_execution_shiftreg #(
122127
end
123128
end
124129
assign sdo_int = data_sdo_shift[DATA_WIDTH-1];
130+
assign sdo_toshiftreg = (transfer_active && trigger_tx && first_bit && sdo_enabled);
125131

126132
// In case of an interface with high clock rate (SCLK > 50MHz), the latch of
127133
// the SDI line can be delayed with 1, 2 or 3 SPI core clock cycle.

library/spi_engine/spi_engine_offload/spi_engine_offload.v

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ module spi_engine_offload #(
5252

5353
input ctrl_sdo_wr_en,
5454
input [(DATA_WIDTH-1):0] ctrl_sdo_wr_data,
55+
input ctrl_sdo_src_sel,
5556

5657
input ctrl_enable,
5758
output ctrl_enabled,
@@ -95,7 +96,7 @@ module spi_engine_offload #(
9596
localparam SDO_SOURCE_MEM = 1'b0;
9697

9798
reg spi_active = 1'b0;
98-
reg sdo_source_select = SDO_SOURCE_MEM;
99+
wire sdo_source_select;
99100

100101
reg [CMD_MEM_ADDRESS_WIDTH-1:0] ctrl_cmd_wr_addr = 'h00;
101102
reg [CMD_MEM_ADDRESS_WIDTH-1:0] spi_cmd_rd_addr = 'h00;
@@ -111,10 +112,12 @@ module spi_engine_offload #(
111112
wire [CMD_MEM_ADDRESS_WIDTH-1:0] spi_cmd_rd_addr_next;
112113
wire spi_enable;
113114
wire trigger_posedge;
115+
reg sdo_mem_valid;
114116

117+
assign sdo_source_select = ctrl_sdo_src_sel;
115118
assign cmd_valid = spi_active;
116119
assign sdo_data_valid = (sdo_source_select == SDO_SOURCE_STREAM) ?
117-
s_axis_sdo_valid : spi_active;
120+
s_axis_sdo_valid : (spi_active && sdo_mem_valid);
118121
assign s_axis_sdo_ready = (sdo_source_select == SDO_SOURCE_STREAM) ?
119122
sdo_data_ready : 1'b0;
120123
assign offload_sdi_valid = sdi_data_valid;
@@ -278,34 +281,14 @@ module spi_engine_offload #(
278281
if (!spi_active) begin
279282
// start offload when we have a valid trigger, offload is enabled and
280283
// the DMA is enabled
281-
if (trigger_posedge && spi_enable && (offload_sdi_ready || (SDO_STREAMING && s_axis_sdo_valid)))
284+
if (trigger_posedge && spi_enable)
282285
spi_active <= 1'b1;
283286
end else if (cmd_ready && (spi_cmd_rd_addr_next == ctrl_cmd_wr_addr)) begin
284287
spi_active <= 1'b0;
285288
end
286289
end
287290
end
288291

289-
always @(posedge spi_clk ) begin
290-
if (!spi_resetn) begin
291-
sdo_source_select <= SDO_SOURCE_MEM;
292-
end else begin
293-
if (SDO_STREAMING) begin
294-
if (sdo_source_select == SDO_SOURCE_MEM) begin
295-
// switch to streaming sdo after we're done with reading the sdo memory
296-
if (sdo_data_valid && sdo_data_ready && (spi_sdo_rd_addr+1 == ctrl_sdo_wr_addr)|| (ctrl_sdo_wr_addr==0 && spi_active) ) begin
297-
sdo_source_select <= SDO_SOURCE_STREAM;
298-
end
299-
end else begin
300-
// switch back to sdo memory after last command accepted
301-
if (cmd_ready && (spi_cmd_rd_addr_next == ctrl_cmd_wr_addr)) begin
302-
sdo_source_select <= SDO_SOURCE_MEM;
303-
end
304-
end
305-
end
306-
end
307-
end
308-
309292
always @(posedge spi_clk) begin
310293
if (!cmd_valid) begin
311294
spi_cmd_rd_addr <= 'h00;
@@ -322,6 +305,18 @@ module spi_engine_offload #(
322305
end
323306
end
324307

308+
always @(posedge spi_clk ) begin
309+
if (!spi_resetn) begin
310+
sdo_mem_valid <= 1'b0;
311+
end else begin
312+
if (!spi_active && trigger_posedge && spi_enable) begin
313+
sdo_mem_valid <= (ctrl_sdo_wr_addr != 'h00); // if ctrl_sdo_wr_addr is 0, mem is empty
314+
end else if (sdo_data_ready && spi_active && sdo_mem_valid && (spi_sdo_rd_addr + 1'b1 == ctrl_sdo_wr_addr)) begin
315+
sdo_mem_valid <= 1'b0;
316+
end
317+
end
318+
end
319+
325320
always @(posedge ctrl_clk) begin
326321
if (ctrl_mem_reset)
327322
ctrl_cmd_wr_addr <= 'h00;

library/spi_engine/spi_engine_offload/spi_engine_offload_ip.tcl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ adi_add_bus "spi_engine_offload_ctrl" "slave" \
5454
{ "ctrl_cmd_wr_data" "cmd_wr_data"} \
5555
{ "ctrl_sdo_wr_en" "sdo_wr_en"} \
5656
{ "ctrl_sdo_wr_data" "sdo_wr_data"} \
57+
{ "ctrl_sdo_src_sel" "sdo_src_sel"} \
5758
{ "ctrl_enable" "enable"} \
5859
{ "ctrl_enabled" "enabled"} \
5960
{ "ctrl_mem_reset" "mem_reset"} \

0 commit comments

Comments
 (0)