2013-06-24 3 views
0

Я побеседовал с учебниками по выпечке в Кембридже (базовая разработка ОС с небольшими демонстрациями для малины pi). Только я написал код в C вместо этого. У меня есть настройка среды разработки, и я могу успешно запустить свой код с отключенной настройкой GCC, но не включен.Оптимизированная память, оптимизированная для IO и GCC

Проблема возникает с моим кодом, который использует IO с отображением памяти (если я скомпилировал все остальное, кроме следующего файла с оптимизацией, он работает). Поначалу я думал, что мои указатели не были объявлены как изменчивые, поэтому компилятор оптимизировал фактическую запись в память и вместо этого использовал регистры. Но даже когда я объявляю их неустойчивыми, проблема сохраняется.

Вот как я делаю запись в память:

#define UART0_CR ((volatile uint32_t *) (UART0_BASE + 0x30)) 
... 
*UART_CR = 0; 

указатели летучего типа, так что я не могу понять, почему GCC решит не делать фактическую запись. Есть ли что-то еще, что мне нужно для наблюдения? Я не понимаю, как использовать летучие?

Полный рабочий файл (с оптимизацией выключения в любом случае):

#include <stdint.h> 
#include <uart.h> 

#define GPIO_BASE 0x20200000 
#define GPPUD  ((volatile uint32_t *) (GPIO_BASE + 0x94)) 
#define GPPUDCLK0 ((volatile uint32_t *) (GPIO_BASE + 0x98)) 

#define UART0_BASE  0x20201000 
#define UART0_DR  ((volatile uint32_t *) (UART0_BASE + 0x00)) 
#define UART0_FR  ((volatile uint32_t *) (UART0_BASE + 0x18)) 
#define UART0_IBRD  ((volatile uint32_t *) (UART0_BASE + 0x24)) 
#define UART0_FBRD  ((volatile uint32_t *) (UART0_BASE + 0x28)) 
#define UART0_LCRH  ((volatile uint32_t *) (UART0_BASE + 0x2C)) 
#define UART0_CR  ((volatile uint32_t *) (UART0_BASE + 0x30)) 
#define UART0_IMSC  ((volatile uint32_t *) (UART0_BASE + 0x38)) 
#define UART0_ICR  ((volatile uint32_t *) (UART0_BASE + 0x44)) 

static void delay(int32_t count) { 
    asm volatile("__delay%=: subs %[count], %[count], #1; bne __delay%=\n" 
       : 
       : [count]"r"(count) 
       : "cc" 
    ); 
} 

void uart_init() {  
    *UART0_CR = 0; // Disable UART0.  
    *GPPUD = 0;  // Disable pull up/down for all GPIO pins & delay for 150 cycles. 
    delay(150); 
    *GPPUDCLK0 = (1 << 14) | (1 << 15); // Disable pull up/down for pin 14,15 & delay for 150 cycles. 
    delay(150); 
    *GPPUDCLK0 = 0; // Write 0 to GPPUDCLK0 to make it take effect.  
    *UART0_ICR = 0x7FF; // Clear pending interrupts. 
    *UART0_IBRD = 1; //Set rate 
    *UART0_FBRD = 40;  
    *UART0_LCRH = (1 << 4) | (1 << 5) | (1 << 6); // Enable FIFO & 8 bit data transmissio (1 stop bit, no parity).  
    *UART0_IMSC = (1 << 1) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10); // Mask all interrupts. 
    *UART0_CR = (1 << 0) | (1 << 8) | (1 << 9); // Enable UART0, receive & transfer part of UART. 
} 

void uart_putc(uint8_t byte) {  
    while (1) { // wait for UART to become ready to transmit  
     if (!(*UART0_FR & (1 << 5))) break; 
    } 
    *UART0_DR = byte; // Transmit 
} 

void uart_puts(const char *str) { 
    while (*str) { 
     uart_putc(*str++); 
    } 
} 

EDIT:

Посмотрел, как просматривать сборки, очень полезно, большое спасибо. Если я беру первые 2 выписывает из УАПП я инициализации (до первого вызова задержки) я получаю:

Неоптимизированный:

uart_init: 
    @ args = 0, pretend = 0, frame = 0 
    @ frame_needed = 1, uses_anonymous_args = 0 
    stmfd sp!, {fp, lr} 
    add fp, sp, #4 
    ldr r3, .L3 
    mov r2, #0 
    str r2, [r3, #0] 
    ldr r3, .L3+4 
    mov r2, #0 
    str r2, [r3, #0] 

Оптимизированный:

uart_init: 
    @ args = 0, pretend = 0, frame = 0 
    @ frame_needed = 0, uses_anonymous_args = 0 
    @ link register save eliminated. 
    ldr r3, .L2 
    ldr r2, .L2+4 
    mov r1, #0 
    str r1, [r3, #48] 
    str r1, [r2, #148] 

Единственное различие, кажется, что для неоптимизированного значения он не добавляет смещения меток .L2 и .L2 + 4, которые оптимизирован. Если указатели на этих ярлыках уже не подготовлены к расчетам на них.

У меня есть раздвоенный qemu (qemu-rpi), модифицированный для поддержки малины pi, поэтому я попытаюсь проверить, какие значения загружены в регистры r3 и r2, чтобы увидеть, являются ли они правильными указателями до того, как магазин произойдет и затем я иду проверить, не зацикливается ли putc на передаче, используя точки останова. Не очень разбираюсь в моей среде, но это может занять некоторое время!

+0

Какие у вас есть доказательства того, что фактическая запись не выполнена? Вы посмотрели на сборку? – ouah

+0

Код выглядит хорошо при первом румянце.Что происходит, когда оно оптимизировано? Цикл uart_putc() навсегда ожидает бит 5? – torek

+0

I abstract my Mem/IO читает и пишет по этой и другим причинам, github.com/dwelch67/raspberrypi. Вы можете играть в игры до тех пор, пока не будете синими в лицо с атрибутами, специфичными для компилятора, и в конечном итоге все равно столкнуться с проблемой оптимизации. Аппаратный ввод-вывод в моем случае находится в asm, но в основном в отдельном файле, а не в части оптимизации. –

ответ

1

Использование оптимизатора вместе с кодом, связанным с оборудованием, может привести к причудливому поведению.

Попробуйте использовать атрибут «» ((noinline)) »перед функциями, которые общаются с вашим оборудованием. Я также рекомендовал бы поместить весь код, который говорит с оборудованием, в свой собственный файл и отключить оптимизацию. Оптимизатор может переупорядочить или вставить эти элементы в очередь.

+0

Хорошо, это исправляет проблему. Я попытался использовать этот атрибут и обнаружил, что это требуется только для функции встроенной задержки. Который я предполагаю, нарушает задержку и заставляет последовательное устройство получать команды слишком быстро. Почему это? Возможно ли, что оптимизатор вставляет код задержки в методы, забывая, что он изменчив и оптимизирует задержку? – Callum

+0

Thankyou так много. Я думаю, что собираюсь записать свои MMIO в функцию сборки, которую я позвоню из C, чтобы избежать подобных проблем в будущем! – Callum

+0

Я не помню конкретно все то, что оптимизатор может сделать с вашим кодом. Но это замечательно с его переупорядочиванием, удалением и вложением выбора. –

0

Я пытаюсь сделать то же самое , но вместо определения, я просто назначая так:

volatile const int *Register = (volatile const int *)0xFFFEF000; 

Затем вы можете отправить значения непосредственно в регистры по имени:

Register = 0xFFFFFFFF;