问题描述
我有以下5行代码,并希望这些行以O2或O3的确切顺序执行:
PORT->Group[GPIO_PORTB].OUTCLR.reg = (volatile uint32_t) 1 << 9;
TC3->COUNT16.COUNT.reg = (volatile uint16_t) 0;
TC3->COUNT16.CC[0].reg = (volatile uint16_t) vusb_driver->in_data->bitlength;
SERCOM0->SPI.DATA.reg = (volatile uint32_t) 0x54;
DMAC->Channel[USB_SEND_SD_DMA_CH].CHCTRLA.reg = (volatile uint8_t) DMAC_CHCTRLA_ENABLE;
如果我使用O2或O3进行优化,则代码将在264行中断,因为该行必须在265行之前执行:
261: PORT->Group[GPIO_PORTB].OUTCLR.reg = (volatile uint32_t) 1 << 9;
200001EE ldr r1,[pc,#84]
263: TC3->COUNT16.CC[0].reg = (volatile uint16_t) vusb_driver->in_data->bitlength;
200001F0 ldr r5,#84]
264: SERCOM0->SPI.DATA.reg = (volatile uint32_t) 0x54;
200001F2 ldr r4,#88]
265: DMAC->Channel[USB_SEND_SD_DMA_CH].CHCTRLA.reg = (volatile uint8_t) DMAC_CHCTRLA_ENABLE;
200001F4 ldr r0,#88]
261: PORT->Group[GPIO_PORTB].OUTCLR.reg = (volatile uint32_t) 1 << 9;
200001F6 mov.w r6,#512
200001FA str.w r6,[r1,#148]
262: TC3->COUNT16.COUNT.reg = (volatile uint16_t) 0;
200001FE strh r2,[r3,#20]
263: TC3->COUNT16.CC[0].reg = (volatile uint16_t) vusb_driver->in_data->bitlength;
20000200 ldr r2,[r5]
20000202 ldr r2,[r2,#20]
20000204 ldrh.w r2,#72]
20000208 strh r2,#28]
264: SERCOM0->SPI.DATA.reg = (volatile uint32_t) 0x54;
2000020A movs r5,#84
265: DMAC->Channel[USB_SEND_SD_DMA_CH].CHCTRLA.reg = (volatile uint8_t) DMAC_CHCTRLA_ENABLE;
2000020C movs r2,#2
264: SERCOM0->SPI.DATA.reg = (volatile uint32_t) 0x54;
2000020E str r5,[r4,#40]
解决方法
您对volatile
的使用是不正确的,您应将目标对象定义为volatile
,以确保按照程序顺序正确写入目标对象。
在正常情况下,如果执行的效果相同(这是"as-if rule"),则允许编译器对指令重新排序。因此,您必须执行以下操作之一:
- 表明指令有不同的作用(例如,使相关的
.reg
变量易变;或通过指针的别名等) - 使用某种特定于编译器的指令来控制其行为。
- 不进行编译,即以不同的方式生成您的机器代码。
具体来说,如果您选择第一个选项,则必须向编译器或您自己解释为什么?
第[264]行必须在第265行之前执行
在什么意义上“必须”在265之前执行?谁会注意到?您可以使用该问题的具体答案来强制执行所需的执行顺序。