Ви не увійшли.
Коли компілятор зберігає змінну в регістрі, фрагмент програми працює в рази швидше. Але він може використовувати або не використовувати регістр за власним розсудом. Чи відомі комусь ВЛАСНОРУЧ ПЕРЕВІРЕНІ засоби змусити компілятор використовувати для змінної регістр. Ключове слово "register" не працює, принаймні у мене.
Неактивний
Я так підозрюю, що змінна повинна влазити в регістр.
Це компіляторо-залежна магія.
The register keyword is not a guarantee that the variable will be placed in a register.
Якщо компілятор вирішить що використати регістр буде прикольно - розмістить у регістрі. Можна спробувати вимкнути оптимізацію.
Якщо треба рахувати такти - краще на асемблері.
Чи відомі комусь ВЛАСНОРУЧ ПЕРЕВІРЕНІ засоби змусити компілятор використовувати для змінної регістр.
Стандартних таких засобів у мовах C та C++ немає.
Навіщо це вам потрібно? У більшості випадків (але не завжди) компілятор знає краще за програміста, де розміщувати змінну. Краще напишіть, яку саме проблему намагаєтесь вирішити використанням регістру для змінної.
Якщо таки потрібно, є власноруч перевірений GCC Inline Assembly.
Ключове слово "register" не працює, принаймні у мене.
register - це лише підказка компілятору, причому давно застаріла (deprecated).
Вимкнути оптимізацію - цікава ідея. Куди треба лізти для цього
Не треба. Примусове вимкнення оптимізації в сучасних компіляторах не має практичного сенсу. До того ж, це скоріш змусить НЕ використовувати регістр, ніж навпаки.
Неактивний
В avr-gcc можна об'явити глобальну змінну:
register uint8_t myregvar asm("r16");
вона гарантовано буде в r16, але код на C не буде з нею працювати оптимально.
На asm (або вставками на asm) з нею можна працювати як завгодно оптимально і одночасно мати доступ з C, це зручно, коли частина проекту на asm, а частина на C.
upd:
якщо потрібна двобайтова змінна, то:
register uint16_t myregvar asm("r16");
в коді на asm r16 буде молодшим, r17 - старшим
Остання редакція Honey (2025-08-20 20:56:53)
Неактивний
Лет десять назад обратил внимание, что CodeVisionAVR по умолчанию начинает размещение переменных в регистрах (R0-R16), потом уже в памяти. В моем любимом IARе тоже надо явно указывать в программе как описал Honey для avr-gcc.
Неактивний
Навіщо це вам потрібно?
Формую відеосигнал зсувом байтової змінної. Якщо змінна в регістрі, то через однобітовий порт виводжу послідовно 8 бітів за 0,5 мікросекунди (сам у шоці). Якщо змінна не в регістрі - 1 біт за той же час. Різниця катастрофічна
Остання редакція MikeM (2025-08-20 22:20:31)
Неактивний
В avr-gcc можна об'явити глобальну змінну:
register uint8_t myregvar asm("r16");
Це не специфічно для avr-gcc, для інших платформ теж так можна.
вона гарантовано буде в r16, але код на C не буде з нею працювати оптимально.
Якщо точніше, гарантованим буде сайд-ефект у вигляді доступу до регістру при доступі до змінної. Саме значення може зберігатись в іншому регістрі, даючи деоптимізацію:
register uint8_t x asm("r16");
void foo(void)
{
for (x = 0; x < 100; x++)
GPIOR0 = x;
}
foo:
.L__stack_usage = 0
ldi r24,0
.L2:
mov r16,r24
cpi r24,lo8(100)
brlo .L3
ret
.L3:
out 0x1e,r24
subi r24,lo8(-(1))
rjmp .L2
https://godbolt.org/z/n4Kx4frGe
А якщо раптом помилково використати call-clobbered register і не побачити попередження від компілятора, то ловити баг можна буде дуже довго
Неактивний
Формую відеосигнал зсувом байтової змінної. Якщо змінна в регістрі, то через однобітовий порт виводжу послідовно 8 бітів за 0,5 мікросекунди (сам у шоці). Якщо змінна не в регістрі - 1 біт за той же час. Різниця катастрофічна
Для такої задачі inline assembler - саме воно. Не обовʼязково inline, можна і в окремому source файлі.
Неактивний
Формую відеосигнал зсувом байтової змінної.
Весь фреймбуфер все одно в 1 байт не влізе.Так то через SPI теж можна 1 байт дуже швидко вигрузити.
Так то через SPI теж можна 1 байт дуже швидко вигрузити.
Більше того, поки один вигружається, можна вже підготувати наступний. Але з атмеговим SPI-контролером "розриви" все одно будуть, бо регістр даних не буферизований. А якщо використати USART в режимі SPI, то можна практично без розривів.
Остання редакція dimich (2025-08-20 22:47:01)
Неактивний
А чому б не використати якийсь штатний регістр, що не використовується за призначенням (напр. OCRxA/B якогось таймера)?
А чому б не використати якийсь штатний регістр, що не використовується за призначенням (напр. OCRxA/B якогось таймера)?
Для чого, для оптимізації? Не плутайте регістри процесора з регістрами ввода-вивода. AVR не вміє бітові зсуви чи іншу арифметику над регістрами ввода-вивода, тільки set/clear bit.
А для "загального використання" є три I/O регістра GPIOR0-GPIOR2. Їх зручно використовувати для бітових флагів, що виставляються в обробниках переривань.
Неактивний
Звичайнісінький 16 МГц UNO. Я ж казав "Сам у шоці"
Тобто 1 біт за 1 такт на atmega328p? Щось тут не те.
(Я маю на увазі довільні дані, а не фіксований патерн)
Остання редакція dimich (2025-08-20 23:46:16)
Неактивний
Саме так. Я не розумію, як таке може бути, але засоби об'єктивного контролю підтверджують.
А можете показати код (тільки той, що виводить байт) та опції компіляції? Або дизасембльований код. Бо чудес не буває.
Неактивний
не знаю, як вставити фото екрана осциллографа
Внизу під вікном редагування "Завантаження". Там "Upload a file". Потім відкриваєте завантажений файл, копіюєте його адресу і вставляєте в текст.
Неактивний
shifter = figures[codePagePtr];
PORTB = shifter;
shifter = shifter >> 1;
PORTB = shifter;
shifter = shifter >> 1;
PORTB = shifter;
shifter = shifter >> 1;
PORTB = shifter;
shifter = shifter >> 1;
PORTB = shifter;
shifter = shifter >> 1;
PORTB = shifter;
shifter = shifter >> 1;
PORTB = shifter;
shifter = shifter >> 1;
PORTB = shifter;
Неактивний