Size: a a a

Maxwell's Demons

2021 February 14

RS

Roman Storozhenko in Maxwell's Demons
Kirill
Всё таки подход в libopencm3 в виде "один бит == функция" немного провальный и не на всю периферию можно натянуть.

Решил я тут запилить sdio для stm32 в libopencm3

Сделал всё по её спорным канонам, запись в регистр разбита на OVER_9999 отдельных функций. Типа:
...
void sdio_set_cpsm_long_response_mode(uint32_t sdio) {
 SDIO_CMD(sdio) |= SDIO_CMD_LONGRESP;
}
void sdio_set_cpsm_short_response_mode(uint32_t sdio) {
 SDIO_CMD(sdio) &= ~SDIO_CMD_LONGRESP;
}
void sdio_set_command_index(uint32_t sdio, uint8_t index) {
 SDIO_CMD(sdio) = (SDIO_CMD(sdio) & ~(SDIO_CMD_CMDINDEX_MASK << SDIO_CMD_CMDINDEX_SHIFT)) |
   (index << SDIO_CMD_CMDINDEX_SHIFT);
}
...


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

Чужие примеры на регистрах работают идеально. А этот на функциях - никак. При том, что делаю тоже самое.

А потом заметил одну важную деталь. В коде с регистрами они записываются сразу целиком:
SDIO_CMD(sdio) = SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP | cmd;


А у меня каждый бит записывается отдельно, с чтением старых битов (как по канонам libopencm3):
SDIO_CMD(sdio) &= ~SDIO_CMD_CPSMEN;
...
SDIO_CMD(sdio) |= index;
SDIO_CMD(sdio) |= SDIO_CMD_WAITRESP;
SDIO_CMD(sdio) |= SDIO_CMD_CPSMEN;


И тут я как понял. В этой сраной AMBA PL180 регистры тормозят!
Ты в него записываешь бит, тут же читаешь - а его нет. Регистр ещё какое-то время возвращает своё старое значение.

Добавил delay после каждой функции - заработало.

У меня прям подгорело с этого. Написал тестер тормозящих регистров: https://pastebin.com/Z5xWECbt
Практически все тормозят: https://pastebin.com/4WAZ0C6g

Ну вот что это за пиздец?

Кажется теперь я знаю, почему так никто и не запилил sdio в libopencm3.
Это просто невозможно без нарушения принятых в ней подходов.
Там того sdio пару экранов. Можно и самому по RM сделать
источник

RS

Roman Storozhenko in Maxwell's Demons
Kirill
Всё таки подход в libopencm3 в виде "один бит == функция" немного провальный и не на всю периферию можно натянуть.

Решил я тут запилить sdio для stm32 в libopencm3

Сделал всё по её спорным канонам, запись в регистр разбита на OVER_9999 отдельных функций. Типа:
...
void sdio_set_cpsm_long_response_mode(uint32_t sdio) {
 SDIO_CMD(sdio) |= SDIO_CMD_LONGRESP;
}
void sdio_set_cpsm_short_response_mode(uint32_t sdio) {
 SDIO_CMD(sdio) &= ~SDIO_CMD_LONGRESP;
}
void sdio_set_command_index(uint32_t sdio, uint8_t index) {
 SDIO_CMD(sdio) = (SDIO_CMD(sdio) & ~(SDIO_CMD_CMDINDEX_MASK << SDIO_CMD_CMDINDEX_SHIFT)) |
   (index << SDIO_CMD_CMDINDEX_SHIFT);
}
...


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

Чужие примеры на регистрах работают идеально. А этот на функциях - никак. При том, что делаю тоже самое.

А потом заметил одну важную деталь. В коде с регистрами они записываются сразу целиком:
SDIO_CMD(sdio) = SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP | cmd;


А у меня каждый бит записывается отдельно, с чтением старых битов (как по канонам libopencm3):
SDIO_CMD(sdio) &= ~SDIO_CMD_CPSMEN;
...
SDIO_CMD(sdio) |= index;
SDIO_CMD(sdio) |= SDIO_CMD_WAITRESP;
SDIO_CMD(sdio) |= SDIO_CMD_CPSMEN;


И тут я как понял. В этой сраной AMBA PL180 регистры тормозят!
Ты в него записываешь бит, тут же читаешь - а его нет. Регистр ещё какое-то время возвращает своё старое значение.

Добавил delay после каждой функции - заработало.

У меня прям подгорело с этого. Написал тестер тормозящих регистров: https://pastebin.com/Z5xWECbt
Практически все тормозят: https://pastebin.com/4WAZ0C6g

Ну вот что это за пиздец?

Кажется теперь я знаю, почему так никто и не запилил sdio в libopencm3.
Это просто невозможно без нарушения принятых в ней подходов.
То что тут же записанный бит читается не таким это проблемы кеширования и синхронизации.
Можешь поставить DSB, ISB инструкцию.
источник

K

Kirill in Maxwell's Demons
А разве это должно распостраняться на периферию?
источник

RS

Roman Storozhenko in Maxwell's Demons
Kirill
А разве это должно распостраняться на периферию?
Почему нет?
источник

K

Kirill in Maxwell's Demons
Лол, DSB и правда помог. Спасибо!
источник

GK

Grigorii Kuzmin in Maxwell's Demons
Roman Storozhenko
То что тут же записанный бит читается не таким это проблемы кеширования и синхронизации.
Можешь поставить DSB, ISB инструкцию.
странно, а volatile разве не говорит о том, что кешировать нельзя и надо напрямую читать/писать?
источник

GK

Grigorii Kuzmin in Maxwell's Demons
регистры периферии же все volatile
источник

GK

Grigorii Kuzmin in Maxwell's Demons
я думал компайлер вставляет эти барьеры памяти при работе с волатильными переменными
источник

RS

Roman Storozhenko in Maxwell's Demons
Grigorii Kuzmin
странно, а volatile разве не говорит о том, что кешировать нельзя и надо напрямую читать/писать?
Volatile запрещает делать перестановки последовательности и использовать регистровую копию (локальное кеширование).
источник

RS

Roman Storozhenko in Maxwell's Demons
На остальное не влияет
источник

GK

Grigorii Kuzmin in Maxwell's Demons
Roman Storozhenko
Volatile запрещает делать перестановки последовательности и использовать регистровую копию (локальное кеширование).
но компайлер ведь знает, что у конкретного ядра есть кэш данных
источник

GK

Grigorii Kuzmin in Maxwell's Demons
яснопонятно короче)
источник

RS

Roman Storozhenko in Maxwell's Demons
Что стандарт си или с++ говорит по этому поводу?
источник

GK

Grigorii Kuzmin in Maxwell's Demons
Roman Storozhenko
Volatile запрещает делать перестановки последовательности и использовать регистровую копию (локальное кеширование).
на уровне процессора тоже могут быть перестановки при выполнении кода, т.е. влияние volatile должно не только на софтварную часть распространяться
источник

GK

Grigorii Kuzmin in Maxwell's Demons
про стандарт не скажу, возможно, действительно для избегания проблем с кешированием/перестановкой инструкций на уровне проца надо ручками барьеры памяти вставлять
источник

RS

Roman Storozhenko in Maxwell's Demons
Ещё есть особенность записи во flash в МК с кеш.
Записываешь страницу, затем вторую и так далее. Потом проверяешь и обнаруживаешь что данные записаны через полуслово.
Решается DSB после каждой записи слова во flash.
источник

RS

Roman Storozhenko in Maxwell's Demons
Grigorii Kuzmin
на уровне процессора тоже могут быть перестановки при выполнении кода, т.е. влияние volatile должно не только на софтварную часть распространяться
На уровне ядра последовательность не нарушается
источник

GK

Grigorii Kuzmin in Maxwell's Demons
Roman Storozhenko
Ещё есть особенность записи во flash в МК с кеш.
Записываешь страницу, затем вторую и так далее. Потом проверяешь и обнаруживаешь что данные записаны через полуслово.
Решается DSB после каждой записи слова во flash.
вот это прикол
источник

GK

Grigorii Kuzmin in Maxwell's Demons
Roman Storozhenko
На уровне ядра последовательность не нарушается
спекулятивное выполнение конвейера
источник

RS

Roman Storozhenko in Maxwell's Demons
Grigorii Kuzmin
спекулятивное выполнение конвейера
Но последовательность то не нарушается?
источник