Skip to content

Commit b02c5b2

Browse files
committed
perf(support_rp2040): optimize the bitfield conversion loop
I just remembered that this target lacks the `clz` instruction. Also, `UsbBus::ep_in_ready` is `VolatileCell`, so the compiler won't optimize the accesses to this field.
1 parent 559b9fd commit b02c5b2

File tree

1 file changed

+41
-26
lines changed
  • src/r3_support_rp2040/src

1 file changed

+41
-26
lines changed

src/r3_support_rp2040/src/usb.rs

Lines changed: 41 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -407,41 +407,56 @@ impl usb_device::bus::UsbBus for UsbBus {
407407
}
408408

409409
if status.buff_status().bit() {
410-
let mut buf_status = self.usbctrl_regs.buff_status.read().bits();
411-
let mut buf_status_cleared_bits = 0;
412-
let mut i = 31;
413-
414-
while let Some(i_r) = {
415-
let i_r = buf_status.leading_zeros();
416-
(i_r < 32).then(|| i_r)
417-
} {
418-
i -= i_r;
419-
buf_status <<= i_r;
420-
debug_assert_ne!(buf_status & 0x80000000, 0);
421-
422-
if i % 2 == 0 {
423-
// IN EP (i / 2)
424-
ep_in_complete |= 1 << (i / 2);
425-
426-
// Clear the status bit
427-
buf_status_cleared_bits |= 1 << i;
428-
429-
self.ep_in_ready
430-
.set(self.ep_in_ready.get() | (1u16 << (i / 2)));
431-
} else {
432-
// OUT endpoint ((i - 1) / 2)
433-
ep_out |= 1 << (i / 2);
410+
let buf_status = self.usbctrl_regs.buff_status.read().bits();
411+
412+
// IN EP (i / 2), i = 0, 2, 4, ..., 30
413+
{
414+
let mut buf_status = buf_status;
415+
let mut b2 = 1; // 1 << (i / 2)
416+
loop {
417+
if buf_status == 0 {
418+
break;
419+
}
420+
421+
if (buf_status & 1) != 0 {
422+
// ep_in_complete |= 1 << (i / 2)
423+
ep_in_complete |= b2;
424+
}
425+
426+
// i += 2;
427+
buf_status >>= 2;
428+
b2 <<= 1;
434429
}
430+
self.ep_in_ready
431+
.set(self.ep_in_ready.get() | ep_in_complete);
432+
}
435433

436-
i -= 1;
437-
buf_status <<= 1;
434+
// OUT EP ((i - 1) / 2), i = 1, 3, 5, ..., 31
435+
{
436+
let mut buf_status = buf_status >> 1;
437+
let mut b2 = 1; // 1 << ((i - 1) / 2)
438+
loop {
439+
if buf_status == 0 {
440+
break;
441+
}
442+
443+
if (buf_status & 1) != 0 {
444+
// ep_out |= 1 << ((i - 1) / 2)
445+
ep_out |= b2;
446+
}
447+
448+
// i += 2;
449+
buf_status >>= 2;
450+
b2 <<= 1;
451+
}
438452
}
439453

440454
// Clear the status bits for IN endpoints
441455
//
442456
// FIXME: `buff_status` is RO in SVD and the RP2040 manual, but the
443457
// example code does write it:
444458
// <https://github.com/raspberrypi/tinyusb/blob/e0aa405d19e35dbf58cf502b8106455c1a3c2a5c/src/portable/raspberrypi/rp2040/dcd_rp2040.c#L225>
459+
let buf_status_cleared_bits = buf_status & 0x55555555;
445460
unsafe {
446461
(&raw const self.usbctrl_regs.buff_status as *mut u32)
447462
.write_volatile(buf_status_cleared_bits);

0 commit comments

Comments
 (0)