Skip to content

Commit fa931a0

Browse files
author
Lukas Stasytis
committed
fixed DWC in regular cases and improved buffer correction
1 parent b7f7cfe commit fa931a0

3 files changed

Lines changed: 103 additions & 37 deletions

File tree

src/finn/custom_op/fpgadataflow/hwcustomop.py

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -426,42 +426,65 @@ def derive_characteristic_fxns_analytically(self, period, override_rtlsim_dict):
426426

427427
counter, cycles, txn_in = top_level_phase.traverse_phase_tree(0, counter, cycles, txn_in)
428428

429-
def apply_micro_buffer_correction(start, txn_in):
429+
def apply_micro_buffer_correction(start, txn_in, period):
430430
"""There are cases where a node can buffer up the very first 1-2 inputs
431431
immediately, even if it has not started properly consuming inputs yet
432432
This behavior is extremely difficult to model in a characterization tree
433433
and so we perform a manual correction by incrementing the number of
434434
inputs read by 1 and detracting 1 read from the tail of the period
435435
436436
Which node types & configurations this applies for is yet to be
437-
fully determined, but the corrections should happen here"""
437+
fully determined, but the corrections should happen here.
438+
It is possible that this correction is entire unncessary and
439+
simply an rtlsim artefact, but we maintain it for testability for now"""
440+
441+
buffer = 0
438442

439443
if "FMPadding" in self.onnx_node.name:
440444
if "_rtl" in (self.__class__.__name__):
441445
buffer = 1
442-
idx = start + 1
443446
else:
444447
buffer = 2
445-
txn_in[start + 1] += 1
448+
449+
if "StreamingDataWidthConverter" in self.onnx_node.name:
450+
if "_rtl" in (self.__class__.__name__):
451+
buffer = 1
452+
else:
453+
buffer = 2
454+
455+
if buffer > 0:
456+
# buffering does not happen in nodes with short wind-ups
457+
if period < 14:
458+
return txn_in
459+
460+
# main routine
461+
if buffer == 2:
462+
if txn_in[start + 1] - txn_in[start] >= 1:
463+
buffer = 1
464+
else:
465+
txn_in[start + 1] += 1
446466

447467
idx = start + buffer
448468
while idx < len(txn_in):
449-
txn_in[idx] += buffer
469+
if txn_in[idx] - txn_in[idx - 1] < buffer:
470+
txn_in[idx] += buffer
450471
idx += 1
451472

452473
idx = len(txn_in) - 1
453474
last = txn_in[idx]
475+
454476
# deduct 1 read from the tail
455477
while last == txn_in[idx]:
456478
txn_in[idx] -= buffer
457479
idx -= 1
458480

481+
# one extra element to deduct in case of 2 buffers
459482
if buffer == 2:
460483
txn_in[idx] -= 1
461484

462485
return txn_in
463486

464-
txn_in = apply_micro_buffer_correction(0, txn_in)
487+
txn_in = apply_micro_buffer_correction(0, txn_in, period)
465488

466489
txn_in += [counter] * (period - cycles)
467490
padding += period - cycles
@@ -471,7 +494,7 @@ def apply_micro_buffer_correction(start, txn_in):
471494

472495
counter, cycles, txn_in = top_level_phase.traverse_phase_tree(0, counter, cycles, txn_in)
473496

474-
txn_in = apply_micro_buffer_correction(period, txn_in)
497+
txn_in = apply_micro_buffer_correction(period, txn_in, period)
475498

476499
txn_in += [counter] * (period * 2 - cycles)
477500
padding += period * 2 - cycles

src/finn/custom_op/fpgadataflow/streamingdatawidthconverter.py

Lines changed: 69 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -220,43 +220,85 @@ def lut_estimation(self):
220220
return int(cnt_luts + cset_luts)
221221

222222
def prepare_kwargs_for_characteristic_fx(self):
223-
# function for the old DWC version
224-
# newer version will need a separate, much more
225-
# complicated function
223+
"""Characteristic function of the non-general DWC
224+
variant."""
226225

227-
numInWords = int(np.prod(self.get_folded_input_shape()[-2:-1]))
228-
numOutWords = int(np.prod(self.get_folded_output_shape()[-2:-1]))
229-
numReps = int(np.prod(self.get_folded_input_shape()[:1]))
226+
numReps = int(np.prod(self.get_folded_input_shape()[:-1]))
230227

231-
# inWidth = self.get_nodeattr("inWidth")
232-
# outWidth = self.get_nodeattr("outWidth")
228+
inWidth = self.get_nodeattr("inWidth")
229+
outWidth = self.get_nodeattr("outWidth")
233230

234-
read_inputs = Characteristic_Node("read all words", [(numInWords, [1, 0])], True)
231+
print("\nin,out widths:", inWidth, outWidth)
232+
print("inshape:", self.get_folded_input_shape())
233+
print("outshape:", self.get_folded_output_shape())
235234

236-
write_outputs = Characteristic_Node("write all words", [(numOutWords, [0, 1])], True)
235+
wind_up = 1
237236

238-
up_convert_word = Characteristic_Node(
239-
"up convert all words in a single transaction",
240-
[(1, read_inputs), (1, write_outputs)],
241-
False,
242-
)
237+
idle = Characteristic_Node("idle", [(1, [0, 0])], True)
243238

244-
down_convert_word = Characteristic_Node(
245-
"down convert all words in a single transaction",
246-
[(1, read_inputs), (1, write_outputs)],
247-
False,
248-
)
239+
if inWidth > outWidth:
240+
# down-conversion
241+
if inWidth % outWidth != 0:
242+
return None # no support for gcd partial conversion yet
249243

250-
if numInWords > numOutWords:
251-
reps = Characteristic_Node(
252-
"compute a set of DWCs with up conversion", [(numReps, up_convert_word)], False
244+
writes_per_read = inWidth // outWidth
245+
# read 1, write many, repeats for in-word count
246+
247+
read_input = Characteristic_Node("read 1 word", [(1, [1, 0])], True)
248+
249+
write_output = Characteristic_Node("write words", [(writes_per_read, [0, 1])], True)
250+
251+
down_convert_word = Characteristic_Node(
252+
"down convert all words in a single transaction",
253+
[(1, read_input), (1, write_output)],
254+
False,
253255
)
254-
else:
255-
reps = Characteristic_Node(
256-
"compute a set of DWCs with down conversion", [(numReps, down_convert_word)], False
256+
257+
numReps = int(np.prod(self.get_folded_input_shape()[:-1]))
258+
259+
dwc_top = Characteristic_Node(
260+
"compute a set of DWCs with down conversion",
261+
[(wind_up, idle), (numReps, down_convert_word)],
262+
False,
263+
)
264+
265+
elif inWidth < outWidth:
266+
# up-conversion
267+
268+
if outWidth % inWidth != 0:
269+
return None # no support for gcd partial conversion yet
270+
271+
reads_per_write = outWidth // inWidth
272+
# read 1, write many, repeats for in-word count
273+
274+
read_input = Characteristic_Node("read words", [(reads_per_write, [1, 0])], True)
275+
276+
write_output = Characteristic_Node("write 1 word", [(1, [0, 1])], True)
277+
278+
up_convert_word = Characteristic_Node(
279+
"down convert all words in a single transaction",
280+
[(1, read_input), (1, write_output)],
281+
False,
282+
)
283+
284+
numReps = int(np.prod(self.get_folded_output_shape()[:-1]))
285+
dwc_top = Characteristic_Node(
286+
"compute a set of DWCs with up conversion",
287+
[(wind_up, idle), (numReps, up_convert_word)],
288+
False,
257289
)
258290

259-
return reps
291+
else:
292+
# pass-through
293+
294+
numReps = int(np.prod(self.get_folded_input_shape()[:-1]))
295+
296+
pass_through = Characteristic_Node("pass-through", [(1, [1, 1])], True)
297+
298+
dwc_top = Characteristic_Node(
299+
"DWC pass-through, no conversion", [(wind_up, idle), (numReps, pass_through)], False
300+
)
301+
return dwc_top
260302

261303
# def prepare_kwargs_for_characteristic_fx_old(self):
262304
# numInWords = int(np.prod(self.get_folded_input_shape()[-2:-1]))

tests/fpgadataflow/test_fpgadataflow_dwc.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,12 +186,13 @@ def test_fpgadataflow_dwc_stitched_rtlsim(config, impl_style):
186186
@pytest.mark.parametrize(
187187
"config",
188188
[
189-
([1, 24], 6, 4, DataType["INT2"]),
190-
([1, 24], 4, 6, DataType["INT2"]),
189+
([1, 24], 8, 4, DataType["INT2"]),
190+
# ([1, 24], 4, 6, DataType["INT2"]),
191191
([1, 4], 2, 4, DataType["BIPOLAR"]),
192192
([1, 4], 4, 2, DataType["INT2"]),
193193
([1, 2, 8], 4, 4, DataType["INT2"]),
194194
([1, 2, 8], 8, 16, DataType["INT2"]),
195+
([1, 320], 2, 160, DataType["INT2"]),
195196
],
196197
)
197198
@pytest.mark.parametrize("exec_mode", ["rtlsim"])
@@ -207,7 +208,7 @@ def test_fpgadataflow_analytical_characterization_dwc(direction, config, exec_mo
207208
# model = model.transform(InferShapes())
208209
# model = model.transform(SetExecMode(mode))
209210

210-
node_details = ("DWC", shape, inWidth, outWidth, finn_dtype, impl_style)
211+
node_details = ("DWC", config, impl_style)
211212
part = "xc7z020clg400-1"
212213
target_clk_ns = 4
213214
allowed_chr_offset_positions = 5

0 commit comments

Comments
 (0)