- 1
- 2
- 3
- 4
UCSR0A |= TXC0_MASK;
UDR0 = value;
while ((UCSR0A & TXC0_MASK) == 0)
;
Нашли или выдавили из себя код, который нельзя назвать нормальным, на который без улыбки не взглянешь? Не торопитесь его удалять или рефакторить, — запостите его на говнокод.ру, посмеёмся вместе!
0
UCSR0A |= TXC0_MASK;
UDR0 = value;
while ((UCSR0A & TXC0_MASK) == 0)
;
The TXCn flag ... can be cleared by writing a one to its location.
Cleared by writing one, Carl.
0 - номер трансивера, А - ид. регистра (еще есть B, C...)
Тута мы сбрасываем все взведённыйэ в регистре биты? Я правильно понял?
Здеся ждём пока нужные биты сбросятся? А "0)" это смайлик цыклопа?
Пустой апиратор, поставлен на отдельной строччке для улучшения читаемости, чтобы сразу было видно что тело суслика пустое. Если я правильно помню, это было ещё в K&R. Я предпочитаю засовывать тело суслика в вагину {}, можно ещё так {;}.
Нормальная практика для железок. Позволяет не проёбывать события т.к. при очистке записью нуля возможна гонка.
Никак. Он взводится только со стороны железа и сбрасывается только со стороны софта.
reg &= ~mask это read, and, write
reg = mask при стирании единичками это просто write.
Ты описал обычный регистр, похожий на привычную программистам переменную. А схема с "clear by writing one" работает так:
1) считать байт в регистр CPU
2) обработать события согласно битам
3) сделать write с единичками в тех битах, которые нужно стереть, and (not mask) произойдёт внутри железки
И мы не можем случайно стереть биты, которые ещё не видели.
Да, 0 - не трогать, 1 - стереть.
> железке будет сложнее
Программисту будет сложнее :) Тут ты можешь прочитать текущее состояние и просто хуйнуть его обратно чтобы стереть обработанные биты. А с "ноль - стереть, один - не трогать" тебе придётся инвертировать маску.
Разве что, наверное, это предусмотрено, и флаги с такой функциональностью не должны встречаться в одном регистре...
Ну да.
Можно по биту на регистр (но не особо удобно проверять если их много).
Можно level trigger в духе "буфер пуст", который для софта r/o.
Можно сбрасывать записью единичек.
Можно сбрасывать сразу при чтении.
Но сброс единичками - самый удобный способ, на самом деле. Прочитал регистр, обработал интересные тебе события, выбил их единичками. Остальные можно оставить на потом.
А ещё есть такая хуйня как метастабильность. Всё твоё железо держится на теории вероятности. Всегда есть шанс, что проснётся ктулху аппаратный UB. Тлен и безысходность.
Вокруг каждого переключения триггера есть окно (t - setup time, t + hold time) в течении которого входной сигнал не должен меняться. Если поменяется - выход триггера может успокоиться намного позже обычного, следующие элементы схемы из-за этого тоже могут не уложиться в тайминги и всё рассыпается как карточный домик.
Жопа в том, что любой внешний сигнал, не сихронизированный с нашей схемой, рано или поздно переключится как раз посреди этого окна.
Есть воркэраунды, позволяющие загнать эту проблему под ковёр (до раза за миллиарды лет, к примеру). Но совсем убрать её нельзя.
Due to this behavior of the receive buffer, do not use read modify write instructions (SBI and CBI) on this location.
Do not use read-modify-write instructions (SBI and CBI) to set or clear the MPCM bit.
Т.е. никакой магии там нет.
А... вот оно как.
Ну что ты такое несешь? Не, ну если у тебя ассемблер такой кривой, то такая проблема может быть.
Если у тебя есть машинная инструкция, которая может за раз занулить вот тот бит в том 8-битном байте без его предварительного чтения, то проблемы никакой нет. Побитовым "И" можно. Например, есть у нас регистр в котором битики
Никакого предварительного чтения тут не надо
https://ru.wikipedia.org/wiki/Битовые_операции#Побитовое_«И»_(AND)
> Другими словами, если оба соответствующих бита операндов равны 1, результирующий двоичный разряд равен 1; если же хотя бы один бит из пары равен 0, результирующий двоичный разряд равен 0.
А если у процессора нет инструкции, чтобы атомарно пихнуть единичку вот в тот бит в том 8-битном байте, то и стирание через единицу тут может обосраться. Так что тогда надо будет еще всякие прерывания запрещать перед изменением битиков.
"Зануление" одного бита делается побитовым "И" с маской, где везде единички кроме одного места, которое зануляем.
"Заединичивание" одного бита делается побитовым "ИЛИ" с маской, где всего одна единичка в том месте, которое нам нужно "заединичить". С чего вдруг побитовое "И" требует 2 отдельных транзакции на шине, а побитовое "ИЛИ" не требует
"ИЛИ" там нахуй не нужен (ОП юзает его из-за того что control и status смешали в кучу и ему не хочется вспоминать что у него было в control части). Для clear-by-writing-one нужна только запись (reg = mask). А дальше железка внутри себя уже сделает and. Т.е. мы не меняем содержимое регистра, мы отправляем железке команду на сброс нужных битов.
> машинная инструкция, которая может за раз занулить вот тот бит
> прерывания запрещать
Как тебе это поможет против включения бита со стороны железки. В теории, конечно, можно было бы её научить не менять свои регистры пока ты держишь lock на шине... Но это на порядок сложнее тупого clear-by-writing-one.
В теории можно было б просто писать/читать зарезервированные порты и не ебать мозги с этим memory-mapped peripherals
Вот эта хуита
Ну да, отдельные порты психологически легче воспринимаются.
Но как они помогут с синхронизацией доставки ивентов от железки в твой код?
В чем именно MMIO лучше с т.з. синхронизации?
Так что сначала ждём твоего объяснения чем с т.з. синхронизации удобнее отдельные порты :)
(на самом деле нет, т.к. по стандарту самой сишки это UB но мысль думаю ясна)
Ну а нафиг ты тогда этот холивар MMIO vs I/O сюда принёс?
У MMIO всего один плюс - не надо отдельные инструкции городить.
А первый убогий DMA контроллер когда завезли?
Ну одновременно только кроссбар типа bus matrix'а на STM'ках позволяет...
Или там проц тупо стоял и ждал пока DMA хуярит и ему шина совсем не доставалась?
Ну. По сути просто дополнительный бит на шине в поле адреса.
Однако я тупанул и не учёл, что при memory-mapped I/O, некий "верховный" дешифратор (возможно, внутри самого CPU) мог бы выставлять подобие IORQ, и каждой железке тогда не пришлось бы проверять весь адрес целиком.
Кстати, кажется, ZX Spectrum при вводе-выводе несколько младших битов адреса вообще использовал по одной штуке на отдельный аппаратный запрос.
Чтобы в адресное пространство процессора вкроить как можно больше RAM, ROM, и достаточно MMIO.
> предланагаешь
Мысль была о том, как проверка пучка верхних дорожек адреса сводится к проверке одной единственной IORQ. Для оригинального IBM PC (8088, 20 линий адреса), чтобы выхватить 8 KB под BIOS вверху 1 MB (FE000-FFFFF), надо проверить 7 верхних дорожек, верно? А в случае IBM PC AT (80286, 24 линии), чтобы выделить один адрес для MMIO с неким контроллером в слоте ISA, - все 24?
Я просто предположил, на чём могли бы экономить. А экономили, если с сегодняшней точки зрения, то вообще на спичках. IBM вот сделали IRQ по положительному перепаду, а вентиль A20 в контроллер клавиатуры уместили.
Да. При этом практически ведь требуется лишь малая доля из всех возможных 2^N адресов.
Я хотел было разобраться и отреферировать про PMIO Спектрума, но сходу не могу найти ничего кроме общих слов из мануала и вот этой таблицы. https://velesoft.speccy.cz/zxporty-cz.htm . Судя по ней, устройства ооочень "ленятся" проверять адресные линии (таким образом дичайше сокращая бесконфликтную часть пространства).
> плевок в вечность
Ко мне эта книга относительно недавно попала, и как раз про плевок тоже запомнилось. Там ещё говорилось, что по отрицательному перепаду было бы меньше ложных прерываний из-за помех (spurious interrupts).
Перевёл его тебе в тактильную область. Проверь.
⠀⢀⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⡆
⠀⡾⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣾⠋⠀
⢸⠇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⠟⠁⠀⠀
⢸⡆⠀⠀⠀⠀⠀⠀⠀⢀⣀⣴⡿⠁⠀⠀⠀⠀
⠀⠻⣄⠀⠀⠀⠀⠀⣠⣿⡿⠋⠀⠀⠀⠀⠀⠀
⠀⠀⠈⠛⠲⠶⠖⢛⡽⠋⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⣴⠏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⣠⠞⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⢀⡾⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠠⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
> Очень жаль что Гук больше не пишет
Да, я б тоже почитал.
Литературу по PC, конечно, советуй, если не трудно. Иногда что-то берусь читать, но очень нерегулярно.
У меня есть железный 286, который лелею и включаю при обострениях ностальгии. Иногда любопытство доводит до ассемблера, но о решении насущных низкоуровневых задач пока и речи нет. Последнее, с чем обломался, - освободить в MS-DOS немного conventional памяти. Кажется, нет у моего железа никаких средств, которые могли бы отобразить имеющуюся оперативку в верхних 384 КБ (чтоб выпихнуть часть драйверов в UMB). Похоже, остаётся лишь добыть, а лучше изготовить плату расширения с сотней КБ оперативки, которая заполнит окно. Но это неточно и "на вырост".
Вот этот цикл while(RNG_GetFlagStatus(RNG_FLAG_DRDY) == RESET) очевидно тупо читает в цикле фигню из MMIO и ждет когда там будет не RESET. С тем же успехом можно было б читать какой-нибудь порт в цикле пока там не выйдет требуемое значение
У тебя ALU стоит прямо в оперативке и каждой железке? Ну ок, тогда действительно не надо.
Надо просто с префиксом LOCK делать http://www.club155.ru/x86cmd/LOCK
В x86 даже есть особые инструкции BTR, BTS, так что OR и AND можно не использовать
Ну блин, lock же не отменяет джвух обращений на шине... Он тупо не даёт захватить шину другим bus master'ам между ними.
Плюс, как я писал выше, придётся ещё и саму железку учить понимать lock чтобы она не меняла свои регистры под лочкой.
З.Ы. Причём на STM'ках такая пара доступна через один регистр - 0x0001000 выключает первый бит, 0x00000001 включает его, 0x00020001 атомарно выключает второй и включает первый и т.п.
- А если 0x00010001 записать, что будет?
- Что будет, что будет... на жопу упаду! (с)
У мужчины, если он здоров, из члена идёт только моча и сперма. (ну ещё смазка, не суть.). У здоровой женщины из пизды регулярно идёт слизь, моча, кровь - ну как, аппетит разыгрался? Благодаря тому, что у мужчины половые органы - наружние, поддерживать их гигиену куда проще, чем женщинам.
@Благодаря тому, что у мужчины половые органы - наружние, поддерживать их гигиену куда проще, чем женщинам.
Попробуй не смыть ее вовремя - аромат будет сногсшибательный..
Но в целом согласен.
"Ы".
- консольное приложение про Сейлор Мун