1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
|
# SPDX-License-Identifier: LGPL-3.0-or-later
#
# Copyright 2019 Ettus Research, A National Instruments Company
#
# Timing constraints for Rhodium's MAX 10 board controller
set_time_format -unit ns -decimal_places 3
# Some constants for constraining the design with the FPGA-centric method:
# Maximum trace propagation delay is assumed to be 0.6 ns on any traces
# to on-dboard slaves
set board_delay 0.600
set clk_uncertainty 0.150
###############################################################################
# Clocks
###############################################################################
# The PS SPI clock is maximum 10 MHz. It is driven from another source and
# provided with the data.
# CPLD_PS_SPI_CLK_25: 8 MHz
set sclk_ps_period 125.000
# Create clock for the PS's SPI interface
create_clock -name sclk_ps -period $sclk_ps_period \
[get_ports CPLD_PS_SPI_CLK_25]
# The PL SPI clock is split into two pieces. For the normal case, the clock
# frequency is 10 MHz. This is for any read operations.
#
# CPLD_PL_SPI_SCLK_18 pass through / read back ONLY: 10 MHz
set sclk_pl_period 100.000
create_clock -name sclk_pl -period $sclk_pl_period \
[get_ports CPLD_PL_SPI_SCLK_18]
# We can go faster for the PL writes to the internal registers and LOs.
# This rate is not supported for readback, but it helps with getting the DSA
# settings and LO settings in faster.
# CPLD_PL_SPI_SCLK_18 internal ONLY: 25 MHz
set sclk_pl_wr_period 40.000
create_clock -name sclk_pl_wr -period $sclk_pl_wr_period \
[get_ports CPLD_PL_SPI_SCLK_18] -add
# Output clocks for the MAX 10's SPI master interfaces (1 for each slave IC)
create_generated_clock -source [get_ports CPLD_PS_SPI_CLK_25] \
-name clkdist_clk [get_ports CLKDIST_SPI_SCLK]
create_generated_clock -source [get_ports CPLD_PS_SPI_CLK_25] \
-name adc_clk [get_ports ADC_SPI_SCLK_18]
create_generated_clock -source [get_ports CPLD_PS_SPI_CLK_25] \
-name dac_clk [get_ports DAC_SPI_SCLK_18]
create_generated_clock -source [get_ports CPLD_PS_SPI_CLK_25] \
-name phdac_clk [get_ports PHDAC_SPI_SCLK]
create_generated_clock -source [get_ports CPLD_PL_SPI_SCLK_18] \
-master_clock [get_clocks sclk_pl] \
-name lo_clk [get_ports LO_SPI_SCLK]
create_generated_clock -source [get_ports CPLD_PL_SPI_SCLK_18] \
-master_clock [get_clocks sclk_pl_wr] \
-name lo_wr_clk [get_ports LO_SPI_SCLK] -add
create_generated_clock -source [get_ports CPLD_PL_SPI_SCLK_18] \
-master_clock [get_clocks sclk_pl] \
-name lodist_clk [get_ports LODIST_Bd_SPI_SCLK]
# Virtual clock for DSA writes for skew calculations
#create_generated_clock -source [get_pins lo_gain_table\|dsa1_le\|clk]
create_generated_clock -source [get_ports CPLD_PL_SPI_SCLK_18] \
-master_clock [get_clocks sclk_pl_wr] \
-name dsa_reg_clk [get_pins lo_gain_table\|dsa1_le\|q]
create_generated_clock -source [get_pins lo_gain_table\|dsa1_le\|q] \
-name dsa_clk [get_ports RxLO_DSA_LE]
# PL's pass through clock doesn't interact with internal clock
set_clock_groups -physically_exclusive \
-group [get_clocks {sclk_pl_wr lo_wr_clk dsa_reg_clk dsa_clk}] \
-group [get_clocks {sclk_pl lo_clk lodist_clk}]
set_clock_groups -asynchronous \
-group [get_clocks {sclk_ps clkdist_clk adc_clk dac_clk phdac_clk}] \
-group [get_clocks {sclk_pl sclk_pl_wr lo_clk lodist_clk}]
set_clock_uncertainty -to [get_clocks {sclk_ps sclk_pl sclk_pl_wr clkdist_clk
adc_clk dac_clk phdac_clk lo_clk lo_wr_clk lodist_clk dsa_reg_clk dsa_clk}] \
$clk_uncertainty
###############################################################################
# Timing Budget Calculations
###############################################################################
# Here we carve out some timing budget for the master's SPI interfaces.
# The master will use these values to time its SPI interface.
# The PL's write-only values are smaller because there are no external chip
# dependencies.
set setup_ps 25
set hold_ps 30
# PL SPI is constrained on the master with an allowed skew value of +/- 3 ns
# relative to the launch clock
# Increase to 5 ns here for more margin
set pl_skew 5
# Clocks are nominally a 50% duty cycle, so difference between latch and
# launch is half a period, so subtract allowed skew from that for setup/hold
# specification. The half period is due to launch being the falling edge and
# latch being the rising edge.
set setup_pl [expr {$sclk_pl_period / 2 - $pl_skew}]
set hold_pl [expr {$sclk_pl_period / 2 - $pl_skew}]
set setup_pl_wr [expr {$sclk_pl_wr_period / 2 - $pl_skew}]
set hold_pl_wr [expr {$sclk_pl_wr_period / 2 - $pl_skew}]
# Calculate input delays relative to falling edge (launch)
# Min is hold time after previous rising edge (previous latch)
# Max is setup time before next rising edge (next latch)
set input_delay_min_ps [expr {-$sclk_ps_period / 2 + $hold_ps}]
set input_delay_max_ps [expr {$sclk_ps_period / 2 - $setup_ps}]
set input_delay_min_pl [expr {-$sclk_pl_period / 2 + $hold_pl}]
set input_delay_max_pl [expr {$sclk_pl_period / 2 - $setup_pl}]
set input_delay_min_pl_wr [expr {-$sclk_pl_wr_period / 2 + $hold_pl_wr}]
set input_delay_max_pl_wr [expr {$sclk_pl_wr_period / 2 - $setup_pl_wr}]
# Again, carve out timing budget for master's SPI interface
# Readback on the master will depend on clk-to-q of our slave.
# These values will need to be at least as large as the worst slave.
# Clock arrival at the slave will be delayed by propagation through the MAX 10
# Data to the MAX 10's input port will be further delayed by slave's clk-to-q
# On top of that, we then need budget for the data to cross the MAX 10, head
# out the I/O, and propagate to the master's pin. Then the master will need
# some budget for setup time.
#
# Here is what we'll budget:
# Clk propagation to I/O: 7 ns
# Clk trace delay: 1 ns
# Worst-case chip clk-to-q: 10 ns
# Data trace delay: 1 ns
# Data propagation delay from input pin to output pin: 8 ns
# Total clk-to-q from MAX 10 sclk input to MAX 10 output: 27 ns
#
# Then master's budget is 23 ns for clock delay + data delay + setup time
set clk_q_max_ps 27.000
# For the PL, the worst-case chip changes to 2 ns, so there is more budget
set clk_q_max_pl 20.000
# clk-to-q determines one side of the data invalid window
# The maximum output delay is simply latch edge - clk-to-q
# Launch is falling edge, and latch is rising edge, so...
set output_delay_max_ps [expr {$sclk_ps_period / 2 - $clk_q_max_ps}]
set output_delay_max_pl [expr {$sclk_pl_period / 2 - $clk_q_max_pl}]
# The minimum output delay represents the other edge of the data invalid
# window. Our clock is likely quite delayed already, but add a little more
# margin for hold time.
set output_delay_min_ps -5.000
set output_delay_min_pl -5.000
###############################################################################
# I/O groups (for reference later)
###############################################################################
# Chip selects
set ps_csb [get_ports {
CPLD_PS_ADDR0_25
CPLD_PS_ADDR1_25
CPLD_PS_SPI_LE_25
usrp_io[12]
usrp_io[13]
}]
set pl_csb [get_ports {
CPLD_PL_SPI_ADDR0_18
CPLD_PL_SPI_ADDR1_18
CPLD_PL_SPI_ADDR2_18
CPLD_PL_SPI_LE_18
}]
# Data for internal PL SPI
set pl_src [get_ports {
CPLD_PL_SPI_SDI_18
}]
# Passthrough inputs (forward direction)
# CPLD_PS_SPI_CLK_25 and CPLD_PL_SPI_SCLK_18 are special
set ps_pt_src [get_ports {CPLD_PS_SPI_LE_25
usrp_io[12]
usrp_io[13]
CPLD_PS_ADDR1_25
CPLD_PS_SPI_SDI_25
}]
set pl_pt_src [get_ports {CPLD_PL_SPI_LE_18
CPLD_PL_SPI_ADDR1_18
CPLD_PL_SPI_ADDR2_18
CPLD_PL_SPI_SDI_18
}]
# Passthrough outputs (forward direction)
# And inputs from the SPI slaves (readback direction)
set clkdist_spi_out [get_ports {
CLKDIST_SPI_CS_L
CLKDIST_SPI_SDIO
}]
set clkdist_spi_in [get_ports {
CLKDIST_SPI_SDIO
}]
set phdac_spi [get_ports {
PHDAC_SPI_CS_L
PHDAC_SPI_SDI
}]
set dac_spi_out [get_ports {
DAC_SPI_CS_L_18
DAC_SPI_SDIO_18
}]
set dac_spi_in [get_ports {
DAC_SPI_SDIO_18
}]
set adc_spi_out [get_ports {
ADC_SPI_CS_L_18
ADC_SPI_SDIO_18
}]
set adc_spi_in [get_ports {
ADC_SPI_SDIO_18
}]
set lo_spi_out [get_ports {
LO_TX_CS_L
LO_RX_CS_L
LO_SPI_SDI
}]
set lo_spi_in [get_ports {
LOSYNTH_RX_MUXOUT
LOSYNTH_TX_MUXOUT
}]
set lodist_spi_out [get_ports {
LODIST_Bd_SPI_CS_L
LODIST_Bd_SPI_SDI
}]
# Readback outputs
set ps_rb_out [get_ports CPLD_PS_SPI_SDO_25]
set pl_rb_out [get_ports CPLD_PL_SPI_SDO_18]
##############################################################################
# Chip-selects provide async resets
##############################################################################
set_false_path -from $ps_csb -to [get_pins *|clrn]
set_false_path -from $pl_csb -to [get_pins *|clrn]
# Also ignore setup/hold analysis for chip-selects affecting readback path
# These are available many cycles before readback begins and have
# combinatorial paths to the output
set_false_path -from $ps_csb -to $ps_rb_out
set_false_path -from $pl_csb -to $pl_rb_out
set_input_delay -clock sclk_ps -clock_fall -max $input_delay_max_ps \
[get_ports CPLD_PS_ADDR0_25]
set_input_delay -clock sclk_ps -clock_fall -min $input_delay_min_ps \
[get_ports CPLD_PS_ADDR0_25]
set_input_delay -clock sclk_pl -clock_fall -max $input_delay_max_pl \
[get_ports CPLD_PL_SPI_ADDR0_18]
set_input_delay -clock sclk_pl -clock_fall -min $input_delay_min_pl \
[get_ports CPLD_PL_SPI_ADDR0_18]
set_input_delay -clock sclk_pl_wr -clock_fall -max $input_delay_max_pl_wr \
[get_ports CPLD_PL_SPI_ADDR0_18] -add
set_input_delay -clock sclk_pl_wr -clock_fall -min $input_delay_min_pl_wr \
[get_ports CPLD_PL_SPI_ADDR0_18] -add
##############################################################################
# Input delays from SPI master
##############################################################################
set_input_delay -clock sclk_ps -clock_fall -max $input_delay_max_ps $ps_pt_src
set_input_delay -clock sclk_ps -clock_fall -min $input_delay_min_ps $ps_pt_src
set_input_delay -clock sclk_pl -clock_fall -max $input_delay_max_pl $pl_pt_src
set_input_delay -clock sclk_pl -clock_fall -min $input_delay_min_pl $pl_pt_src
set_input_delay -clock sclk_pl_wr -clock_fall -max $input_delay_max_pl_wr $pl_src -add
set_input_delay -clock sclk_pl_wr -clock_fall -min $input_delay_min_pl_wr $pl_src -add
##############################################################################
# Output delays to each SPI slave (uses setup/hold times from data sheet)
##############################################################################
set adc_setup 4
set adc_hold 2
set_output_delay -clock adc_clk -max [expr {$adc_setup + $board_delay}] \
$adc_spi_out
set_output_delay -clock adc_clk -min [expr {-$adc_hold - $board_delay}] \
$adc_spi_out
set dac_setup 10
set dac_hold 5
set_output_delay -clock dac_clk -max [expr {$dac_setup + $board_delay}] \
$dac_spi_out
set_output_delay -clock dac_clk -min [expr {-$dac_hold - $board_delay}] \
$dac_spi_out
set phdac_setup 5
set phdac_hold 5
set_output_delay -clock phdac_clk -max [expr {$phdac_setup + $board_delay}] \
$phdac_spi
set_output_delay -clock phdac_clk -min [expr {-$phdac_hold - $board_delay}] \
$phdac_spi
set clkdist_setup 10
set clkdist_hold 10
set_output_delay -clock clkdist_clk -max [expr {$clkdist_setup + $board_delay}] \
$clkdist_spi_out
set_output_delay -clock clkdist_clk -min [expr {-$clkdist_hold - $board_delay}] \
$clkdist_spi_out
set lo_setup 2
set lo_hold 2
set_output_delay -clock lo_wr_clk -max [expr {$lo_setup + $board_delay}] \
$lo_spi_out
set_output_delay -clock lo_wr_clk -min [expr {-$lo_hold - $board_delay}] \
$lo_spi_out
##############################################################################
# Input delays from each SPI slave (uses clk-to-q times from data sheet)
# One board delay for clock, another for data
##############################################################################
set lo_clk_q 2
set_input_delay -clock lo_clk -clock_fall -max [expr {$lo_clk_q + $board_delay + $board_delay}] \
$lo_spi_in
set_input_delay -clock lo_clk -clock_fall -min 0 \
$lo_spi_in
set adc_clk_q 10
set dac_clk_q 10
set clkdist_clk_q 10
set_input_delay -clock adc_clk -clock_fall -max [expr {$adc_clk_q + $board_delay + $board_delay}] \
$adc_spi_in
set_input_delay -clock adc_clk -clock_fall -min 0 \
$adc_spi_in
set_input_delay -clock dac_clk -clock_fall -max [expr {$dac_clk_q + $board_delay + $board_delay}] \
$dac_spi_in
set_input_delay -clock dac_clk -clock_fall -min 0 \
$dac_spi_in
set_input_delay -clock clkdist_clk -clock_fall -max [expr {$clkdist_clk_q + $board_delay + $board_delay}] \
$clkdist_spi_in
set_input_delay -clock clkdist_clk -clock_fall -min 0 \
$clkdist_spi_in
##############################################################################
# Output delays for readback path
##############################################################################
set_output_delay -clock sclk_ps -max $output_delay_max_ps $ps_rb_out
set_output_delay -clock sclk_ps -min $output_delay_min_ps $ps_rb_out
set_output_delay -clock sclk_pl -max $output_delay_max_pl $pl_rb_out
set_output_delay -clock sclk_pl -min $output_delay_min_pl $pl_rb_out
##############################################################################
# GPIOs and DSAs
# Outputs that aren't timing-critical
##############################################################################
set gpos [get_ports {Tx_Sw*
Rx_LO_*
Tx_LO_*
Rx_Sw*
Rx_Demod_*
Tx_HB_LB_Select
Rx_HB_LB_Select
Cal_iso_Sw_Ctrl
LODIST_Bd_IO1
}]
# Inputs that aren't timing-critical
set gpis [get_ports {LO_SYNC
CPLD_ATR_TX_18
CPLD_ATR_RX_18
DAC_Alarm_18
CLKDIST_Status*
LODIST_Bd_IO1
}]
# DSAs (special skew needs)
# RxLO_DSA_LE used for skew basis
set dsas [get_ports {Tx_DSA*
Rx_DSA*
TxLO_DSA*
LO_DSA*
}]
# Just do false paths for gpios
set_false_path -to $gpos
set_false_path -from $gpis
# Unused
set_false_path -to $lodist_spi_out
# DSA skew timing
# Earlier, we created a "clock" for one of the DSA latch enable signals
# Use set_output_delay to constrain skew around the latch enable
# set_multicycle_path is used to make latch clock = launch clock for setup
# Constrain skew to 8 ns -- controller nominally does 120 ns minimum between
# edges, and 100 ns is the DSA's requirement for setup/hold
set dsa_skew 8.0
set_output_delay -clock dsa_clk -max -$dsa_skew $dsas
set_output_delay -clock dsa_clk -min $dsa_skew $dsas
set_multicycle_path -start -setup 0 -to $dsas
set_max_delay -from [get_ports CPLD_ATR_TX_18] \
-to [get_ports {Tx_Sw1_Ctrl_1 Tx_Sw1_Ctrl_2}] 10.0
|