7
31
Fork
You've already forked blackmagic
23

Increase performance of SWD and JTAG bitbanging #1688

Open
ALTracer wants to merge 12 commits from ALTracer/fix/tap-timing into main
pull from: ALTracer/fix/tap-timing
merge into: blackmagic-debug:main
blackmagic-debug:main
blackmagic-debug:fix/pre-bmp-v3-cross-file-cleanup
blackmagic-debug:feature/bmda-remote-comms
blackmagic-debug:ALTracer/feature/aarch64-ident
blackmagic-debug:feature/better-meson-optimisation-handling
blackmagic-debug:feature/am335x-support
blackmagic-debug:feature/esp32-c3-support
blackmagic-debug:feature/cortex-ar-software-breakpoints
blackmagic-debug:feature/unit-testing
blackmagic-debug:feature/windows-usb-serial-interface-naming
blackmagic-debug:fix/bmp-external-spi
blackmagic-debug:ALTracer/feature/bluepillplus-platform
blackmagic-debug:ALTracer/feature/at32f43x-unrdp
blackmagic-debug:feature/const-correctness
blackmagic-debug:ALTracer/feature/fault_handlers
blackmagic-debug:ALTracer/feature/hazard3-ice40-support
blackmagic-debug:fix/ci-cleanup
blackmagic-debug:ALTracer/fix/gdb-10-12-thread
blackmagic-debug:ALTracer/feature/blackpill-f4-adc
blackmagic-debug:ALTracer/fix/cortex-desc-allocfail-report
blackmagic-debug:ALTracer/feature/spi-perf
blackmagic-debug:ALTracer/feature/calibrate_swd
blackmagic-debug:ALTracer/feature/blank-check
blackmagic-debug:feature/avr
blackmagic-debug:v2.0
blackmagic-debug:v1.9
blackmagic-debug:v1.10
blackmagic-debug:v1.8
ALTracer commented 2023年11月25日 21:13:15 +01:00 (Migrated from github.com)
Copy link

Detailed description

  • This is a refactoring of core bitbanging routines.
  • The existing problem was IMO suboptimal efficiency of swdptap, jtagtap functions.
  • This PR solves this problem by extracting and improving the busy-looping delay; dropping double STM32F4 GPIO_BSRR writes; and rebalancing some of the no_delay routines to adjust for changes.

Tested on blackpill-f411ce platform connected to a stm32f103cb DUT. Firmware does not crash on exceptions from spurious ACKs. The 24MHz fx2la does not let me verify setup-and-hold timing compliancy, but the target silicon replies okay. I could retest with other targets accessible to me, possibly with low HCLKs. I was focusing ot stm32f4 platforms, but lm4f launchpad-icdi may be affected, too.
LINERESET waveform improved from 2.988 MHz to ~8.000 MHz, that is swd_seq_out_no_delay().
BMDA -r -f 8M was 22.5 and 41 KiB/s in JTAG and SWD mode, becomes 28 and 44 KiB/s respectively (but that bottleneck is different).

The PR aims to:

  • increase raw SWD performance of capable platforms (stm32f4), and by extension JTAG performance;
  • improve granularity of selecting max frequency (thanks to a quicker busy-delay loop); and fix said frequency calculations;
  • rebalance edge-case timings where needed;
  • optionally reduce AP WAIT polling spam (this makes logs and wire capture snapshots cleaner, but may hurt performance).

Important mentions:
GPIO_BSRR hack was introduced in github.com/blackmagic-debug/blackmagic@f1ea5ed8f9 ; the reasoning behind it is not clear to me, but we can either set some default divider to target lower (2 MHz) frequency, and BMDA already asks for some 3 or 4 MHz. I wired everything on a breadboard with flying wires and a couple ground connections (no ribbon cables).
swdptap.c has optimize(3) since https://github.com/blackmagic-debug/blackmagic/pull/669/commits/4698a26bab59236efc0217068b49ae734853fd86 (but not jtagtap.c). -O3 increases flash footprint and may alter the timings.

Your checklist for this pull request

  • I've read the Code of Conduct
  • I've read the guidelines for contributing to this repository
  • It builds for hardware native (make PROBE_HOST=native)
  • It builds as BMDA (make PROBE_HOST=hosted)
  • I've tested it to the best of my ability
  • My commit messages provide a useful short description of what the commits do

Closing issues

No known issues w.r.t. SWJ speed.

## Detailed description * This is a refactoring of core bitbanging routines. * The existing problem was IMO suboptimal efficiency of swdptap, jtagtap functions. * This PR solves this problem by extracting and improving the busy-looping delay; dropping double STM32F4 GPIO_BSRR writes; and rebalancing some of the no_delay routines to adjust for changes. Tested on `blackpill-f411ce` platform connected to a stm32f103cb DUT. Firmware does not crash on exceptions from spurious ACKs. The 24MHz fx2la does not let me verify setup-and-hold timing compliancy, but the target silicon replies okay. I could retest with other targets accessible to me, possibly with low HCLKs. I was focusing ot stm32f4 platforms, but lm4f `launchpad-icdi` may be affected, too. LINERESET waveform improved from 2.988 MHz to ~8.000 MHz, that is `swd_seq_out_no_delay()`. BMDA `-r -f 8M` was 22.5 and 41 KiB/s in JTAG and SWD mode, becomes 28 and 44 KiB/s respectively (but that bottleneck is different). The PR aims to: * increase raw SWD performance of capable platforms (stm32f4), and by extension JTAG performance; * improve granularity of selecting max frequency (thanks to a quicker busy-delay loop); and fix said frequency calculations; * rebalance edge-case timings where needed; * optionally reduce AP WAIT polling spam (this makes logs and wire capture snapshots cleaner, but may hurt performance). Important mentions: GPIO_BSRR hack was introduced in https://github.com/blackmagic-debug/blackmagic/commit/f1ea5ed8f9f6dc1f006185d051da682bed63c6ac ; the reasoning behind it is not clear to me, but we can either set some default divider to target lower (2 MHz) frequency, and BMDA already asks for some 3 or 4 MHz. I wired everything on a breadboard with flying wires and a couple ground connections (no ribbon cables). `swdptap.c` has `optimize(3)` since https://github.com/blackmagic-debug/blackmagic/pull/669/commits/4698a26bab59236efc0217068b49ae734853fd86 (but not `jtagtap.c`). -O3 increases flash footprint and may alter the timings. ## Your checklist for this pull request * [x] I've read the [Code of Conduct](https://github.com/blackmagic-debug/blackmagic/blob/main/CODE_OF_CONDUCT.md) * [x] I've read the [guidelines for contributing](https://github.com/blackmagic-debug/blackmagic/blob/main/CONTRIBUTING.md) to this repository * [x] It builds for hardware native (`make PROBE_HOST=native`) * [x] It builds as BMDA (`make PROBE_HOST=hosted`) * [ ] I've tested it to the best of my ability * [x] My commit messages provide a useful short description of what the commits do ## Closing issues No known issues w.r.t. SWJ speed.
dragonmux left a comment
Copy link

This is looking provisionally very good and we see a lot of promise here - we'll have to do a pile of testing to make sure this doesn't regress the setup-and-hold timings, but mostly the notes and comments in this review are about form not function. The whole volatile vs register thing in particular raises some interesting questions to explore.

This is looking provisionally very good and we see a lot of promise here - we'll have to do a pile of testing to make sure this doesn't regress the setup-and-hold timings, but mostly the notes and comments in this review are about form not function. The whole `volatile` vs `register` thing in particular raises some interesting questions to explore.
@ -31,11 +31,13 @@
jtag_proc_s jtag_proc;

We'll have to do some captures and testing with this attribute to make sure it's not shooting the timings in the foot - as you note in the PR description. We do note that this particular function signature still has the old ticks nomenclature in it, so please switch that to clock_cycles.

We'll have to do some captures and testing with this attribute to make sure it's not shooting the timings in the foot - as you note in the PR description. We do note that this particular function signature still has the old `ticks` nomenclature in it, so please switch that to `clock_cycles`.
@ -51,9 +53,8 @@ void jtagtap_init(void)
jtag_proc.tap_idle_cycles = 1;

This is a great shout - if you could please move the comment explaining what this is doing up to this, you can then eliminate the preprocessor guarding and the old code.

This is a great shout - if you could please move the comment explaining what this is doing up to this, you can then eliminate the preprocessor guarding and the old code.
@ -65,2 +65,3 @@
continue;
/* Hold low for approximately 1.5 ms */
platform_delay(1U); /* Requires SysTick interrupt to be unblocked */
gpio_set(TRST_PORT, TRST_PIN);

Of these two forms, we prefer this one. Please see our notes in timing_stm32.c's platform_delay_busy on the matter of __asm__("nop") vs continue. The same query and notes apply here as there.

Of these two forms, we prefer this one. Please see our notes in timing_stm32.c's `platform_delay_busy` on the matter of `__asm__("nop")` vs `continue`. The same query and notes apply here as there.
@ -158,3 +169,4 @@
platform_delay_busy(target_clk_divider);
/* If TDO is high, store a 1 in the appropriate position in the value being accumulated */
if (gpio_get(TDO_PORT, TDO_PIN))
value |= 1U << bit;

Please include a comment on what this is doing - we don't want to assume that the reader has seen the other uses of this and knows what's going on. Is there any particular reason for the inserting of a no-op rather than only a reordering barrier?

Please include a comment on what this is doing - we don't want to assume that the reader has seen the other uses of this and knows what's going on. Is there any particular reason for the inserting of a no-op rather than only a reordering barrier?

The cppreference page on C's volatile does not mention anything about forced stack usage and we've never seen it imply any such - are we sure that is what the compiler's doing here? Either way, we would strongly prefer you to use a for loop not a do-while here. This is a for loop in disguise.

The disappearance of the loop when using continue; without volatile can be entirely explained not so much by DCE (it's the result, not the cause) but by there being no observable side effects thus allowing the compiler to assume that nothing of value is done by the loop. This is the reason for using volatile in the jtagtap code. Perhaps we can use volatile register to force the compiler to consider the operation to have observable side-effects but also keep the loop counter register-bound?

The [cppreference page on C's `volatile`](https://en.cppreference.com/w/c/language/volatile) does not mention anything about forced stack usage and we've never seen it imply any such - are we sure that is what the compiler's doing here? Either way, we would strongly prefer you to use a for loop not a do-while here. This is a for loop in disguise. The disappearance of the loop when using `continue;` without `volatile` can be entirely explained not so much by DCE (it's the result, not the cause) but by there being no observable side effects thus allowing the compiler to assume that nothing of value is done by the loop. This is the reason for using `volatile` in the jtagtap code. Perhaps we can use `volatile register` to force the compiler to consider the operation to have observable side-effects but also keep the loop counter register-bound?

Same comments as in jtagtap.c

Same comments as in jtagtap.c
@ -187,10 +198,12 @@ static void swdptap_seq_out_parity(const uint32_t tms_states, const size_t clock
const bool parity = calculate_odd_parity(tms_states);
swdptap_seq_out(tms_states, clock_cycles);

As this is only used in the one place and is bitwise masked, perhaps lets make this const uint8_t parity and put the bit mask on the end, lifting it from the gpio_set_val() call below? Failing that, we should make it uint32_t so we don't do a signed+bitwise oops below.

As this is only used in the one place and is bitwise masked, perhaps lets make this `const uint8_t parity` and put the bit mask on the end, lifting it from the `gpio_set_val()` call below? Failing that, we should make it `uint32_t` so we don't do a signed+bitwise oops below.

Please insert a note here about this being a reordering barrier - same as in other places the trick is used.

Please insert a note here about this being a reordering barrier - same as in other places the trick is used.
ALTracer (Migrated from github.com) reviewed 2023年11月26日 00:29:33 +01:00
ALTracer (Migrated from github.com) commented 2023年11月26日 00:29:33 +01:00
Copy link

Indeed volatile register was the first thing I tried, only to be yelled at by the compiler to swap qualifiers... and identical codegen. I specifically wanted to avoid extraneous ldr/str of loop counters, so I monitored Puncover and objdump -CSd. Maybe Compiler Explorer can shed some light on why this codegens this way.

Indeed `volatile register` was the first thing I tried, only to be yelled at by the compiler to swap qualifiers... and identical codegen. I specifically wanted to avoid extraneous ldr/str of loop counters, so I monitored Puncover and objdump -CSd. Maybe Compiler Explorer can shed some light on why this codegens this way.

Oh how interesting - ok, that'll be an interesting session in CE then as yes, that might well provide some insight into how and why the compiler's choosing to do what it does.

Oh how interesting - ok, that'll be an interesting session in CE then as yes, that might well provide some insight into how and why the compiler's choosing to do what it does.
ALTracer (Migrated from github.com) reviewed 2023年11月26日 00:45:36 +01:00
ALTracer (Migrated from github.com) commented 2023年11月26日 00:45:36 +01:00
Copy link

Probably qualifying a variable as volatile forces the compiler to assume that it should be observable elsewhere, and hence needs to be pinned to SRAM (if only on the stack). This directly contradicts with the intent of register-allocated counters (which debuggers don't display due to "optimized away" but you can always dump the gp_regs). Something "dead store elimination".
And the for-loop form is longer and has an extra jump, I didn't subjectively like it; objectively it has to fit into Flash prefetch buffer which is a few (4) 64-bit lines on F103 (?) to not incur wait-states of 72MHz MCU against 24MHz flash on random jumps.

Probably qualifying a variable as `volatile` forces the compiler to assume that it should be observable elsewhere, and hence needs to be pinned to SRAM (if only on the stack). This directly contradicts with the intent of register-allocated counters (which debuggers don't display due to "optimized away" but you can always dump the gp_regs). Something "dead store elimination". And the for-loop form is longer and has an extra jump, I didn't subjectively like it; objectively it has to fit into Flash prefetch buffer which is a few (4) 64-bit lines on F103 (?) to not incur wait-states of 72MHz MCU against 24MHz flash on random jumps.

From our perspective re the for loop part, the for loop form should code gen to the same or very near the same as the do-while (perhaps needs the condition expressed as --counter > 0 and --counter in the update step removed to do it) while being a much clearer expression of your intent. Think this is very much going to be "take it to Compiler Explorer and tinker for an hour" to find the right thing to do and the right way to express this.

From our perspective re the for loop part, the for loop form should code gen to the same or very near the same as the do-while (perhaps needs the condition expressed as `--counter > 0` and `--counter` in the update step removed to do it) while being a much clearer expression of your intent. Think this is very much going to be "take it to Compiler Explorer and tinker for an hour" to find the right thing to do and the right way to express this.
koendv commented 2023年11月28日 11:02:35 +01:00 (Migrated from github.com)
Copy link

With #1688 and #1690 applied, on an stm32f411 platform, rtt has a measured speed of 114.292 chars/s if target is stm32f102, 121.297 chars/s if target is stm32f411.
The documentation UsingRTT.md mentions a speed of 50.000 chars/s, perhaps update this number if PR is merged.

With #1688 and #1690 applied, on an stm32f411 platform, rtt has a measured speed of 114.292 chars/s if target is stm32f102, 121.297 chars/s if target is stm32f411. The documentation UsingRTT.md mentions a speed of 50.000 chars/s, perhaps update this number if PR is merged.
ALTracer (Migrated from github.com) reviewed 2023年12月02日 20:10:46 +01:00
@ -187,10 +198,12 @@ static void swdptap_seq_out_parity(const uint32_t tms_states, const size_t clock
const bool parity = calculate_odd_parity(tms_states);
swdptap_seq_out(tms_states, clock_cycles);
ALTracer (Migrated from github.com) commented 2023年12月02日 20:10:46 +01:00
Copy link

Zooming out: do we actually care about 2..32 number of bits, or just the SWD parity per IHI0031 B4.1.6? The same 4698a26ba introduced the two builtin calls, which was a better idea than spinning the parity manually. And I see an opportunity to eliminate either __popcountsi2() or __paritysi2(), currently both are used, only once. They are 32+40 bytes, (36+52 depending on platform Thumb2 availability; popcount is bigger). GCC sees we don't care in seq_out and substitutes parity in place of popcount (because of the LSBit masking), but doesn't see in seq_in and leaves popcount alone.

Zooming out: do we actually care about 2..32 number of bits, or just the SWD parity per IHI0031 B4.1.6? The same 4698a26ba introduced the two builtin calls, which was a better idea than spinning the parity manually. And I see an opportunity to eliminate either `__popcountsi2()` or `__paritysi2()`, currently both are used, only once. They are 32+40 bytes, (36+52 depending on platform Thumb2 availability; popcount is bigger). GCC sees we don't care in seq_out and substitutes parity in place of popcount (because of the LSBit masking), but doesn't see in seq_in and leaves popcount alone.
ALTracer (Migrated from github.com) reviewed 2023年12月02日 21:11:12 +01:00
@ -31,11 +31,13 @@
jtag_proc_s jtag_proc;
ALTracer (Migrated from github.com) commented 2023年12月02日 21:11:12 +01:00
Copy link

750 kHz of tdi_tdo_seq on native was unremarkable, I hope performance improves -- please note, during capture/analysis, whether a given hardware relies on ancient FLITF Prefetch (2x64-bit lines) or runs from "0-wait-state" shadow SRAM.
Updated jtagtap_tms_seq() declaration and definition.

750 kHz of tdi_tdo_seq on `native` was unremarkable, I hope performance improves -- please note, during capture/analysis, whether a given hardware relies on ancient FLITF Prefetch (2x64-bit lines) or runs from "0-wait-state" shadow SRAM. Updated `jtagtap_tms_seq()` declaration and definition.
ALTracer (Migrated from github.com) reviewed 2023年12月02日 21:33:52 +01:00
ALTracer (Migrated from github.com) commented 2023年12月02日 21:33:52 +01:00
Copy link

Your suggestion of --counter > 0 gets the codegen I want and the C idiomatic form you look to preserve, thanks.
Updated the three places accordingly.
m3/m4/m7 still get the SUBS+BNE.N, m0 (f072) gets subs; cmp; bne.n so its divisor timings will be off.

Your suggestion of `--counter > 0` gets the codegen I want and the C idiomatic form you look to preserve, thanks. Updated the three places accordingly. m3/m4/m7 still get the SUBS+BNE.N, m0 (`f072`) gets `subs; cmp; bne.n` so its divisor timings will be off.
ALTracer (Migrated from github.com) reviewed 2023年12月02日 21:44:55 +01:00
@ -51,9 +53,8 @@ void jtagtap_init(void)
jtag_proc.tap_idle_cycles = 1;
ALTracer (Migrated from github.com) commented 2023年12月02日 21:44:54 +01:00
Copy link

Updated as such. Note that it would be ADIV5_SWD_TO_JTAG_SELECT_SEQUENCE if the unit included adiv5.h -- this magic number also occurs in hosted/ftdi_jtag. That one will use _next().
I assume the jtagtap_cycle() method is a somewhat recent addition -- it's not used widely across the codebase, if only in BMPremote. I can even eliminate it as dead code for ADIv5 and RISC-V DTM targets, breaking the v0/v2 remote contract; unsure about AVR PDI. It's also too fast in comparison to other methods.

Updated as such. Note that it would be `ADIV5_SWD_TO_JTAG_SELECT_SEQUENCE` if the unit included adiv5.h -- this magic number also occurs in hosted/ftdi_jtag. That one will use `_next()`. I assume the `jtagtap_cycle()` method is a somewhat recent addition -- it's not used widely across the codebase, if only in BMPremote. I can even eliminate it as dead code for ADIv5 and RISC-V DTM targets, breaking the v0/v2 remote contract; unsure about AVR PDI. It's also too fast in comparison to other methods.
@ -187,10 +198,12 @@ static void swdptap_seq_out_parity(const uint32_t tms_states, const size_t clock
const bool parity = calculate_odd_parity(tms_states);
swdptap_seq_out(tms_states, clock_cycles);

We only care about the single bit of parity (__builtin_parity(tms_states)), not the rest of the value of popcount.

This kind of thing is why we've been thinking on how on earth to lift these builtin calls into their own function in one of the buffer_utils.h or maths_utils.h headers, as we should really provide: versions for each supported compiler; a fallback implementation for compilers that do not have the required builtin (just as with ulog2 which uses the exact paradigm we're wanting to switch to).

We only care about the single bit of parity (`__builtin_parity(tms_states)`), not the rest of the value of popcount. This kind of thing is why we've been thinking on how on earth to lift these builtin calls into their own function in one of the buffer_utils.h or maths_utils.h headers, as we should really provide: versions for each supported compiler; a fallback implementation for compilers that do not have the required builtin (just as with ulog2 which uses the exact paradigm we're wanting to switch to).
@ -51,9 +53,8 @@ void jtagtap_init(void)
jtag_proc.tap_idle_cycles = 1;

As we've got a #define for it in that header, include the header - that's fine. We should look to reduce the number of places this constant is defined down to the one, documented, and global place ideally.

Correct, jtagtap_cycle() was introduced in v1.8 and the BMP remote protocol implementation may need tweaking to provide a jtagtap_next()-based fallback, but we're principally fine with that as a pivot as this is exactly the kind of thing it was introduced for from what we can tell from Uwe's PR and commit for it.

As we've got a `#define` for it in that header, include the header - that's fine. We should look to reduce the number of places this constant is defined down to the one, documented, and global place ideally. Correct, `jtagtap_cycle()` was introduced in v1.8 and the BMP remote protocol implementation may need tweaking to provide a jtagtap_next()-based fallback, but we're principally fine with that as a pivot as this is exactly the kind of thing it was introduced for from what we can tell from Uwe's PR and commit for it.
ALTracer (Migrated from github.com) reviewed 2023年12月31日 04:52:09 +01:00
@ -187,10 +198,12 @@ static void swdptap_seq_out_parity(const uint32_t tms_states, const size_t clock
const bool parity = calculate_odd_parity(tms_states);
swdptap_seq_out(tms_states, clock_cycles);
ALTracer (Migrated from github.com) commented 2023年12月31日 04:52:09 +01:00
Copy link

Thread resolved by merging (and rebasing over) PR1700.

Thread resolved by merging (and rebasing over) PR1700.
ALTracer (Migrated from github.com) reviewed 2023年12月31日 04:54:56 +01:00
@ -65,2 +65,3 @@
continue;
/* Hold low for approximately 1.5 ms */
platform_delay(1U); /* Requires SysTick interrupt to be unblocked */
gpio_set(TRST_PORT, TRST_PIN);
ALTracer (Migrated from github.com) commented 2023年12月31日 04:54:55 +01:00
Copy link

Updated delay loops to --counter > 0 form.

Updated delay loops to `--counter > 0` form.
ALTracer (Migrated from github.com) reviewed 2023年12月31日 04:59:04 +01:00
@ -158,3 +169,4 @@
platform_delay_busy(target_clk_divider);
/* If TDO is high, store a 1 in the appropriate position in the value being accumulated */
if (gpio_get(TDO_PORT, TDO_PIN))
value |= 1U << bit;
ALTracer (Migrated from github.com) commented 2023年12月31日 04:59:04 +01:00
Copy link

Annotated for the readers. This routine is too fast in comparison to others, because it has nothing to do besides toggle the jTCK pin, and it certainly does not move data into (or out of) BMP. I may even want to add more nops or something similar to tone down this one.

Annotated for the readers. This routine is too fast in comparison to others, because it has nothing to do besides toggle the jTCK pin, and it certainly does not move data into (or out of) BMP. I may even want to add more nops or something similar to tone down this one.
ALTracer (Migrated from github.com) reviewed 2023年12月31日 05:00:34 +01:00
ALTracer (Migrated from github.com) commented 2023年12月31日 05:00:34 +01:00
Copy link

Updated the delay loop to --counter > 0U;) form.

Updated the delay loop to `--counter > 0U;)` form.
ALTracer (Migrated from github.com) reviewed 2023年12月31日 05:10:35 +01:00
ALTracer (Migrated from github.com) commented 2023年12月31日 05:10:35 +01:00
Copy link

Added a comment. Both swdptap_seq_in_no_delay() and swdptap_seq_out_no_delay() need careful consideration in code influencing bitbanged timings, including effect of gpio_set()/clear() or gpio_set_val() and gpio_get().
I would like to see this entire routine fit into ART cache of STM32F4, or at least not jump around thanks to all the gpio_* bits inlined.

Added a comment. Both `swdptap_seq_in_no_delay()` and `swdptap_seq_out_no_delay()` need careful consideration in code influencing bitbanged timings, including effect of `gpio_set()/clear()` or `gpio_set_val()` and `gpio_get()`. I would like to see this entire routine fit into ART cache of STM32F4, or at least not jump around thanks to all the `gpio_*` bits inlined.
ALTracer commented 2024年01月01日 18:14:20 +01:00 (Migrated from github.com)
Copy link

With #1688 and #1690 applied, on an stm32f411 platform, rtt has a measured speed of 114.292 chars/s if target is stm32f102, 121.297 chars/s if target is stm32f411. The documentation UsingRTT.md mentions a speed of 50.000 chars/s, perhaps update this number if PR is merged.

Thanks; the documented speed will certainly need updating, more so because of #1536.
I repeated the tests myself on blackpill-f411ce platform (96 MHz) and a gd32f103cb DUT clocked to 72 MHz; then 96, and 64, and even 48 MHz by providing a modified SystemClockConfig(). At default poll interval settings of 256 8 10 it is ~97000 chars/s, at 50 8 10 it is as you say, ~120000 chars/s, but altering them to monitor rtt poll 25 5 10 yields ~167000-17000 chars/s. This means the bottleneck is not in DUT downclocked to 48MHz, but rather in the BMD/libopencm3 code. orbtop could provide more detailed data.
BMDA, for the record, manages only ~27000 chars/s using BMPremote with this platform (and non-1-byte read libc calls).

> With #1688 and #1690 applied, on an stm32f411 platform, rtt has a measured speed of 114.292 chars/s if target is stm32f102, 121.297 chars/s if target is stm32f411. The documentation UsingRTT.md mentions a speed of 50.000 chars/s, perhaps update this number if PR is merged. Thanks; the documented speed will certainly need updating, more so because of #1536. I repeated the tests myself on `blackpill-f411ce` platform (96 MHz) and a gd32f103cb DUT clocked to 72 MHz; then 96, and 64, and even 48 MHz by providing a modified `SystemClockConfig()`. At default poll interval settings of `256 8 10` it is ~97000 chars/s, at `50 8 10` it is as you say, ~120000 chars/s, but altering them to `monitor rtt poll 25 5 10` yields ~167000-17000 chars/s. This means the bottleneck is not in DUT downclocked to 48MHz, but rather in the BMD/libopencm3 code. `orbtop` could provide more detailed data. BMDA, for the record, manages only ~27000 chars/s using BMPremote with this platform (and non-1-byte read libc calls).
@ -51,9 +53,8 @@ void jtagtap_init(void)
jtag_proc.tap_idle_cycles = 1;

We went checking and the remote protocol has this fallback - apparently we thought about this when rewriting BMDA's implementation. We should verify fallbacks for the other adaptors are present, but as most of them outright replace this init code we don't see that being a problem as such - though it is a target for potential future dedupe in the backends.

We went checking and the remote protocol has this fallback - apparently we thought about this when rewriting BMDA's implementation. We should verify fallbacks for the other adaptors are present, but as most of them outright replace this init code we don't see that being a problem as such - though it is a target for potential future dedupe in the backends.
tlyu commented 2024年01月15日 00:15:42 +01:00 (Migrated from github.com)
Copy link

Thanks for working on this! I tried it out a bit, and it seems to sometimes set target_clk_divider to zero, causing underflow and very long delays. This would be on platforms that set BITBANG_CALIBRATED_FREQS. On the other platforms, there are added checks that prevent that.

At least the clock speeds seem more consistent across different routines.

There are lots of remaining oddities about the timing that I see on the logic analyzer, but I'm still investigating those.

Thanks for working on this! I tried it out a bit, and it seems to sometimes set `target_clk_divider` to zero, causing underflow and very long delays. This would be on platforms that set `BITBANG_CALIBRATED_FREQS`. On the other platforms, there are added checks that prevent that. At least the clock speeds seem more consistent across different routines. There are lots of remaining oddities about the timing that I see on the logic analyzer, but I'm still investigating those.
tlyu commented 2024年01月15日 04:17:14 +01:00 (Migrated from github.com)
Copy link

The main improvement is making the parity read/write functions have a consistent pulse width compared to the non-parity ones, at least in the case that does delays.

For the non-delay case, there seems to be increased asymmetry in the clock waveform, possibly due to replacing the NOP instructions with barriers. Some of these barriers are redundant, because the GPIO accesses are already volatile.

Also, I only have a 24MHz logic analyzer, so my ability to analyze differences in the no-delay case are going to be confounded by inadequate sample rate.

The main improvement is making the parity read/write functions have a consistent pulse width compared to the non-parity ones, at least in the case that does delays. For the non-delay case, there seems to be increased asymmetry in the clock waveform, possibly due to replacing the NOP instructions with barriers. Some of these barriers are redundant, because the GPIO accesses are already volatile. Also, I only have a 24MHz logic analyzer, so my ability to analyze differences in the no-delay case are going to be confounded by inadequate sample rate.
This pull request has changes conflicting with the target branch.
  • src/platforms/common/jtagtap.c
  • src/platforms/common/stm32/gpio.h
  • src/platforms/common/stm32/timing_stm32.c
  • src/platforms/common/swdptap.c
View command line instructions

Manual merge helper

Use this merge commit message when completing the merge manually.

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin ALTracer/fix/tap-timing:ALTracer/fix/tap-timing
git switch ALTracer/fix/tap-timing
Sign in to join this conversation.
No reviewers
Labels
Clear labels
BMD App
Black Magic Debug App (aka. PC hosted) (not firmware)
BMP Firmware
Black Magic Probe Firmware (not PC hosted software)
Bug
Confirmed bug
Build system
Build system
Can't reproduce
Maintainers can't reproduce this problem
CI
Continuous Integration System
Contribution wanted
User contributions welcome
Documentation
Project documentation
Draft
Work in progress draft
Duplicate
This issue or pull request already exists
Enhancement
General project improvement
Feedback wanted
Requires additional submitter feedback
Foreign Host Board
Non Native hardware to runing Black Magic firmware on
GDB
Issue/PR related to GDB
Good first issue
Good for newcommers
HwIssue Mitigation
Solving or mitigating a Hardware issue in Software
Information Needed
Maintainers need more information
NativeHardware
Official Black Magic Debug Hardware
New Host Board
New hardware to run Black Magic firmware on
New Target
New debug target
Off Topic
Something that does not involve the project in any way
Potential Bug
A potential, unconfirmed or very special circumstance bug
Regression
Bug caused by a regression
User Interest Needed
More user interest required before consideration
User Testing Needed
Looking for user testing reports
Won't fix
Outside of the project scope or works as intended
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
blackmagic-debug/blackmagic!1688
Reference in a new issue
blackmagic-debug/blackmagic
No description provided.
Delete branch "ALTracer/fix/tap-timing"

Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?