Про удаление лишнего припоя с ножек: тут уже рекомендовали оплётку, но есть ещё одна особенность: если лишнего припоя мало и вы не можете ткнуть в него паяльником или оплёткой — и, главное, он где‐то за ножками и паяльником с нормальной температурой не нагревается, иногда имеет смысл добавить больше припоя. Огромная капля удаляется оплёткой с ножек без проблем, мелкая капля едва касающаяся чего‐либо паяльником не удаляется без добавления припоя в принципе: либо вы поглощаете её лишним припоем, либо можно попробовать много флюса и фен. Нагревать паяльник выше той температуры, при которой вам комфортно паять ножки, для удаления мелкой капли не нужно. При использовании оплётки, если вы паяете на минимальной комфортной температуре, придётся добавить 20—30 ℃.
Я обычно паяю большим топориком (K) с 240 ℃ для микросхем с ножками, 250 ℃ для ёмкостей/… 0603—0805, подключающихся к огромным полигонам, 260—280 ℃ для танталовых конденсаторов и THD. Выше в специальных случаях. Если жало — не большой топорик, температура может потребоваться выше.
А относительно BGA: по‐моему вы ухудшили себе жизнь, не купив ИК станцию вместо столика с подогревом. У нас в компании BGA паяют без трафаретов и пасты: берём нормальный флюс (сейчас — Mechanic SD-360), мажем его очень тонким и ровным слоем по всем площадкам, ставим схему и греем ИК станцией. Работает как с золотым финишным покрытием (иммерсионное золото), так и с ПОС‐63 (или остатками шариков), но если ПОС‐63 появился после выпайки микросхемы, а не после завода, то его нужно аккуратно выровнять оплёткой (в плохих случаях: сначала паяльником смахнуть остатки шариков, а потом уже оплёткой), при этом не убрав этой оплёткой маску (что тем легче сделать, чем горячее паяльник) и не сорвав случайно площадки (что тем легче сделать, чем холоднее паяльник). Трафарет понадобится, если нужно будет перенакатывать шарики. Или если вы всё же решите поставить по одному 0402 конденсатору под каждый шарик питания и у вас есть ИК станция.
В качестве бюджетной ИК можно брать Puhui T-962, но её придётся доработать (у нас это запасная станция на случай поломки основной). Доработать — это обклеить термоскотчем, изменить прошивку, добавить дополнительный температурный сенсор.
Такие костыли я видел. Они хорошо заметны, и они точно не могут привести к идентичным $dir-fe (выводам git fast-export).
И в любом случае, напомню, что ветка началась с того, что я указал возможность сохранения информации о перемещениях в СКВ, хранящей слепки, и hg-git — это просто пример хранения этой информации в СКВ, хранящей слепки. Какими костылями он это делает неважно — это просто пример, что это сделать возможно, соответственно из «в гите как раз слепки хранятся» не может следовать, что гит «не умеет трекать перемещения» — он не умеет трекать перемещения, потому что его авторы решили не добавлять сохранение перемещений, а не потому что он хранит слепки.
Ваша ссылка относится к commit’ам, сделаным в git. У меня commit’ы, сделанные в mercurial, в которых уже есть информация о переименованиях и она должна быть частью commit’а и на стороне mercurial, и на стороне git, чтобы hg-git вообще работал: хэши commit’ов должны сохраняться при конвертации в любую сторону, чтобы можно было нормально работать, а не постоянно решать проблемы рассинхронизации. Можете проверить, например, так:
Скрипт
#!/bin/sh
set -e
# set -x
TGT=$1 ; shift
if test "$TGT" = "--help" ; then
echo "Usage: $0 NEWDIR"
exit 1
fi
export SCREENDIR="$(realpath "$TGT")/screen"
mkdir -p "$TGT"
mkdir -m 0700 -p "$SCREENDIR"
cd "$TGT"
for dir in mv nomv ; do
hg init "$dir"
cd "$dir"
echo abc > a
hg add a
hg commit -m 'Add a' --date=2000-01-01 --user=test
hg rm a
echo def > b
hg add b
if test "$dir" = mv ; then
hg mv -A a b
fi
hg commit -m 'Move a to b' --date=2000-01-01 --user=test
hg bookmark master
hg gexport
cd .hg/git
git fast-export master > "../../../$dir-fe"
git bundle create "../../../$dir-bundle" master
git log > "../../../$dir-log"
screen -d -m -S git-daemon git daemon --export-all --base-path=.
hg clone "git://127.0.0.1/" "../../../$dir-clone"
screen -X quit
cd ../..
hg log --follow b > "../$dir-log-follow"
cd ..
cd "$dir-clone"
hg log --follow b > "../$dir-clone-log-follow"
cd ..
diff --report-identical-files "$dir-log-follow" "$dir-clone-log-follow"
done
Здесь я клонировал репозиторий git «по сети» и сравнил вывод hg log --follow оригинального и склонированного репозитория. Они совпадают.
Вообще‐то хранение слепков/разностей и возможность сохранения информации о перемещении файлов несколько ортогональны. Git вполне мог сохранять информацию о факте перемещения отдельно от самих слепков. Более того, hg-git отлично сохраняет куда‐то информацию о перемещениях. Я у себя проверил вот таким скриптом:
#!/bin/sh
set -e
TGT=$1 ; shift
if test "$TGT" = "--help" ; then
echo "Usage: $0 NEWDIR"
exit 1
fi
mkdir -p "$TGT"
cd "$TGT"
for dir in mv nomv ; do
hg init "$dir"
cd "$dir"
echo abc > a
hg add a
hg commit -m 'Add a' --date=2000-01-01 --user=test
hg rm a
echo def > b
hg add b
if test "$dir" = mv ; then
hg mv -A a b
fi
hg commit -m 'Move a to b' --date=2000-01-01 --user=test
hg bookmark master
hg gexport
cd .hg/git
git fast-export master > "../../../$dir-fe"
git bundle create "../../../$dir-bundle" master
git log > "../../../$dir-log"
cd ../..
cd ..
done
Разница в том, что оказалось в git видна только в файлах $dir-bundle, $dir-log содержит только различающиеся хэши второго commit’а, а $dir-fe идентичны, так что как достать эту информацию из git и как она вообще сохраняется мне не очевидно. Возможно, hg-git просто нашёл какой‐то способ хранения своих метаданных и git понятия не имеет, что они означают. Код [hg-]git я сейчас как‐то смотреть не хочу. Но факт тот, что в git вполне возможно сохранять информацию о переименованиях, хранение слепков этому не мешает.
Смысла в исправляющих кодах тогда ещё меньше. Я не решаю вычислительные задачи, я чем‐то заполняю память. Если вычисление эталонного содержимого памяти занимает меньше времени, чем подсчёт и коррекция ошибок с использованием кодов коррекции ошибок, то при проверке его можно просто вычислить ещё раз. Если больше, то мне и так сложно понять, зачем тратить время на вычисление кодов коррекции при инициализации, сложные вычисления собственно содержимого памяти увеличат время инициализации ещё больше.
Кстати, ещё в копилку, почему писать программную реализацию ECC в моём случае — плохая идея: вообще‐то начальное заполнение памяти происходит во время облучения — т.е. когда в памяти активно появляются новые ОС, мешая всему подряд, но особенно любым операциях, использующим большие куски ОЗУ. Точнее, это не всегда так, только почти всегда — если в схеме возникают только ОС в памяти, память инициализируется только до облучения, но помимо одиночных сбоев в микроконтроллерах часто есть ещё такие интересные вещи как функциональные сбои, требующие произведения сброса (скорее всего, те же одиночные сбои, но просто где‐то внутри) и тиристорные эффекты, требующие выключения и включения питания.
---
Хотя я сейчас подумал, что какая‐то программная коррекция ошибок может пригодиться в тех случаях, когда я храню в ОЗУ саму исполняемую программу, что происходит, когда flash просто нет. У меня было, кажется, что‐то вроде одной такой схемы когда‐то давно и ОС смотреть там было сложно (и то, что никакой коррекции ошибок, кроме сброса при зависании, я не добавил, не помогло).
Но, я думаю, если только интерфейс, по которому в ОЗУ загружается программа, не будет очень медленным и безальтернативным, вместо кодов коррекции ошибок я скорее сделаю что‐то вроде перезаписи ОЗУ с программой данными, полученными повторно по этому же или более быстрому интерфейсу. А если он будет — то можно просто записать в ОЗУ три/пять/семь/… копий программы и использовать мажорирование, полагаясь на малую вероятность получить один и тот же сбой в двух/трёх/четырёх/… далеко расположенных местах сразу — не так сбоеустойчиво (в худшем случае) и экономно по памяти, как, скажем, коды Рида‐Соломона, но зато коррекция ошибок требует меньше времени и меньше иструкций.
И в любом случае, коррекция ошибок в таких схемах будет работать только если ошибка возникла в том коде, что должен быть выполнен после коррекции ошибок, и в тот момент времени, когда коррекция ошибок ещё не произошла. Нужно будет подумать, как её вставить так, чтобы увеличить вероятность, что инструкции с ошибками не будут выполнены, с учётом того, что больше инструкций и больше времени — больше ошибок.
Вообще не понятно как вы фиксируете-отлавливаете ошибки с памятью если такие коды не используете.
Если содержимое памяти — это функция от адреса (или, тем более, константа), то нужно просто запихать во flash‐память эту функцию (константу) и сравнивать содержимое памяти с ней. Если использовать исправляющие коды и случайные данные, то, во‐первых, код проверки и, соответственно, цикл ФК будет занимать больше времени. Во‐вторых, инициализация памяти будет занимать больше времени. В‐третьих, как я написал, сбоев будет много, но при этом заранее не известно, сколько в одном регионе накопится за цикл ФК — сколько сбоев должны выдерживать исправляющие ошибки коды — тем более, учитывая, что в схемах, где об ОС не думали при разработке могут найтись и множественные логически близко расположенные сбои (когда одна частица сбивает сразу несколько бит).
Исправляющие ошибки коды позволяют формировать с одной стороны как бы псевдо случайные данные близкие к данным используемым в реальной работе, а с другой стороны локализовать ошибку если она вдруг появится, ну и техника работы с такими кодами очень проработана - известна.
Знание, что именно должно лежать в памяти работает не хуже для локализации. И в реальной работе в памяти будет так же не случайный шум, а почти наверняка что‐то вроде массивов каких‐нибудь объектов и у каждого объекта схожий префикс. (К примеру, ASCII текст имеет бит 7 равный 0, а цифры конкретно вообще имеют четыре одинаковых наиболее значащих бит, у чисел с плавающей точкой в наиболее значащих битах расположены знак и экспонента.)
Обычно сбои там или приводят к функциональному сбою (== что‐то не работает, но почему именно мы не знаем) и написание прошивки на ассемблере никак с ними не поможет, либо тестирование сбоев в них на ассемблере и на C особо не отличается и соответственно не входит в список причин, по которым я использую ассемблер.
Если оно присутствует в железе, то приходится. Если нет, то не имеет смысла, содержимое памяти, в которой проверяется наличие ОС — это всегда какая‐то простая функция вида f(адрес), во многих случаях даже f(_) = const. Исправляющие ошибки коды будут использовать разработчики аппаратуры, после расчёта вероятности получения сбоя. С ECC в данном случае работать не удобно. Дело в том, что в космосе вам, в зависимости от орбиты, может прилетать одна частица в месяц/неделю/день/… — ECC с таким легко справляется. На испытаниях в сторону микросхемы может лететь до несколько десятков тысяч частиц в секунду (в саму микросхему попадёт, если я не ошибаюсь, порядка на два—три меньше, пропорционально её площади) — чем больше, тем меньше мы стоим на ускорителе и меньше платим за его время. Если память без ECC, то увеличение числа частиц в разумных пределах мало что качественно меняет — вероятность пропустить сбой из‐за того, что в одном месте произошло два сбоя за цикл ФК низкая, а несколько сбоев рядом никак не отличаются от нескольких сбоев далеко друг от друга. Если же память с ECC, то подача слишком большого числа частиц приведёт к неизбежному заключению «ECC не работает», что, возможно, не соответствует реальности. Но при этом ECC действительно может не работать — одна частица вполне может сбить одновременно пачку ячеек; разработчики схемы должны позаботится о том, чтобы это было не проблемой, сделав логически близкие адреса физически не такими близкими, но мы — испытательный центр — должны как‐то проверить, что они действительно это сделали. Схемы с такой памятью также могут по‐разному реагировать на сбои — не все, к примеру, предоставляют счётчик скорректированных ошибок. В общем, я скорее рад, что микросхемы со встроенным ECC мне приходят нечасто.
Что Вас удивляет? Ускорители ЛЯР ОИЯИ вполне себе живут и здравствуют, можете поискать, где — именно они используются для испытаний на воздействие ТЗЧ. Есть медицинский ускоритель протонов в Обнинске. А если вам всего лишь нужно ускорить электроны и потом превратить их в гамма‐излучение, то такие устройства в принципе относительно часто встречающиеся, небольшие — могут поместиться в вашу комнату (если не считать свинца, из‐за которого ваша комната рухнет на соседа снизу или подвал ещё до установки в неё ускорителя и того, что размещать ускоритель в жилом помещении вам наверняка нельзя) — и некоторые даже используются для промышленной дезинфекции.
Я работаю в испытательном центре, занимающемся испытаниями на радиационную стойкость, а не разрабатываю аппаратуру. Т.е. мне нужно предоставлять данные для ответа на вопросы вида «насколько вероятно, что прилетевшая в схему частица вызовет сбой в определённом блоке» (блоки в основном ограничиваются разными видами памяти), а не собственно как‐то компенсировать результат этого сбоя.
Соответственно, всё, что мои прошивки делают — это крутят определённый набор тестов, в то время как сама схема стоит с открытым кристаллом и подвергается бомбардировке тяжёлыми заряженными частицами (ТЗЧ), обычно ионами благородных газов из ускорителя. (Или ещё чем и не обязательно с открытым кристаллом, но конкретно одиночные сбои интересны при испытаниях на ТЗЧ.)
Потом, на основе моих данных, кто‐то будет решать, что всё‐таки нужно делать, чтобы его изделие нормально работало в космосе. Но это вопрос не ко мне.
Если вы будете писать как я, то прилетающие частицы вас не особо будут беспокоить — но у меня для стабильности работы тестовой прошивки есть по сути одно и не очень полезное (для реальных прошивок) правило — не используйте никакую память, кроме flash, а если очень нужно — используйте мало памяти и не держите там ничего долго. Ну и по возможности не оставляйте в прошивке код для перезаписи flash, результат случайного прыжка туда вам не понравится.
Это не самый оптимальный код, какой может быть¹, но он работает.
Вообще на хабре где‐то была хорошая статья про ARM ассемблер, но я что‐то не могу её найти. Поисковик, тем не менее, находит достаточно статей про ARM ассемблер, в том числе упоминающий инструкцию it… (ne|…): кроме сей инструкции ассемблер для меня особо ничем не примечателен. (В примере выше, насколько я знаю, я мог бы её и опустить, но вот, например, в макросе проверки памяти на ОС есть кусок вида
eors r1, r1, \tmpreg3
itt ne
strne \tmpreg3, [\tmpreg1]
blne count_ones
, где с ней просто удобнее.)
¹ Особенно учитывая, что .else ветка существует исключительно чтобы я мог ради интереса посмотреть на diff между результатом дизассемблирования почти одной и той же прошивки, скомпилированной под разные STM’ки и не получить 100500 отличий в адресах инструкций.
Я свои прошивки вообще на ассемблере часто пишу. Это позволяет мне делать интересные вещи вроде контроля одиночных сбоев в регистрах общего назначения: попробуйте убедить компилятор C в том, что ему нужно поместить глобальную переменную в регистр. Последний раз как я пытался это сделать, прошивка почему‐то не заработала, хотя компилятор вроде поддерживал привязку переменной к регистру.
Результат также быстрее, чем -O0. (Про остальные -O такого не скажу, но мои прошивки не делают некоторые вещи, которые делает startup: не копируют в ОЗУ значения разных переменных, обычно не инициализируют стэк.)
Так «ссылка на объект или функцию» — нормальное определение. Вы не можете посмотреть на него и сказать «если я прибавлю к этой ссылке 10, то я попаду в соседний объект». Интереснее вопрос «а что такое объект»: если я правильно понимаю логику компиляторов, это будет что‐то вроде «кусок памяти, выделенный для одного экземпляра типа».
С точки зрения компилятора, это что‐то вроде пары из адреса и объекта, которому этот адрес принадлежит. Например, посмотрите как clang компилирует следующую программу:
int main(void) {
int a = 0;
int b = 1;
*(&a + (&b - &a)) = 2;
return b;
}
Она возвращает 1, потому что по мнению оптимизатора вы не можете взять адрес объекта a и перейти из него в объект b: это разные объекты, живущие в разных реальностях. Это имеет физический смысл при использовании чего‐то вроде CHERI, но, т.к. почти никто не использует такие процессоры, почти всё время это просто ещё один пример использования UB для оптимизации.
Это так же пример, почему вы больше не можете считать, что указатель — это просто адрес в памяти: современные компиляторы так больше не считают.
То, что обычно, зависит от того, что вы делаете. Я занимаюсь испытанием микросхем на радиационную стойкость и я почти никогда не округляю до ближайшего значения: это либо округление вверх (параметр‐критерий годности, должный быть «не больше» какого‐то значения; требуемый уровень воздействия, …), либо вниз (… «не меньше»; уровень стойкости), либо «от центра» (параметры, которые одновременно не больше и не меньше) — т.е. что в данном контексте «более консервативно».
У Excel, кстати, функции для округления вверх и вниз до множителя определённого значения есть. А в LabVIEW, который часто используется испытательными центрами, почему‐то есть только округление до целых.
Ruby и Python — да. В javascript похоже засунули в стандарт оптимизацию, используемую для таблиц lua (скорее не саму оптимизацию, но её последствия в части того, как удобнее всего реализовывать итерацию по object): MDN в документации for..in утверждает
The traversal order, as of modern ECMAScript specification, is well-defined and consistent across implementations. Within each component of the prototype chain, all non-negative integer keys (those that can be array indices) will be traversed first in ascending order by value, then other string keys in ascending chronological order of property creation.
Где это написано в собственно спецификации ECMAScript я не нашёл, но в этом тексте написано сначала цифровые индексы по порядку, потом строковые ключи таки в порядке добавления.
В C# Dictionary без Sorted не сортирует по ключам. Интерфейс Map в Java не требует определённого порядка. Если это более скриптовый язык, где словари являются частью основного синтаксиса, то внутри почти наверняка будет хэш‐таблица, которые с сортировкой по ключам не очень дружат.
Собственно под «обычно» я думал скорее про них — я обычно использую Rust или такие скриптовые языки и в Rust есть, к примеру, HashMap и BTreeMap, но у обоих название вида ImplementationMap и нельзя сказать, что есть какие‐то предпочтения на уровне языка или стандартной библиотеки. HashMap, впрочем, используется чаще, потому что за сортировку по ключам вы платите скоростью всех операций в данном случае.
Про удаление лишнего припоя с ножек: тут уже рекомендовали оплётку, но есть ещё одна особенность: если лишнего припоя мало и вы не можете ткнуть в него паяльником или оплёткой — и, главное, он где‐то за ножками и паяльником с нормальной температурой не нагревается, иногда имеет смысл добавить больше припоя. Огромная капля удаляется оплёткой с ножек без проблем, мелкая капля едва касающаяся чего‐либо паяльником не удаляется без добавления припоя в принципе: либо вы поглощаете её лишним припоем, либо можно попробовать много флюса и фен.
Нагревать паяльник выше той температуры, при которой вам комфортно паять ножки, для удаления мелкой капли не нужно. При использовании оплётки, если вы паяете на минимальной комфортной температуре, придётся добавить 20—30 ℃.
Я обычно паяю большим топориком (K) с 240 ℃ для микросхем с ножками, 250 ℃ для ёмкостей/… 0603—0805, подключающихся к огромным полигонам, 260—280 ℃ для танталовых конденсаторов и THD. Выше в специальных случаях. Если жало — не большой топорик, температура может потребоваться выше.
А относительно BGA: по‐моему вы ухудшили себе жизнь, не купив ИК станцию вместо столика с подогревом. У нас в компании BGA паяют без трафаретов и пасты: берём нормальный флюс (сейчас — Mechanic SD-360), мажем его очень тонким и ровным слоем по всем площадкам, ставим схему и греем ИК станцией. Работает как с золотым финишным покрытием (иммерсионное золото), так и с ПОС‐63 (или остатками шариков), но если ПОС‐63 появился после выпайки микросхемы, а не после завода, то его нужно аккуратно выровнять оплёткой (в плохих случаях: сначала паяльником смахнуть остатки шариков, а потом уже оплёткой), при этом не убрав этой оплёткой маску (что тем легче сделать, чем горячее паяльник) и не сорвав случайно площадки (что тем легче сделать, чем холоднее паяльник).
Трафарет понадобится, если нужно будет перенакатывать шарики. Или если вы всё же решите поставить по одному 0402 конденсатору под каждый шарик питания и у вас есть ИК станция.
В качестве бюджетной ИК можно брать Puhui T-962, но её придётся доработать (у нас это запасная станция на случай поломки основной). Доработать — это обклеить термоскотчем, изменить прошивку, добавить дополнительный температурный сенсор.
Такие костыли я видел. Они хорошо заметны, и они точно не могут привести к идентичным
$dir-fe
(выводамgit fast-export
).И в любом случае, напомню, что ветка началась с того, что я указал возможность сохранения информации о перемещениях в СКВ, хранящей слепки, и hg-git — это просто пример хранения этой информации в СКВ, хранящей слепки. Какими костылями он это делает неважно — это просто пример, что это сделать возможно, соответственно из «в гите как раз слепки хранятся» не может следовать, что гит «не умеет трекать перемещения» — он не умеет трекать перемещения, потому что его авторы решили не добавлять сохранение перемещений, а не потому что он хранит слепки.
Ваша ссылка относится к commit’ам, сделаным в git. У меня commit’ы, сделанные в mercurial, в которых уже есть информация о переименованиях и она должна быть частью commit’а и на стороне mercurial, и на стороне git, чтобы hg-git вообще работал: хэши commit’ов должны сохраняться при конвертации в любую сторону, чтобы можно было нормально работать, а не постоянно решать проблемы рассинхронизации. Можете проверить, например, так:
Скрипт
Здесь я клонировал репозиторий git «по сети» и сравнил вывод
hg log --follow
оригинального и склонированного репозитория. Они совпадают.Вообще‐то хранение слепков/разностей и возможность сохранения информации о перемещении файлов несколько ортогональны. Git вполне мог сохранять информацию о факте перемещения отдельно от самих слепков. Более того,
hg-git
отлично сохраняет куда‐то информацию о перемещениях. Я у себя проверил вот таким скриптом:Разница в том, что оказалось в git видна только в файлах
$dir-bundle
,$dir-log
содержит только различающиеся хэши второго commit’а, а$dir-fe
идентичны, так что как достать эту информацию из git и как она вообще сохраняется мне не очевидно. Возможно, hg-git просто нашёл какой‐то способ хранения своих метаданных и git понятия не имеет, что они означают. Код [hg-]git я сейчас как‐то смотреть не хочу. Но факт тот, что в git вполне возможно сохранять информацию о переименованиях, хранение слепков этому не мешает.Смысла в исправляющих кодах тогда ещё меньше. Я не решаю вычислительные задачи, я чем‐то заполняю память. Если вычисление эталонного содержимого памяти занимает меньше времени, чем подсчёт и коррекция ошибок с использованием кодов коррекции ошибок, то при проверке его можно просто вычислить ещё раз. Если больше, то мне и так сложно понять, зачем тратить время на вычисление кодов коррекции при инициализации, сложные вычисления собственно содержимого памяти увеличат время инициализации ещё больше.
Кстати, ещё в копилку, почему писать программную реализацию ECC в моём случае — плохая идея: вообще‐то начальное заполнение памяти происходит во время облучения — т.е. когда в памяти активно появляются новые ОС, мешая всему подряд, но особенно любым операциях, использующим большие куски ОЗУ. Точнее, это не всегда так, только почти всегда — если в схеме возникают только ОС в памяти, память инициализируется только до облучения, но помимо одиночных сбоев в микроконтроллерах часто есть ещё такие интересные вещи как функциональные сбои, требующие произведения сброса (скорее всего, те же одиночные сбои, но просто где‐то внутри) и тиристорные эффекты, требующие выключения и включения питания.
---
Хотя я сейчас подумал, что какая‐то программная коррекция ошибок может пригодиться в тех случаях, когда я храню в ОЗУ саму исполняемую программу, что происходит, когда flash просто нет. У меня было, кажется, что‐то вроде одной такой схемы когда‐то давно и ОС смотреть там было сложно (и то, что никакой коррекции ошибок, кроме сброса при зависании, я не добавил, не помогло).
Но, я думаю, если только интерфейс, по которому в ОЗУ загружается программа, не будет очень медленным и безальтернативным, вместо кодов коррекции ошибок я скорее сделаю что‐то вроде перезаписи ОЗУ с программой данными, полученными повторно по этому же или более быстрому интерфейсу. А если он будет — то можно просто записать в ОЗУ три/пять/семь/… копий программы и использовать мажорирование, полагаясь на малую вероятность получить один и тот же сбой в двух/трёх/четырёх/… далеко расположенных местах сразу — не так сбоеустойчиво (в худшем случае) и экономно по памяти, как, скажем, коды Рида‐Соломона, но зато коррекция ошибок требует меньше времени и меньше иструкций.
И в любом случае, коррекция ошибок в таких схемах будет работать только если ошибка возникла в том коде, что должен быть выполнен после коррекции ошибок, и в тот момент времени, когда коррекция ошибок ещё не произошла. Нужно будет подумать, как её вставить так, чтобы увеличить вероятность, что инструкции с ошибками не будут выполнены, с учётом того, что больше инструкций и больше времени — больше ошибок.
Если содержимое памяти — это функция от адреса (или, тем более, константа), то нужно просто запихать во flash‐память эту функцию (константу) и сравнивать содержимое памяти с ней. Если использовать исправляющие коды и случайные данные, то, во‐первых, код проверки и, соответственно, цикл ФК будет занимать больше времени. Во‐вторых, инициализация памяти будет занимать больше времени. В‐третьих, как я написал, сбоев будет много, но при этом заранее не известно, сколько в одном регионе накопится за цикл ФК — сколько сбоев должны выдерживать исправляющие ошибки коды — тем более, учитывая, что в схемах, где об ОС не думали при разработке могут найтись и множественные логически близко расположенные сбои (когда одна частица сбивает сразу несколько бит).
Знание, что именно должно лежать в памяти работает не хуже для локализации. И в реальной работе в памяти будет так же не случайный шум, а почти наверняка что‐то вроде массивов каких‐нибудь объектов и у каждого объекта схожий префикс. (К примеру, ASCII текст имеет бит 7 равный 0, а цифры конкретно вообще имеют четыре одинаковых наиболее значащих бит, у чисел с плавающей точкой в наиболее значащих битах расположены знак и экспонента.)
Обычно сбои там или приводят к функциональному сбою (== что‐то не работает, но почему именно мы не знаем) и написание прошивки на ассемблере никак с ними не поможет, либо тестирование сбоев в них на ассемблере и на C особо не отличается и соответственно не входит в список причин, по которым я использую ассемблер.
Если оно присутствует в железе, то приходится. Если нет, то не имеет смысла, содержимое памяти, в которой проверяется наличие ОС — это всегда какая‐то простая функция вида f(адрес), во многих случаях даже f(_) = const. Исправляющие ошибки коды будут использовать разработчики аппаратуры, после расчёта вероятности получения сбоя.
С ECC в данном случае работать не удобно. Дело в том, что в космосе вам, в зависимости от орбиты, может прилетать одна частица в месяц/неделю/день/… — ECC с таким легко справляется. На испытаниях в сторону микросхемы может лететь до несколько десятков тысяч частиц в секунду (в саму микросхему попадёт, если я не ошибаюсь, порядка на два—три меньше, пропорционально её площади) — чем больше, тем меньше мы стоим на ускорителе и меньше платим за его время. Если память без ECC, то увеличение числа частиц в разумных пределах мало что качественно меняет — вероятность пропустить сбой из‐за того, что в одном месте произошло два сбоя за цикл ФК низкая, а несколько сбоев рядом никак не отличаются от нескольких сбоев далеко друг от друга.
Если же память с ECC, то подача слишком большого числа частиц приведёт к неизбежному заключению «ECC не работает», что, возможно, не соответствует реальности. Но при этом ECC действительно может не работать — одна частица вполне может сбить одновременно пачку ячеек; разработчики схемы должны позаботится о том, чтобы это было не проблемой, сделав логически близкие адреса физически не такими близкими, но мы — испытательный центр — должны как‐то проверить, что они действительно это сделали.
Схемы с такой памятью также могут по‐разному реагировать на сбои — не все, к примеру, предоставляют счётчик скорректированных ошибок.
В общем, я скорее рад, что микросхемы со встроенным ECC мне приходят нечасто.
Что Вас удивляет? Ускорители ЛЯР ОИЯИ вполне себе живут и здравствуют, можете поискать, где — именно они используются для испытаний на воздействие ТЗЧ. Есть медицинский ускоритель протонов в Обнинске. А если вам всего лишь нужно ускорить электроны и потом превратить их в гамма‐излучение, то такие устройства в принципе относительно часто встречающиеся, небольшие — могут поместиться в вашу комнату (если не считать свинца, из‐за которого ваша комната рухнет на соседа снизу или подвал ещё до установки в неё ускорителя и того, что размещать ускоритель в жилом помещении вам наверняка нельзя) — и некоторые даже используются для промышленной дезинфекции.
Я работаю в испытательном центре, занимающемся испытаниями на радиационную стойкость, а не разрабатываю аппаратуру. Т.е. мне нужно предоставлять данные для ответа на вопросы вида «насколько вероятно, что прилетевшая в схему частица вызовет сбой в определённом блоке» (блоки в основном ограничиваются разными видами памяти), а не собственно как‐то компенсировать результат этого сбоя.
Соответственно, всё, что мои прошивки делают — это крутят определённый набор тестов, в то время как сама схема стоит с открытым кристаллом и подвергается бомбардировке тяжёлыми заряженными частицами (ТЗЧ), обычно ионами благородных газов из ускорителя. (Или ещё чем и не обязательно с открытым кристаллом, но конкретно одиночные сбои интересны при испытаниях на ТЗЧ.)
Потом, на основе моих данных, кто‐то будет решать, что всё‐таки нужно делать, чтобы его изделие нормально работало в космосе. Но это вопрос не ко мне.
Если вы будете писать как я, то прилетающие частицы вас не особо будут беспокоить — но у меня для стабильности работы тестовой прошивки есть по сути одно и не очень полезное (для реальных прошивок) правило — не используйте никакую память, кроме flash, а если очень нужно — используйте мало памяти и не держите там ничего долго. Ну и по возможности не оставляйте в прошивке код для перезаписи flash, результат случайного прыжка туда вам не понравится.
Я написал ответ на вопрос «зачем» в той части предложения, что вы почему‐то решили не цитировать.
Для CA это, кажется, будет
при условии, что вы заранее знаете, где стэк.
Я для заполнения памяти использовал следующие макросы:
Это не самый оптимальный код, какой может быть¹, но он работает.
Вообще на хабре где‐то была хорошая статья про ARM ассемблер, но я что‐то не могу её найти. Поисковик, тем не менее, находит достаточно статей про ARM ассемблер, в том числе упоминающий инструкцию
it… (ne|…)
: кроме сей инструкции ассемблер для меня особо ничем не примечателен. (В примере выше, насколько я знаю, я мог бы её и опустить, но вот, например, в макросе проверки памяти на ОС есть кусок вида, где с ней просто удобнее.)
¹ Особенно учитывая, что
.else
ветка существует исключительно чтобы я мог ради интереса посмотреть наdiff
между результатом дизассемблирования почти одной и той же прошивки, скомпилированной под разные STM’ки и не получить 100500 отличий в адресах инструкций.Я свои прошивки вообще на ассемблере часто пишу. Это позволяет мне делать интересные вещи вроде контроля одиночных сбоев в регистрах общего назначения: попробуйте убедить компилятор C в том, что ему нужно поместить глобальную переменную в регистр. Последний раз как я пытался это сделать, прошивка почему‐то не заработала, хотя компилятор вроде поддерживал привязку переменной к регистру.
Результат также быстрее, чем -O0. (Про остальные -O такого не скажу, но мои прошивки не делают некоторые вещи, которые делает startup: не копируют в ОЗУ значения разных переменных, обычно не инициализируют стэк.)
Так «ссылка на объект или функцию» — нормальное определение. Вы не можете посмотреть на него и сказать «если я прибавлю к этой ссылке 10, то я попаду в соседний объект». Интереснее вопрос «а что такое объект»: если я правильно понимаю логику компиляторов, это будет что‐то вроде «кусок памяти, выделенный для одного экземпляра типа».
С точки зрения компилятора, это что‐то вроде пары из адреса и объекта, которому этот адрес принадлежит. Например, посмотрите как clang компилирует следующую программу:
Она возвращает 1, потому что по мнению оптимизатора вы не можете взять адрес объекта
a
и перейти из него в объектb
: это разные объекты, живущие в разных реальностях. Это имеет физический смысл при использовании чего‐то вроде CHERI, но, т.к. почти никто не использует такие процессоры, почти всё время это просто ещё один пример использования UB для оптимизации.Это так же пример, почему вы больше не можете считать, что указатель — это просто адрес в памяти: современные компиляторы так больше не считают.
Del
То, что обычно, зависит от того, что вы делаете. Я занимаюсь испытанием микросхем на радиационную стойкость и я почти никогда не округляю до ближайшего значения: это либо округление вверх (параметр‐критерий годности, должный быть «не больше» какого‐то значения; требуемый уровень воздействия, …), либо вниз (… «не меньше»; уровень стойкости), либо «от центра» (параметры, которые одновременно не больше и не меньше) — т.е. что в данном контексте «более консервативно».
У Excel, кстати, функции для округления вверх и вниз до множителя определённого значения есть. А в LabVIEW, который часто используется испытательными центрами, почему‐то есть только округление до целых.
Ruby и Python — да. В javascript похоже засунули в стандарт оптимизацию, используемую для таблиц lua (скорее не саму оптимизацию, но её последствия в части того, как удобнее всего реализовывать итерацию по object): MDN в документации for..in утверждает
Где это написано в собственно спецификации ECMAScript я не нашёл, но в этом тексте написано сначала цифровые индексы по порядку, потом строковые ключи таки в порядке добавления.
В C#
Dictionary
безSorted
не сортирует по ключам. ИнтерфейсMap
в Java не требует определённого порядка. Если это более скриптовый язык, где словари являются частью основного синтаксиса, то внутри почти наверняка будет хэш‐таблица, которые с сортировкой по ключам не очень дружат.Собственно под «обычно» я думал скорее про них — я обычно использую Rust или такие скриптовые языки и в Rust есть, к примеру, HashMap и BTreeMap, но у обоих название вида ImplementationMap и нельзя сказать, что есть какие‐то предпочтения на уровне языка или стандартной библиотеки. HashMap, впрочем, используется чаще, потому что за сортировку по ключам вы платите скоростью всех операций в данном случае.